当我与人们谈论 Git 时,几乎每个人对 `git rebase` 命令 都有强烈的反应。这个命令导致很多人直接更改目录,删除仓库,然后重新克隆并重新开始。我认为这来自于对分支如何实际工作方式的误解、相当糟糕的默认界面,以及一些搞砸事情的合并冲突。
Git squash
如果你曾经在本地进行了大量的提交,并希望有一种方法可以将它们全部压缩成一个提交,那么你很幸运。 Git 将这个概念称为“压缩提交(squashing commits)”。我在编写文档时发现了这个概念。我花了十几个提交才最终把一小段 markdown 弄对。仓库维护者不想看到我的所有尝试都弄乱项目的历史记录,所以我被告知“只需 git squash 你的提交”。
压缩听起来是一个可靠的计划。但只有一个问题。我不知道怎么做。作为 Git 新手,我做了任何人都会做的事情。我查阅了 `squash` 的手册,并立即遇到了障碍。
$ man git-squash
> No manual entry for git-squash
事实证明,我被告知的不是运行一个名为 `squash` 的 Git 命令,而是被要求运行一个完全独立的命令,该命令最终会将我的所有提交合并为一个。这是一个常见的情况:一些使用该工具一段时间的人使用行话或提及一个概念,对他们来说绝对清楚,但对新技术人员来说并不明显。
从概念上讲,它看起来像这样:

图片来自 Dan Burton 在 Unsplash
我这样安排是为了鼓励你,你绝对不是第一个或最后一个被 Git 或谈论 Git 的人弄糊涂的人。要求澄清和寻求帮助找到正确的文档是可以的。文档维护者实际的意思是,“使用 Git rebase 将提交压缩为一个。”
Git rebase
git rebase 命令将一系列提交从其第一个父提交中移除,并将其放置在另一条提交链的末尾,将两条提交链合并为一条长链,而不是两条并行链。我知道这是一个密集的陈述。
如果你回想一下 Git 提交是如何链接在一起的,你可以看到除了你的初始 `main` 分支之外的任何分支都有一个父提交作为该链的“基础”。变基是将另一条链中的最后一个提交作为指定分支的新的“基础”提交的行为。
你可能已经更熟悉 Git merge。看看 git-scm.com 站点如何解释这两者的区别

(Git-scm.com, CC BY-SA 3.0)
在这个合并示例中,Git 保留了图像中显示的提交链 C4,其父级为 C2,在合并 C3 中的更改以创建一个全新的提交 C5 时。 “experiment” 的分支指针仍然存在,并且仍然指向 C4。
此示例中的变基显示了一个类似的情况,即 C4 首先作为一个单独的分支存在,其父级为 C2。但是,它不是与 C3 的代码合并,而是使 C3 成为 C4 的新父级,从而产生了一个名为 C4 的新提交。值得注意的是,分支指针“main”尚未移动。要使 Git 将指针移动到链的末尾(当前由“experiment”指向),你还需要执行合并。
变基不是合并的替代品。 它是一种用于创建更清晰的历史记录的工具,与合并结合使用。
交互式变基是你最好的朋友!
从命令行执行变基最可怕的部分之一是可怕的界面。运行命令 `git rebase <target-refr>` 要么成功,要么崩溃。没有太多的反馈或方法来确保它正在做你精确想要的事情。幸运的是,rebase 命令和许多其他 Git 命令都有交互模式,你可以使用参数 `-i' 或 `–interactive` 调用它。

(Dwayne McDaniel, CC BY-SA 4.0)
在调用交互模式时,变基从一个可怕的黑匣子转变为一个选项菜单,允许你对你正在变基的提交链执行多项操作。对于每个提交,你可以选择
-
Pick:按原样包含它
-
Reword:重写提交消息
-
Edit:在变基完成之前,对提交中的文件进行进一步的更改
-
Squash:将多个提交合并为一个提交,保留所有提交消息
-
Fixup:将多个提交合并为一个提交,但只保留最后一个提交消息
-
Drop:丢弃此提交
我个人喜欢开源 GitLens VS Code 扩展 使用下拉选择列表来布局选项的方式,但 Git 允许你使用任何编辑器分配这些选项。对于像 Emacs 或 Vim 这样的纯文本工具,你需要键入选择而不是从菜单中选择,但最终结果仍然相同。
何时变基
知道何时变基与知道如何变基一样重要。事实上,如果你不关心你的仓库历史记录有点混乱,那么你可能永远不会执行变基。但是如果你确实想要创建更清晰的历史记录并减少混乱你的图形视图的提交,那么始终要牢记一条明确的经验法则
“不要变基存在于你的仓库之外的提交,并且其他人可能已经基于这些提交进行了工作。”
如果你遵循该指导原则,你就会没事的。
简而言之,如果你创建一个本地分支来完成你的工作,请随意随意变基它。但是一旦推送了该分支,就不要变基它。这真的取决于你。
希望你发现这有助于理解 git rebase 命令的工作方式,并且可以更有信心地使用它。与任何 Git 命令一样,练习是学习和理解正在发生的事情的唯一真正方法。我鼓励你勇敢地尝试交互式变基!
Git cherry-pick
大多数开发人员都提交了工作,却意识到他们一直在错误的分支上工作。理想情况下,他们可以直接挑选出一个提交并将其移动到正确的分支。这正是 `git cherry-pick` 所做的。
Cherry-picking 是变基单个提交的艺术。这是一种如此常见的模式,以至于他们为其提供了自己的命令。

(Crossroadsphotototeam, CC BY-SA 2.0)
要执行 cherry-pick,你只需告诉 Git 你想要移动到“此处”(HEAD 指向的位置)的提交的 ID
$ git cherry-pick <target-ref>
如果出现问题,由于 Git 提供的错误消息,恢复起来很简单。
$ git cherry-pick -i 2bc01cd
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
error: could not apply 2bc01cd… added EOF lines
hint: After resolving the conflicts, mark them with
hint: "git add/rm ", then run
hint: "git cherry-pick --continue".
hint: You can instead skip this commit with "git cherry-pick --skip".
hint: To abort and get back to the state before "git cherry-pick",
hint: run "git cherry-pick --abort".
$ git cherry-pick --abort
Git 更多功能
`git rebase` 命令是 Git 实用程序的一个强大组成部分。最好在压力下使用它之前,先使用测试仓库练习使用它,但是一旦你熟悉了它的概念和工作流程,你就可以帮助提供清晰的仓库开发历史记录。
评论已关闭。