小编典典

Git 工作流程和变基与合并问题

all

几个月来,我和其他开发人员一起在一个项目中使用了
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

有两个本质区别(我认为):我总是使用合并而不是变基,并且我将我的功能分支(和我的功能分支提交)推送到远程存储库。

我对远程分支的推理是我希望在工作时备份我的工作。我们的存储库会自动备份,如果出现问题可以恢复。我的笔记本电脑没有,或者没有那么彻底。因此,我讨厌在我的笔记本电脑上有没有在其他地方镜像的代码。

我对合并而不是 rebase 的理由是,merge 似乎是标准的,而 rebase 似乎是一个高级功能。我的直觉是我想做的不是高级设置,所以 rebase
应该是不必要的。我什至仔细阅读了关于 Git 的新实用程序设计书,它们广泛地涵盖了合并,几乎没有提到变基。

无论如何,我在最近的一个分支上遵循我的工作流程,当我试图将它合并回 master
时,一切都变得糟糕透顶。与本应无关紧要的事情发生了很多冲突。这些冲突对我来说毫无意义。我花了一天的时间整理一切,最终以强制推送到远程 master
达到高潮,因为我的本地 master 已经解决了所有冲突,但远程 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

事实上,我们的工作流程有点不同,因为我们倾向于进行 squash 合并 而不是原始合并。( 注意:这是有争议的,见下文。
)这允许我们将整个功能分支变成 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

Squash Merge Controversy - 正如一些评论者所指出的,squash
合并将丢弃您功能分支上的所有历史记录。顾名思义,它将所有提交压缩为一个。对于小功能,这是有道理的,因为它将它压缩成一个包。对于更大的功能,这可能不是一个好主意,特别是如果您的个人提交已经是原子的。这真的取决于个人喜好。

Github 和 Bitbucket(其他?)Pull Requests - 如果您想知道合并/rebase 与 Pull Requests
的关系,我建议您按照上述所有步骤进行操作,直到您准备好合并回 master。无需手动与 git 合并,您只需接受 PR。请注意,这不会进行 squash
合并(至少默认情况下不会),但非 squash、非快进是 Pull Request 社区中公认的合并约定(据我所知)。具体来说,它是这样工作的:

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。如果你在挣扎,那就坚持下去,最终你会看到隧道尽头的曙光。


阅读 80

收藏
2022-02-28

共1个答案

小编典典

“冲突”是指“同一内容的平行演化”。因此,如果它在合并期间“全部下地狱”,则意味着您在同一组文件上进行了大规模的演变。

变基比合并更好的原因是:

  • 你用主人之一重写你的本地提交历史(然后重新应用你的工作,然后解决任何冲突)
  • 最终的合并肯定是一个“快进”的合并,因为它将拥有 master 的所有提交历史,加上只有你的更改才能重新应用。

我确认在这种情况下正确的工作流程(公共文件集的演变) 首先是 rebase ,然后是 merge

但是,这意味着,如果您推送本地分支(出于备份原因),则不应被其他任何人拉取(或至少使用)该分支(因为提交历史记录将被连续的 rebase 重写)。

2022-02-28