如何在git中合并提交之前找到两个分支的共同祖先?

时间:2015-05-20 06:35:21

标签: git

背景

我正在尝试编写一个脚本,它将使用git简化我的backport进程。

修复当前版本中的错误的一般过程如下:

  1. master分支到错误修复分支,例如bugfix/abc
  2. 完成所有提交以修复bugfix/abc
  3. 上的错误
  4. bugfix/abc合并到master(没有快进合并)
  5. 现在,当我想将修复程序向后移植到版本1(例如,分支v1)时,我会这样做:

    1. bugfix/abc创建一个新分支,例如bugfix/def
    2. 然后在合并提交之前手动查找master上的提交,例如f4d399238f
    3. 现在我使用rebase:$ git rebase --onto v1 f4d399238f bugfix/def
    4. 这很好用(在解决了我必须在上游合并之前使用提交之后)。

      问题

      如何在合并提交之前找到两个分支的共同祖先? (对于backport过程的第2步)。

      试过

      1. git merge-base bugfix/abc master
        • 由于合并已经完成,因此只返回bugfix/abc
        • 开头的提交
      2. 使用git log结合#1的结果来获取此提交的子级
      3. 更新

        这个问题与Find common ancestor of two branches之间的主要区别在于两个分支已经合并。正如我所提到的,最佳提交作为合并分支的头部返回。我需要在合并提交之前使用共同的祖先

        假设bug修复后的分支已合并为master,如下所示:

        A---B v1
             \
              C---D---F---H master
                   \     /
                    E---G bugfix/abc
        

        正在运行$ git merge-base master bugfix/abc将返回 G ,但我需要 D (甚至 F 也会为了使用目的而这样做rebase --onto)。

        一旦我 D ,我就会跑:

        $ git branch bugfix/def bugfix/abc
        $ git rebase --onto v1 D bugfix/def
        $ git checkout v1
        $ git merge bugfix/def
        

        最终获得所需的结果:

              E'---G' bugfix/def
             /      \
        A---B--------I v1
             \
              C---D---F---H master
                   \     /
                    E---G bugfix/abc
        

2 个答案:

答案 0 :(得分:3)

  

如何在合并提交之前找到两个分支的共同祖先? (对于backport过程的第2步)。

有几种选择:

git merge-base

git merge-base是您要查找的命令

  

git merge-base 在两次提交之间找到最佳共同祖先,以便在三向合并中使用。如果后者是前者的祖先,一个共同的祖先更好比另一个共同的祖先。没有任何更好的共同祖先的共同祖先是最佳共同祖先,即合并基础。请注意,一对提交可以有多个合并基础。

从日志中手动找到它

git log --decorate --graph --oneline --all

这将在日志中显示叉点,以便您可以跟踪分支的提交ID。

答案 1 :(得分:0)

对于我所展示的情况,我找到了一个合理的解决方案:

git rev-list --first-parent master | gawk -v bugfix=bugfix/abc '{
    commit = $1
    branchCmd = "git branch --contains \"" commit "\" \"" bugfix "\""
    if (branchCmd | getline) {
        print commit
        exit
    }
}'

这将打印D

事实证明,如果master已合并到bugfix/abc,则会失败,如下所示:

      E'---G'---h' bugfix/def
     /           \
A---B-------------J v1
     \
      C---D---F-------I master
           \   \     /
            E---G---H bugfix/abc

在这种情况下,它会打印F,但这仍然不是我们想要的。

如果branch --contains只有一些选项限制父母,例如--first-parent就像有rev-list ...

解决方法是将脚本修改为以下内容:

git rev-list --first-parent master | gawk -v bugfix=bugfix/abc '{
    commit = $1
    branchCmd = "git branch --contains \"" commit "\" \"" bugfix "\""
    if (branchCmd | getline) {
        timestampCmd = "git show -s --format=%ct \"" commit "\""
        if (timestampCmd | getline timestamp) {
            revlistCmd = "git rev-list --first-parent --max-age=" timestamp " \"" bugfix "\""
            while (revlistCmd | getline line) {
                if (commit == line) {
                    print commit
                    exit
                }
            }
        }
    }
}'

这里的想法是我们采取每个可能的结果,并检查是否可以从bugfix/abc到达,但只能在第一个父项后面。 --max-age意味着我们只会在必要时返回。如果无法访问,则必须是从masterbugfix/abc的合并。如果是,那么我们打印提交哈希并退出。