查看分支是否包含未合并的更改

Find out whether a branch contains unmerged changes

在我使用 Gerrit 进行代码审查的开发工作流程中,分支包含对文件的一个或多个更改。在这些获得批准后,这些将被挑选出来并附加上 Reviewed-by 标签。

但是,在尝试删除工作分支时,我收到一条警告,提示并非所有更改都已合并:

$ git branch -d documentation 
error: The branch 'documentation' is not fully merged.
If you are sure you want to delete it, run 'git branch -D documentation'.

但是修改后的文件完全一样。唯一的区别(通过 git show --pretty=fuller 发现)包括 Committer、CommitDate 和提交消息。Gerrit 插入的 Change-Id 完全相同。

有没有办法删除分支而不抱怨这样的差异?当确实有不同的提交未合并时,它显然仍然会抱怨。

git branch 仅适用于 DAG。你要求 git 检查 内容 是否完全合并,这是一个更难的问题。

有两个明显的 git 工具可以找到答案:

  1. git cherry:这可能正是您想要的;试试吧。
  2. git merge:进入您认为应该全力以赴的分支顶端的分离 HEAD,然后对您打算删除的分支进行虚拟合并。如果生成的合并提交与 HEAD 首次分离的点具有相同的树,则执行建议的删除是安全的。 (如果不是,则可能是误合并,或者 if/when 已解决的合并冲突表明它无论如何都是安全的。)

Torek 建议尝试合并分支以查看是否所有内容都已合并。这很容易做到,但需要修改工作树。

假设以下 git 日志,其中 docs update 是一个修改文件 doc/README.dissector 的提交,该文件存在于 documentationmaster 分支上。您可以看到自提交 a984dbf ("parent commit").

中的拆分以来没有其他提交
* 9667666 (master) latest commit
* ...
* 6284040 docs update (commit cherry-picked by Gerrit)
* ...
* a984dbf other commits on master
| * 8b8cb8f (documentation) docs update (branch pushed for review)
|/  
* e76e140 parent commit

它是这样工作的:

  1. 确保当前工作树是干净的(即没有未提交的更改)。如果不是这种情况,请使用 git stash 搁置更改。

    $ git status
    On branch master
    Your branch is up-to-date with 'origin/master'.
    nothing to commit, working directory clean
    
  2. 在这里您可以看到删除 documentation 分支的尝试由于问题中描述的细微差异而失败:

    $ git branch -d documentation
    error: The branch 'documentation' is not fully merged.
    If you are sure you want to delete it, run 'git branch -D documentation'.
    
  3. 没问题!尝试合并...

    $ git merge --squash documentation
    Squash commit -- not updating HEAD
    Automatic merge went well; stopped before committing as requested
    
  4. ... 并检查它是否导致任何差异(您也可以使用 git diff)。如您所见,没有剩余的更改:

    $ git status
    On branch master
    Your branch is up-to-date with 'origin/master'.
    nothing to commit, working directory clean
    
  5. 现在我们确认该分支不包含其他提交,我们可以安全地删除它:

    $ git branch -D documentation
    Deleted branch documentation (was 8b8cb8f).
    

还有第二种但不太明显的方法可以在不触及工作三者或索引的情况下测试合并,如 中所述。

它仅在提交引用(示例中的"master")不包含拆分后的其他更改时才有效。如果是这样,那么您将获得一个差异,其中包含自提交合并以来 master 中的新更改。在这种情况下,使用较早的提交而不是 "master".

示例会话:

  1. 找到基本提交(给定示例中的"e76e140 parent commit"):

    $ git merge-base master documentation
    e76e14074e5a9c46886ab3124a5649eabe7bfe99
    
  2. 尝试合并:

    $ git merge e76e14074e5a9c46886ab3124a5649eabe7bfe99 master documentation
    changed in both
      base   100644 3fdc91af1748f6db1dcb9729cd6e2846b9c7b2f8 doc/README.dissector
      our    100644 10ba4e6b3f1a2e91cb61dc4133bca4a61b50e47b doc/README.dissector
      their  100644 61384b5df44ff0e13374e3d93b3e6d01fa9c380a doc/README.dissector
    
  3. 得出结论。上面的输出可能给你的印象是文档分支没有完全合并到 master 分支中。然而事实并非如此。如果文件不同,差异将显示在这些行下方。当输出为空时,分支被完全合并(并且 git branch -d documentation 不会抱怨)。
    由于没有差异(所有内容都已合并),我们可以安全地删除分支:

    git branch -D documentation
    

使用以下 git 别名,您可以简单地调用 git test-merge documentation 来自动执行上述步骤:

git config --global alias.test-merge '!sh -c '\''branch="${2:-$(git rev-parse --abbrev-ref HEAD)}"; git merge-tree $(git merge-base "" "$branch") "$branch" ""'\'' --'

用法:

# Test merge of branch "documentation" in the current branch
git test-merge documentation
# Test merge of branch "documentation" in the "master-1.12" branch
git test-merge documentation master-1.12