将开发合并到主分支的正确方法

Proper way to merge dev into main branch

我在一家公司工作,我们决定要更恰当地使用git。我负责将dev分支整合到主分支中,对于不同场景下如何正确合并感到困惑。

我们现在的工作方式:开发人员只需将他们的功能分支重新设置为 dev 分支。完成后,他们会向 dev 分支提交合并请求。然后,我会检查代码(我们是一个小团队),并接受合并请求。之后他们会简单地删除功能分支。当 dev 分支被正确测试后,我会在 GitLab 中创建一个到主分支的合并请求,将其分配给自己并批准。这会在 main 分支上创建一个提交:

Merge branch 'dev' into 'main'

但是,现在 dev 分支落后于 main 一个提交。我该如何最好地解决这个问题?到目前为止,我只是简单地将 main 再次合并到 dev 中,但这看起来既麻烦又奇怪,因为它们现在是我的 dev 分支中的另一个提交;

Merge branch 'main' into 'dev'

我也可以在 main 上对 dev 进行变基,但我了解到“你永远不应该对 public 分支进行变基”

This 所以问题告诉我正确的方法是先将 main 合并到 dev 中,以确保主分支保持干净。这是实现 dev --> main 合并的最佳方式吗?

这是否受到 git 快进与 default 合并的概念的影响?我读到,当从当前分支尖端到目标分支有一条线性路径时,就会发生快进合并。这意味着,当 dev 分支在合并时仅领先 xmain 的提交,同时没有对 main 提交(这在我们的代码中很常见)工作,因为我们在技术上只承诺从 devmain),合并将自动成为快进合并?这种行为对于将 dev 合并到 main 是否有问题,我应该在合并时使用 -no-ff 标志吗?

如果我理解正确,快进合并 集成 dev 提交到 main 分支,而 --no-ff merge 导致合并总是创建一个新的提交对象,即使合并可以 快进执行(来源:This SO question)。这是否意味着 ff 合并不会创建提交,而 dev 只是提前 x 提交到 main?在本地合并分支后,我如何将合并推到上游?我是应该在本地合并 dev 和 main,还是继续使用 gitlab web 界面?

不用说,我对这一切感到很困惑。如果有人能解决问题就太好了。

我想集中回答你问题的一部分,因为你一次问了多个问题。您可以问问自己 project/team 是否有一个开发分支是个好主意。如果没有它,也许您会更有效率 and/or 具有相同的代码质量 and/or 维护能力。参见例如this SO question 关于拥有开发分支的好处。

关于本地与 Gitlab/Github 合并: 我总是会尝试与 Gitlab 合并,因为它允许讨论更改并将有关合并(请求)的链接更容易地发送给其他人。此外,它将使您更容易在合并实际发生之前依赖 CI,因此仅在管道成功时才合并(参见 this Gitlab Documentation)。

我认为解决您问题的最佳解决方案(将提交中的更改从 main 带到 dev 分支)是 cherry pickinggit cherry-pick.这使您能够从 main 获取一组提交而无需合并或变基,并避免您指出的所有问题。

看看这个guide,前段时间帮了我很多。

您对 git merge --no-ff 的理解几乎是正确的。可能需要调整的部分是你使用 integrates 这个词来表示快进,而重要的是要意识到你是否允许快进发生,或者你是否使用 --no-ff 强制创建合并提交,生成的文件结构是相同的。在这两种情况下,所有提交都是“集成”的,您可以在两个分支中看到它们具有相同的提交 ID。强制合并提交会影响分支历史图。请注意,在快进合并之后,分支是相同的,这意味着两个分支名称都指向相同的提交 ID。如果 fast-forward 是可能的,但您使用 --no-ff 来创建合并提交,则其中一个分支指向合并提交,并且正如您所注意到的那样,将是源分支之前的一个提交。这引出了您的问题:

However, now the dev branch is one commit behind main. How do I best fix this? Up until now I would simply merge main into dev again but this seems cumbersome and strange as their is now another commit in my dev branch:

此处有两个观察结果:

  1. 实际上,如果您将 dev 合并到 main,然后将 main 合并回 dev ,那么在任何新提交出现在 [=13= 之前],然后快进回到 dev 是可能的,如果你不希望的话,你不必生成新的合并提交(带有消息“Merge branch main into dev”)到。如果您允许快进合并,那么之后 dev 将指向与 main 相同的提交,这将是带有消息“Merge branch dev into main”的合并提交。如果您 选择 为该合并使用 --no-ff 那么您当然会创建一个新的合并提交。
  2. 让我们假设合并提交在那里,要么是因为新提交偷偷进入两个合并之间的 dev,要么是因为您使用了 --no-ff 并强制执行它。 那又怎样? 如果你强制合并提交(例如默认的 Git Flow 推荐),那么是的,你将有合并提交,这意味着 devmain 永远不会相同,完全没问题

现在让我们解决您的其他一些问题:

This SO question tells me the proper way is to first merge main into dev, to make sure main branch stays clean. Would this be the best way of achieving dev --> main merges?

这取决于你。在 Git 流模型中,如果新提交出现在 main 中,您通常会希望尽快将 main 合并回 dev,这样您就不会测试与之前不同的东西你会部署。 (或者更糟的是,如果您从 dev 或临时 release 分支部署,您不会从 main 中删除生产中的修补程序更改,因为它们不在您的 release 分支。)因此,在将 dev 合并到 main 之前,您并不是真的需要将 main 合并到 dev。相反,如果 修补程序出现在 main 上,您应该在不久之后将它们合并到 dev 中。然后 dev 将始终准备好合并到 main.

And is any of this influenced by the notion that git fast-forwards merges by default? ... when the dev branch is simply ahead x of commits to main ... the merge would automatically be a fast-forward merge?

是的。如果可能,快进合并是默认设置。

Is this behavior problematic for merging dev into main, and should I use the -no-ff flag when merging?

没有问题。是否应该强制合并提交取决于您。有一些优点和缺点。摘自我的 :

The merge (with --no-ff) forces a merge commit, and this is helpful because each PR contains the list of commits associated with just that PR, enabling you to view the first-parent history which shows all merges into the branch, and easily compare them. Another benefit of forcing the merge commit is that it's easy to revert an entire PR by simply reverting the merge commit, rather than individually reverting every commit that was in the original PR.

请注意,Git实验室将“拉取请求”称为“合并请求”,因此您可以在上段中看到“PR”的地方替换“MR”。强制合并提交的唯一缺点是:如果您不关心刚才提到的任何这些优点,那么它会给结果图增加不必要的复杂性。

最后,您问了:

How would I then push the merge upstream after merging branches locally? Should I even merge dev and main locally or simply keep using gitlab web interface for this?

如果您没有启用分支保护,这没有什么不同。如果您为 devmain 分支(在 GitLab 中)打开分支 protection/policies,那么您将需要使用合并请求功能来执行这些合并。完成合并请求后,您可以 select 是否要快进或强制合并提交。如果您在本地执行此操作,则只需将分支推送到您的远程服务器 (GitLab),前提是您有权执行此操作。无论哪种方式,最终结果都是一样的。