Git
参考链接
工作流程
存储分区
工作区(Workspace)
位置:项目目录
文件状态:
- 未跟踪(untracked):新建文件
- 未暂存(unstaged):修改文件(modified),删除文件(deleted)
- 未修改(unmodify)
暂存区(Index / Stage)
位置:项目目录下 .git 文件夹中
文件状态:
- 已暂存(staged)
本地库(Repository)
位置:项目目录下 .git 文件夹中
文件状态:
- 已提交(committed)
远程库(Remote)
文件状态:
- 已推送(pushed)
命令
init
创建本地库
git init
clone
克隆远程库到本地库和工作区。
git clone [-b <分支名|标签名>] <https链接|ssh链接> [<文件夹名>]
配置SSH
安装 TortoiseGit 后,打开 设置 - 网络,配置 SSH 客户端改为:D:\Software\Git\usr\bin\ssh.exe
。(或者在安装过程中,选择 OpenSSH 协议而非 TortoiseGitPlink 协议,因为 Git 使用的是 OpenSSH 协议)
通过 ssh-keygen -t rsa -C "<邮箱>"
命令,在用户目录中的 .ssh 文件夹生成 id_rsa(私钥)和 id_rsa.pub(公钥),将 id_rsa.pub 文件内容复制到远程库的 SSH 公钥配置中。
新版 Git 因为 SHA-1 算法安全问题,默认禁用 ssh-rsa 公钥,可以采用其他秘钥生成算法(ecdsa-sk 和 ed25519-sk),如 ssh-keygen -t ed25519 -C "<邮箱>"
。
remote
远程库管理
# 添加远程库
git remote add <远程库名> <远程库链接>
#显示所有远程库
git remote -v
# 显示指定远程库的信息
git remote show <远程库名>
# 远程库名重命名
git remote rename <旧远程库名> <新远程库名>
# 删除指定远程库
git remote rm <远程库名>
branch
分支管理
# 创建本地分支
git branch <分支名>
# 查看所有本地分支
git branch
# 查看所有本地分支和远程分支
git branch -a
# 删除指定本地分支
git branch -d <分支名>
# 强制删除指定本地分支
git branch -D <分支名>
# 重命名分支,旧分支无指定时默认当前分支
git branch -m [<旧分支名>] <新分支名>
checkout
丢弃工作区修改,重置到和暂存区一样
# 将暂存区文件提交到版本库
git checkout -- <文件名>
# 切换分支
git checkout <分支名>
# 创建并切换分支
git checkout -b <分支名>
status
查看文件状态
git status
diff
添加到暂存区前,查看文件修改内容
# 指定文件或所有文件
git diff [<文件名>]
add
将工作区文件添加到暂存区
# 直接使用 . 代表未暂存和未跟踪的文件
git add .
commit
将暂存区文件提交到版本库
# 将暂存区文件提交到版本库
git commit -m "日志"
# 将未暂存文件添加暂存区,并提交到版本库(不包含未跟踪文件)
git commit -am "日志"
log
查看日志
# 详细日志
git log [<指定文件>]
# 简化日志
git log --pretty=oneline
git log --oneline
reflog
查看引用记录(回退后通过 log 命令查看不了已经被退回日志,需要通过 reflog 查看引用记录)
git reflog
reset
重置
# 重置到前1个版本
git reset HEAD^
# 重置到前指定数量个版本
git reset HEAD~<数量>
# 重置到指定版本号的版本
git reset <版本号>
# 软重置:只重置本地库
git reset --soft <版本号>
# 混合(默认):重置本地库+暂存区
git reset --mixed <版本号>
# 硬重置:重置本地库+暂存区+工作区
git reset --hard <版本号>
fetch
以 master 分支为例,会包含本地库 master 分支和远程仓库副本 origin/master 分支。
fetch 操作是获取远程库最新版本到 origin/master 分支。
此时 master 分支依然未被更新,需要再执行合并操作:git merge origin/master
。
git fetch origin
pull
拉取远程库到远程仓库副本,本地库和工作区,自动合并
# 相当于执行 git fetch origin + git merge origin/master
git pull origin
# 相当于执行 git fetch origin + git rebase origin/master
git pull --rebase origin
push
推送到远程库,并更新远程库的本地副本。
# 完整示例:git push origin master:master
# 本地分支 = 远程分支,省略远程分支,示例:git push origin master
# 当前分支 = 本地分支 = 远程分支,省略分支名,示例:git push origin
git push <远程库名> [<本地分支名>[:<远程分支名>]]
# 推送所有本地分支
git push <远程库名> --all
# 强制推送
git push <远程库名> --force
# 删除远程库的指定分支
git push <远程库名> --delete <远程分支名>
# 本地库关联远程库后的第一次推送,将本地分支和远程分支进行关联
git push -u <远程库名> <分支名>
merge
分支合并
快进式合并:当前分支和目标分支没有产生分叉,则当前分支可以直接前进到目标分支,不会产生一条合并的提交记录。
# 自动快进式合并:能快进式则快进式,否则用非快进式(默认)
git merge --ff <分支名>
# 非快进式合并
git merge --no-ff <分支名>
# 仅快进式合并(当不能快进式合并时合并失败)
git merge --ff-only <分支名>
# 不自动提交,只对非快进式有效(因为快进式不需要提交),
# 此时合并操作未完成,需要再手动提交或者进行回退才能结束
git merge --no-commit <分支名>
# 将目标分支的更改仅更新到工作区,本地库不变,需要再一次性提交这些更改
# 目标分支的提交记录不会出现在当前分支中
git merge --squash <分支名>
rebase
分支变基
# 开始变基
git rebase <分支名>
# 处理完冲突,add之后,继续执行变基
git rebase --continue
# 中止变基,放弃合并,回到操作前的样子
git rebase --abort
stash
贮藏更改,将当前未完成,不想提交的更改暂时保存,以便切换到其他分支工作
# 新增贮藏
git stash push
git stash save '注释'
# 恢复堆栈中最新的贮藏并移除
git stash pop
# 恢复堆栈中指定的贮藏(默认最新贮藏)
git stash apply [stash@{$num}]
# 移除堆栈中指定的贮藏(默认最新贮藏)
git stash drop [stash@{$num}]
# 移除所有贮藏
git stash clear
# 查看贮藏列表
git stash list
#查看堆栈中指定贮藏和当前工作区的差异(默认最新贮藏)
git stash show [stash@{$num}]
clean
删除未跟踪的文件
git clean -f
config
优先级:system < global < local
# 系统级,对所有用户有效,对应 Git安装目录\mingw64\etc\gitconfig文件
git config --system --list
# 用户级,对当前用户有效,对应 用户目录\.gitconfig文件
git config --global --list
# 仓库级,对当前仓库有效,对应 项目目录\.git\config文件
git config --local --list
配置管理
# 查看配置列表(优先级越高排越后)
git config --list
# 显示配置对应的文件
git config --list --show-origin
# 查看指定配置项(多个值时返回优先级最高的)
git config <配置名>
git config --get <配置名>
# 查看指定配置项的所有值
git config --get-all <配置名>
# 修改/新增指定配置项(默认仓库级)
# 存在多个值时返回失败
git config <配置名> <值>
# 存在多个值时合并成一个
git config --replace-all <配置名> <值>
# 新增指定配置项(默认仓库级)
git config --add <配置名> <值>
# 删除指定配置项(默认仓库级)
# 存在多个值时返回失败
git config --unset <配置名>
# 存在多个值时全部删除
git config --unset-all <配置名>
常见配置项
# 用户名
git config --global user.name huoyu
# 邮箱
git config --global user.email huoyu@sohu-inc.com
# 自动保存账号密码
git config --global credential.helper store
# 行尾符处理
# core.autocrlf = true 提交时转换为LF,拉取时转换为CRLF
# core.autocrlf = input 提交时转换为LF,拉取时不转换(推荐)
# core.autocrlf = false 不转换
git config --global core.autocrlf input
# hooks目录
git config --local core.hooksPath git_hooks
行尾符
Windows 使用回车(CR)和换行(LF)两个字符来结束一行,而 macOS 和 Linux 只使用换行(LF)一个字符,不统一时 Git 容易有冲突。
推荐使用 core.autocrlf = input
配置,保证代码库中的行尾符都是 LF。同时将 VSCode 的 EOL 也设置为 LF,保证工作区产生的行尾符也是 LF,从而实现全部统一为LF。
如果当前工作区的文件已经是 CTLF了,则全部转换为 LF,方法见:批量转换 LF 和 CRLF
Hooks
Git执行特定事件时触发运行的脚本,默认 hooks 目录是 .git/hooks,目录中每个类型的钩子对应一个相应名称的脚本文件,如 pre-commit 文件(没有后缀名)。目录中默认包含的示例都带 .sample 后缀,以防止被运行。
hooks共享
方法1
在 package.json 的 scripts 字段添加 "prepare": "git config core.hooksPath gitHooks"
,prepare 脚本会在 install 脚本执行之后自动执行,将钩子目录改成自定义目录 gitHooks,不在.git 目录中,以便保存到代码库。
在 gitHooks 目录中创建钩子文件。在普通项目中可以直接使用 node 脚本。
#!/usr/bin/env node
const dayjs = require("dayjs");
let day = dayjs(new Date());
console.log("钩子执行时间:" + day.format("YYYY-MM-DD HH:mm:ss"));
在指定为 ES6 模块化规范的项目中(package.json 的 type 字段设定为"module"),脚本文件必须要有文件后缀,因此需要间接调用。
#!/usr/bin/env sh
node ./gitHooks/pre-commit.js;
// pre-commit.js;
import dayjs from "dayjs";
let day = dayjs(new Date());
console.log("钩子执行时间:" + day.format("YYYY-MM-DD HH:mm:ss"));
方法2
使用 husky 库(原理其实同方法1一样)
# 安装husky库,package.json 的 scripts 中新增脚本:"prepare": "husky install"
npx husky-init
# 触发 prepare 脚本的执行,
# 执行 git config core.hooksPath .husky,设置git的钩子目录为 .husky 并生成该目录
npm install