Git工作流程和rebase与merge的问题

1042
我已经和另一个开发者在一个项目上使用Git几个月了。我有数年的SVN经验,所以我想我对这种关系带来了很多包袱。
我听说Git在分支和合并方面非常出色,但到目前为止,我并没有看到它的优势。当然,分支非常简单,但是当我尝试合并时,一切都变得一团糟。现在,我从SVN中习惯了这种情况,但我觉得我只是把一个次优的版本控制系统换成了另一个。
我的合作伙伴告诉我,我的问题源于我想随意合并,而且在许多情况下应该使用rebase而不是merge。例如,他制定了以下工作流程:
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 的新编程书籍,它详细介绍了合并,几乎没有提到变基。
无论如何,我最近在遵循我的工作流程时遇到了问题,当我尝试将其合并回主分支时,一切都变得混乱。有大量与不应该有影响的事情发生冲突。这些冲突对我来说毫无意义。我花了一天时间解决所有问题,并最终强制将其推送到远程主分支,因为我的本地主分支已经解决了所有冲突,但远程主分支仍然不满意。
在这种情况下,“正确”的工作流程是什么?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 checkout master
git merge my_new_feature

实际上,我们的工作流略有不同,因为我们倾向于使用“压缩合并”而不是原始合并。(注意:这是有争议的,请参见下文。)这使我们能够将整个特性分支转换为主分支上的单个提交。然后我们删除我们的特性分支。即使在我们的分支上有些混乱,这也使我们能够在主分支上逻辑地构建我们的提交。所以,这就是我们做的:
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(其他?)拉取请求 - 如果您想知道合并/变基与拉取请求的关系,我建议您按照以上所有步骤操作,直到准备合并回主分支。您只需接受 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。如果你正在挣扎,请坚持下去,最终你会看到隧道尽头的光明。


34
很遗憾,新的《Pragmstic编程》书籍大多数是在使用Git的同时仍然思考SVN,这种情况会误导您。在Git中,当事情可以简化时,rebase能够保持简单。您的经验可能告诉您,您的工作流在Git中不起作用,而不是说Git本身不起作用。 - Paul
18
在这种情况下,我不建议使用“挤压式合并”,因为它不会保存有关合并内容的任何信息(就像 svn 一样,但没有合并信息)。 - Marius K
7
底部的注释很棒,我也有过类似的Git使用困难经历,但现在却无法想象不使用它会怎样。感谢最后的解释,对理解rebase有很大帮助。 - Jon Phenow
6
在你完成功能后,应该在将新功能合并到主分支之前进行最后一次变基操作吗? - softarn
17
您的工作流将丢失已删除分支的所有提交历史记录 :( - Max Nanasy
显示剩余8条评论
11个回答

2
我只使用变基工作流程,因为它在视觉上更清晰(不仅在GitKraken中,在Intellij和gitk中也是如此,但我最推荐的是前者):你有一个分支,它起源于主分支,并返回到主分支。当这个图表干净漂亮时,你会知道永远没有问题出现

enter image description here

我的工作流程与你的几乎相同,但只有一个小区别:在将我的分支rebasemaster的最新更改之前,我会将提交squash成一个本地分支中的一个,因为:

rebase是基于每个提交

这意味着,如果您有15个提交更改与master相同的行,则如果您不进行squash,则必须检查15次,但最终结果才是重要的,对吗?

因此,整个工作流程如下:

  1. 切换到 master 分支并拉取以确保您拥有最新版本

  2. 然后创建一个新分支

  3. 在那里进行您的工作,您可以自由地提交多次,并将其推送到远程,不用担心,因为这是您自己的分支。

  4. 如果有人告诉您,“嘿,我的 PR/MR 已经批准了,现在已合并到主分支”,则可以获取它们/拉取它们。您可以随时执行此操作,也可以在第6步中执行。

  5. 完成所有工作后,请提交它们,并如果您有多个提交,请将它们压缩(它们都是您的工作,您更改代码行数的次数并不重要;唯一重要的是最终版本)。是否推送它并不重要。

  6. 切换到 master 分支,再次 pull 以确保您在本地拥有最新的 master。您的图表应类似于以下内容:

enter image description here

如您所见,您现在处于本地分支,该分支源自于master上的过时状态,而master(本地和远程)已经随着您同事的更改向前推进。
7. 切换回您的分支,并将其变基到master。现在,您只有一个提交,因此您只需要解决一次冲突。(在GitKraken中,您只需将您的分支拖到master上并选择“Rebase”即可,这也是我喜欢它的另一个原因。)之后,您将会像这样:

enter image description here

现在,您已经将最新的master更改与您的分支上的更改合并。您现在可以推送到远程,并且如果您之前已经推送过,则必须强制推送;Git会告诉您无法简单地快进。这很正常,因为通过变基,您已更改了分支的起点。但是您不应该害怕:明智地使用力量,但不要害怕。最终,远程也是您的分支,因此即使您做错了什么,也不会影响master
创建PR/MR并等待批准,这样master将具有您的贡献。恭喜!因此,您现在可以切换到master,拉取更改,并删除本地分支以清理图表。如果在将其合并到主分支时未执行此操作,则应该删除远程分支。
最终图表再次变得干净、清晰:

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接