Lekensteyn
Lekensteyn

Reputation: 66395

Find out whether a branch contains unmerged changes

In my development workflow involving Gerrit for code review, branches contain one or more changes to files. After these got approved, these get cherry picked with Reviewed-by tags appended.

However, when trying to delete the working branch, I get a warning that not all changes are merged:

$ 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'.

The changed files are however exactly the same. The only differences (found via git show --pretty=fuller include the Committer, CommitDate and commit message. The Change-Ids inserted by Gerrit are exactly the same though.

Is there a way to delete branches without complaining about such differences? It should obviously still complain when there are really different commits that did not get merged.

Upvotes: 1

Views: 1369

Answers (2)

Lekensteyn
Lekensteyn

Reputation: 66395

Torek suggests to attempt a merge branch to see whether everything is merged or not. This is easy to do, but requires that the working tree can be modified.

Assume the following git log where docs update is a commit modifying the file doc/README.dissector existing on both the documentation and master branch. You can see that there are no other commits since the split in commit 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

it works like this:

  1. Ensure that the current working tree is clean (that is, no uncommited changes). If this is not the case, use git stash to put the changes aside.

    $ git status
    On branch master
    Your branch is up-to-date with 'origin/master'.
    nothing to commit, working directory clean
    
  2. Here you can see that the attempt to remove the documentation branch fails because of minor differences as described in the question:

    $ 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. No problem! Attempt a merge...

    $ git merge --squash documentation
    Squash commit -- not updating HEAD
    Automatic merge went well; stopped before committing as requested
    
  4. ... and check whether it resulted in any differences (you could as well use git diff). As you can see, there are no remaining changes:

    $ git status
    On branch master
    Your branch is up-to-date with 'origin/master'.
    nothing to commit, working directory clean
    
  5. Now we have a confirmation that the branch does not contain other commits, and we can safely remove it:

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

There is a second, but less obvious way to test the merge without touching the working three nor the index as described in https://stackoverflow.com/a/6283843/427545.

It only works if the commit reference ("master" in the example) does not contain other changes since the split. If it did, then you would get a diff containing the new changes in master since the commit got merged. In that case, use an earlier commit instead of "master".

Example session:

  1. Find the base commit ("e76e140 parent commit" in the given example):

    $ git merge-base master documentation
    e76e14074e5a9c46886ab3124a5649eabe7bfe99
    
  2. Attempt the merge:

    $ 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. Draw conclusions. The above output might give you the impression that the documentation branch was not fulled merged into the master branch. This is however not the case. If the files were different, a diff would be displayed below those lines. When the output is empty, then the branch is fully merged (and git branch -d documentation would not have complained).
    Since there is no diff (everything got merged), we can safely remove the branch:

    git branch -D documentation
    

With the following git alias, you can simply invoke git test-merge documentation to automate the above steps:

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

Usage:

# 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

Upvotes: 0

torek
torek

Reputation: 487805

git branch just works from the DAG. You're asking git to check whether the content is fully merged, which is a more difficult question.

There are two obvious git tools for finding an answer:

  1. git cherry: this might be just what you want; try it out.
  2. git merge: Get onto a detached HEAD at the tip of the branch you think you should be all-into, then do a dummy merge of the branch you're proposing to delete. If the resulting merge commit has the same tree as the point at which HEAD was first detached, it's safe to do the proposed delete. (If not, it may be a mis-merge, or perhaps a merge conflict that, if/when resolved, shows that it's safe anyway.)

Upvotes: 3

Related Questions