文章

《精通git第二版》读书笔记·ch07 git高级命令

《精通git第二版》读书笔记·ch07 git高级命令

选择提交

选择单个提交,可以用SHA-1(简短形式)、分支名、引用日志、祖先引用等方式,具体如下:

  • 简短形式的SHA-1。提供不少于4个sha-1字符,且不含歧义时,即可访问单个提交。
  • 分支名。当某个分支指向某个提交时,可以用该分支名来引用对应的提交。git rev-parse <branchname>可以查看分支对应的提交。
  • 引用日志(reflog)。记录了HEAD和分支引用指向的历史,只存在于本地仓库。使用git reflog查看。通过@{n}语法引用日志记录,例如git show HEAD@{5}
  • 祖先引用。使用xxx^指明祖先引用,例如HEAD^HEAD^2则表示第2个父提交(合并时)。~n表示n个祖先提交。

选择提交区间,可以用双点、多点、三点

  • 双点。选出在一个分支,但是不在另一个分支的提交。例如git log origin/master..HEAD
  • 多点。在引用前添加^或者--not表示,不包含此分支的提交。例如git log refA refB ^refC,表示refA和refB包含,但是refC不含的提交。
  • 三点。选择被两个引用包含,但是非共有的提交。例如git log --left-right master...experiment

交互式暂存

修改一组文件后,如果想将改动放到若干个提交,从而确保提交是逻辑上独立的变更集,则可以使用交互式暂存

git add -i可以启动交互式暂存终端。通过“补丁”模式,可以暂存文件的部分内容,命令为git add -p|--patch

储藏与清理

git stash命令,储藏工作目录中修改和暂存的文件,将未完成的修改储存在一个栈上,默认不储藏未跟踪的文件。常用命令如下:

1
2
3
4
5
6
7
8
9
10
11
12
git stash [save] # 储藏
git stash save --keep-index # 不要储藏已经暂存的文件
git stash -u # 储藏未跟踪的文件
git stash --patch # 交互式储藏

git stash list # 列出储藏列表

git stash apply [--index] [stash@{n}] # 应用储藏
git stash drop stash@{n} # 移除储藏
git stash pop # 应用并丢弃

git stash branch "xxx" # 创建一个新分支,检出储藏所在提交,重新应用工作并丢弃储藏

git clean命令,从工作目录移除未被跟踪的文件,与.gitignore模式匹配的文件不会移除

1
2
git clean -x
git clean -f -d -n 

签名

配置GPG并安装个人密钥。

1
2
gpg --list-keys
gpg --gen-key

配置git。

1
git config --global user.signingkey "xxx"

签署标签。

1
2
3
git tag -s "vxxx" -m "xxx"
git show "vxxx"
git tag -v "vxxx" # 验证签署的标签

签署提交。

1
2
3
4
5
git commit -a -S -m "xxx" # v1.7.9开始
git log --show-signature -1

git merge --verify-signatures # 验证签名,无效时不合并
git merge --verify-signatures -S "xxx" # 对生成的合并提交也签名

如果在流程中使用签名,确保每个人都理解该如何使用

搜索

git grep命令,从提交历史或者工作目录查找字符串或正则表达式。

git log命令,通过提交信息和diff内容查找某个特定的提交。-L启用行日志搜索,展示代码中一行或者一个函数的历史。

1
2
git log -S"xxx" # 显示字符串变动的提交
git log -L :git_deflate_bound:zlib.c # 查看zlib.c中函数git_deflate_bound的变动

重写历史

在与他人共享代码之前,可以考虑重写历史,但是建议不要操作已经共享的代码

重写历史的方式如下:

  • git commit --amend,修改最近一次提交。
  • 交互式变基。可以对提交进行修改、重新排序、移除、压缩、拆分。
  • filter-branch,改写历史中大量的提交。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
git filter-branch --tree-filter 'rm -f passwords.txt' HEAD # 从整个提交历史删除文件
git filter-branch --subdirectory-filter "xxx" HEAD # 将某个子目录作为项目根目录

# 修改邮箱地址
git filter-branch --commit-filter '
    if [ "$GIT_AUTHOR_EMAIL" = "xxx" ]
    then
        GIT_AUTHOR_NAME="xxx";
        GIT_AUTHOR_EMAIL="xxx";
        git commit-tree "$@";
    else
        git commit-tree "$@";
    fi' HEAD

重置和检出

git有三棵目录树

  • HEAD。当前分支的指针,总是指向分支的最后一次提交,作为下一次提交的父提交。可以看作最后一次提交的快照。
  • 索引。即暂存区域,预期的下一次提交。
  • 工作目录。可以看作沙盒,编辑区。

git reset命令,用来移动HEAD分支的指向,更新暂存区域,更新工作区。利用reset命令,可以实现压缩提交。具体为回退后,重新提交。

1
2
3
4
5
git reset --soft "xxx" # 将代码库指向提交xxx
git reset --mixed "xxx" # 移动分支并更新暂存区
git reset --hard "xxx" # 移动分支并更新工作区
git reset --mixed "/xxx" # 路径只更新部分文件
git reset --patch # 一块块的取消暂存

git checkout命令可以用来检出,移动HEAD自身的指向,用于切换分支,对于工作目录是安全的。带路径时,则会覆盖工作区的文件。

1
2
3
git checkout "branch" # 切换分支
git checkout "xxx" -- "/xxx"
git checkout --patch

未完成……

本文由作者按照 CC BY 4.0 进行授权

热门标签