我和另一位开发人员在一个项目中使用 Git 已有几个月了。我有多年的经验SVN,所以我想我给这段关系带来了很多包袱。
我听说 Git 非常适合分支和合并,但到目前为止,我只是没有看到它。当然,分支非常简单,但是当我尝试合并时,一切都变得一团糟。现在,我已经习惯了 SVN,但在我看来,我只是将一个低于标准的版本控制系统换成了另一个。
我的搭档告诉我,我的问题源于我不情愿地合并的愿望,并且在很多情况下我应该使用 rebase 而不是合并。例如,这是他制定的工作流程:
clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature
git checkout master
git merge my_new_feature
本质上,创建一个功能分支,始终从主分支变基到分支,然后从分支合并回主分支。需要注意的是,分支机构始终位于本地。
这是我开始的工作流程
clone remote repository
create my_new_feature branch on remote repository
git checkout -b --track my_new_feature origin/my_new_feature
..work, commit, push to origin/my_new_feature
git merge master (to get some changes that my partner added)
..work, commit, push to origin/my_new_feature
git merge master
..finish my_new_feature, push to origin/my_new_feature
git checkout master
git merge my_new_feature
delete remote branch
delete local branch
有两个本质区别(我认为):我始终使用合并而不是变基,并且我将我的功能分支(以及我的功能分支提交)推送到远程存储库。
我对远程分支的理由是我希望在工作时备份我的工作。我们的存储库会自动备份,如果出现问题可以恢复。我的笔记本电脑不是,或者说没有那么彻底。因此,我讨厌在我的笔记本电脑上保存未在其他地方镜像的代码。
我对合并而不是变基的理由是,合并似乎是标准的,而变基似乎是一项高级功能。我的直觉是,我想做的不是高级设置,因此应该没有必要进行变基。我什至仔细阅读了关于 Git 的新实用编程书籍,它们广泛介绍了合并,但几乎没有提到 rebase。
不管怎样,我在最近的一个分支上遵循我的工作流程,当我试图将它合并回 master 时,一切都陷入了困境。与本不重要的事情发生了很多冲突。这些冲突对我来说毫无意义。我花了一天的时间来解决所有问题,最终导致强制推送到远程主机,因为我的本地主机已经解决了所有冲突,但远程主机仍然不高兴。
对于这样的事情,“正确”的工作流程是什么? Git 应该让分支和合并变得超级简单,但我只是没有看到它。
更新2011-04-15
这似乎是一个非常受欢迎的问题,所以我想我应该用我第一次问以来两年的经验来更新。
事实证明,最初的工作流程是正确的,至少在我们的例子中是这样。换句话说,这就是我们所做的并且有效:
clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git checkout master
git merge my_new_feature
事实上,我们的工作流程有点不同,正如我们倾向于做的那样挤压合并而不是原始合并。 (注意:这是有争议的,见下文。)这使我们能够将整个功能分支转变为 master 上的单个提交。然后我们删除我们的功能分支。这允许我们在 master 上逻辑地构建我们的提交,即使它们在我们的分支上有点混乱。所以,这就是我们所做的:
clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git checkout master
git merge --squash my_new_feature
git commit -m "added my_new_feature"
git branch -D my_new_feature
壁球合并争议- 正如一些评论者所指出的,挤压合并将丢弃功能分支上的所有历史记录。顾名思义,它将所有提交压缩为一个提交。对于小功能来说,这是有意义的,因为它将其压缩到一个包中。对于较大的功能,这可能不是一个好主意,特别是如果您的个人提交已经是原子的。这确实取决于个人喜好。
Github 和 Bitbucket(其他?)拉取请求- 如果您想知道合并/变基与拉取请求有何关系,我建议您遵循上述所有步骤,直到您准备好合并回 master。您只需接受 PR,而不用手动与 git 合并。请注意,这不会进行挤压合并(至少默认情况下不会),但非挤压、非快进是拉取请求社区中接受的合并约定(据我所知)。具体来说,它的工作原理是这样的:
clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git push # May need to force push
...submit PR, wait for a review, make any changes requested for the PR
git rebase master
git push # Will probably need to force push (-f), due to previous rebases from master
...accept the PR, most likely also deleting the feature branch in the process
git checkout master
git branch -d my_new_feature
git remote prune origin
我已经爱上了 Git 并且再也不想回到 SVN 了。如果你正在挣扎,那就坚持下去,最终你会看到隧道尽头的曙光。