Search code examples
gitgit-rebase

When git rebasing two branches with some shared history, is there an easy way to have the common history remain common?


Suppose we have the following revision graph:

A-X-Z--B
     \
      \-C

with A preceding both B and C. Further suppose I rebase A from upstream, creating a new commit A*, and then rebase both B and C onto A*. The resulting revision graph is the following:

A*-X'-Z'-B
 \
  \-X"-Z"-C

Note that the shared history is no longer shared. Is there a simple way to fix this, other than, say, rebasing B and then rebasing C onto Z' explicitly. In other words is there a better way to automatically rebase multiple branches at the same time in order to preserve shared history? It just seems a little bit awkward to have to either artificially place a tag at the split point, or manually inspect the graph to find out sha1 of the commit on which to rebase C to keep the shared history, not to mention opening up the possibility of mistakes, especially since I have to do this every time I rebase until I check the changes into the upstream branch.


Solution

  • git rebase --committer-date-is-author-date --preserve-merges --onto A* A C
    git rebase --committer-date-is-author-date --preserve-merges --onto A* A B
    

    This should keep the common commits having the same sha1 and any merges preserved. Preserve merges is not required in this case, but will become an issue with a less trivial history.

    To do this for all branches that contain A in their history do:

    git branch --contains A | xargs -n 1 git rebase --committer-date-is-author-date --preserve-merges --onto A* A 
    

    Hope this helps.

    UPDATE:

    This may be cleaner syntax:

    for branch in $(git branch --contains A); do git rebase --committer-date-is-author-date --preserve-merges --onto A* A $branch; done