概要
- git 的命令视不同的调用语法,接受 commit 或者 commit range 作为参数,commit 指的是单个 commit, commit range 指的是满足特定条件的 commits 构成的集合;
- 在一个接受 commit range 的上下文中,r 表示 r 及 r 可达的所有 commits, ^r 表示「将 r 排除在外,并且将 r 可达的也排除在外」;
- ^r1 r2 等同于 r1..r2;
- 另外对于 .. 语法,舍去其中的一端等于将这一端用 HEAD 代替,例如 ..r2 等于 HEAD..r2, r2.. 等于 r2..HEAD;
- r1…r2 表示这样的一个 commit 集合:r1 可达的 commits 在该集合中,r2 可达的 commits 在该集合中,但是同时满足 r1 可达和 r2 可达的 commits 不在该集合中;
- 要描述一个 revision 的所有父 commit 的集合:r^@, 注意这个集合不包括 r 本身;
- 在一个接受 commit range 的上下文中,r^! 表示 r 本身,而排除掉它的任何 parent, 也就是说 r^! == { r };
了解 git revisions 的命令
- man 7 gitrevisions 详细介绍指定 git revision 的语法,其中有关于单个 revision 的描述,也有关于指定 commit range 的描述;
- git rev-list <range> 展示一个 <range> (也就是一个 commit range, 也就是一个 commits 集合)具体都包含哪些 commits;
- git rev-parse <revision> 展示一个 <revision> 具体会被 dereference 到哪一个 commit;
合并多个 commit 的几种方法
动机:创建一个临时的 branch, 这个 branch 包含了若干个 commit 的合并 commit, 在图形化 git 前端中,可以方便地查看这个合并 commit 都包含了哪些变更;
方法一:git cherry-pick --no-commit
不足之处:遇到了 merge commit 会比较麻烦,比如说一个 merge commit c3 它的 parent commits 有 c1 和 c2, 那么你需要向 git-cherry-pick 指定 -m 参数(也就是 --mainline
参数)来表明要 replay c3 对于哪个 parent commit 的变更;
方法二:git reset --soft
假设当前的 HEAD 指向 r0, 假设我们执行 git reset --sort rx
, 它能够将 head 移动到一个指定的 revision rx, 但是 tree 和 index 仍然是旧 HEAD 也就是 r0 的版本,这时再执行 git commit
操作就能够创建一个合并了 r0..rx 集合中的所有 commits 的 commit.
方法三:git rebase -i
例如 git rebase -i HEAD~2
, 在弹出的编辑器中将最后一个 commit 标记为 s, 就可以将这个 commit squash 到上一个 commit.