如何避免在GitHub/BitBucket上陷入合并提交的地狱

135

我们的仓库里有很多这样的提交记录:

Merge branch 'master' of bitbucket.org:user/repo

每当开发者将本地分支更新到顶层仓库时,就会发生这种情况。

有没有办法避免这些合并提交污染整个仓库的日志?在发起拉取请求时是否可以以某种方式避免它们?

我知道如果只是在本地虚拟机中完成,我可以使用 git rebase。 在 GitHub/BitBucket UI 中有类似的操作吗?

你们是如何处理这个问题的?

4个回答

195

合并前重新定位功能分支

如果您想避免合并提交,您需要确保所有提交都是快进的。在合并之前,您可以通过确保您的功能分支在开发线上干净地重新定位来实现此目的,如下所示:

git checkout master
git checkout -b feature/foo

# make some commits

git rebase master
git checkout master
git merge --ff-only feature/foo

Rebase有很多标记,包括使用-i标记进行交互式rebase,但是如果您尽可能保持简单,并希望在合并时保留所有分支历史记录,则可能不需要它。

使用--ff-only标记

除了rebase之外,使用--ff-only标记将确保仅允许快进提交。如果提交将是一个合并提交,将不会进行提交。git-merge(1)手册页上说:

--ff-only

拒绝合并并退出非零状态,除非当前HEAD已经是最新的,或者合并可以解决为快进。


1
这是一个很棒的回答。我尽可能经常使用rebase。不过我不知道--ff-only标志。相当酷炫! - Leo Correa
6
感谢您提供关于rebase和--ff-only的建议。然而,正如我所问的,我该如何在GitHub/BitBucket的用户界面中执行此操作?请给予翻译。 - Niklas9
4
我很确定你需要使用CLI来完成你想要的操作。GitHub并没有展示Git的全部功能,只有部分功能以及一些图形化和社交网络附加值。祝好运! - Todd A. Jacobs
3
在将主题分支(feature/foo)合并回主干之前,需要注意的一件事情是,最好先git pull origin master(如果使用远程),以确保主干分支是最新的。如果发现有更新,请务必再次将主干变基到主题分支上,然后再将其合并回主干。 - chikamichi
31
不要称之为“求助于命令行”……实际上你应该警惕“求助于用户界面”! - yurisich
同一主题的另一篇有趣文章:https://www.derekgourlay.com/blog/git-when-to-merge-vs-when-to-rebase/ - phw

20
"Todd A. Jacobs"已经提到了“rebase”的概念。这只是一种更详细的做事方式。 假设你现在在主分支上。
$ git branch
  * master

您想进行修复,因此创建一个从主分支中分离出来的“fixbranch”分支。

$ git checkout -b fixbranch

也许您已经在这个分支上工作了几天,并提交了几次。

在您想要将提交推送到中央主存储库的那一天!请检出主分支并从中央主存储库获取最新更改

$ git checkout master
$ git pull origin master

将你的修复分支与主分支进行变基,以获得清晰的历史记录并在本地库中解决任何冲突。

$ git checkout fixbranch
$ git rebase master

现在fixbranch已经和中央master分支同步,让我将fixbranch合并到主分支中

 $ git checkout master
 $ git merge fixbranch

我完成了!让我将本地主分支推送到中央主分支。

$ git push origin master

https://git-scm.com/book/zh/v2/Git-分支-变基


1

Todd的回答涵盖了命令行。(--ff-only,也可以配置为git命令行的默认合并策略。)

如果您使用GitLab,您是存储库的维护者,并且正在合并其他开发人员的合并请求。如果您想避免创建合并请求,请在存储库中打开“设置” ->“合并请求”,并强制执行仅快进合并:

enter image description here

这将仅在使用合并请求合并时防止合并提交。 如果您还使用命令行git merge,则需要以上解决方案。

此设置的缺点是,如果有许多人在同一源上工作,则他们将不得不经常重建其功能分支,因为来自同事的更改将在他们之前合并。 但为了拥有良好的提交历史,这可能是一个小代价。

看起来怎么样?如果无法使用快速转发策略合并合并请求,则开发人员将在其合并请求页面上获得一个小的重新配置按钮:

enter image description here

他们可以通过单击按钮在 Web UI 中重新基于其特性分支,或者他们可以在命令行上进行变基并强制推送其特性分支到远程。这通常会触发另一个流水线再次构建和测试更改。

如果您使用 GitHub,那么就更简单了。首先,GitHub 尝试自动重新基于功能分支,只要拉取请求的目标分支更改即可。如果重新基础没有冲突,则无需手动操作。其次,如果您想避免创建合并提交,请使用下拉菜单中的最后一项执行合并,而不是直接单击按钮,以允许创建合并提交:

enter image description here


如果有人使用默认的 git pull 命令来将他们的特性分支与上游 (main/master/develop) 更新,则会得到许多合并信息,例如 Merged 'develop' into (回溯合并)。然后,当他们尝试最终合并到主分支时,可能会遇到错误,并且必须进行变基以满足此要求(如果他们的特性分支足够旧)。这样说对吗? - Guildenstern
是的,这是正确的。但开发人员不应该在本地特性分支上使用 pull --merge 命令。他们应该使用 pull --rebase 命令,然后将更改强制推送到远程分支。这样可以保持特性分支的历史记录清晰可读。 - Ferdinand Prantl
是的,这是正确的。但开发人员不应该在本地功能分支上使用pull --merge命令。他们应该使用pull --rebase命令,然后再使用push --force命令推送到远程仓库。这样可以保持功能分支的历史记录清晰可读。 - Ferdinand Prantl

0

可以实现以下操作:

  • branch2 合并到HEAD(又称:当前分支)
    • 不会交错/损坏提交历史记录(即:合并而非进入
    • 不会创建合并提交
    • 不会更改(特别是,不会rebase)branch2
    • 不会对[HEAD]工作树进行中间更改(也就是检出另一个分支),这将要求您清理(或手动存储)您的工作树和/或索引(即暂存区)更改。

以下是如何完成的:

from="branch2" // You only have to change this line
to=HEAD
first_shared_commit="$(
  git merge-base "$to" "$from"
)"
list_of_commits_exclusively_in_from="$(
  git log --format=%H "$first_shared_commit".."$from"
)"

git cherry-pick "$list_of_commits_exclusively_in_from"

我已经为此创建了一个别名。我称之为git merge-quiet。您可以使用以下一行命令在您的.git/config中创建此别名:

git config --global --add alias.merge-quiet '!f(){ to=HEAD; from="$1"; git cherry-pick $(git log --format=%H $(git merge-base "$to" "$from").."$from"); }; f'

我认为这是最好的解决方案,因为它不需要创建一个[暂时的]branch2-rebased分支来避免改变现有的branch2。它通过在内存中创建分支(实际上是将组成分支的提交列表)来实现。

欢迎您的反馈!☮️❤️☸️☯️


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