Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bookkeeping cleanup of equivalent changes across branches in git

I'm attempting to cleanup a large number of topic branches, primarily so that the branch overview for master in github no longer displays spurious "n ahead" indicators in inactive topic branches due to the presence of identical changes.

Without these spurious indicators, this overview page would offer a great way to see at a glance if any commits from old topic branches were inadvertently missed and not merged back down into master.

In the diagram below, Y is a commit in branch topic that was later applied to master as Y' (so they have different sha1 hashes, but identical patch ids).

A --- B --- C --- Y' --- E    <-- master
       \ 
        X --- Y               <-- topic

git cherry master topic appropriately reports:

- Y

But if I try to clean this up by issuing a git merge topic from master, I get a merge conflict since change E in master has since altered the context against which the patch applied.

Is there a way to tell master "Hey, you really do have Y already, so you can stop reporting that you don't."? (Being able to do this in such a way that it could be applied automatically/programmatically is key.)

like image 927
Araxia Avatar asked Nov 13 '22 20:11

Araxia


1 Answers

You can see the effective difference in revisions between branches by passing the --cherry-pick option to git log.

My favourite incantation runs:

git log --left-right --graph --cherry-pick --oneline branch1...branch2

(which I have aliases as git lr).

From the man page:

--cherry-pick 

Omit any commit that introduces the same change as another commit on the "other side" when the set of commits are limited with symmetric difference.

For example, if you have two branches, A and B, a usual way to list all commits on only one side of them is with --left-right (see the example below in the description of the --left-right option). It however shows the commits that were cherry-picked from the other branch (for example, "3rd on b" may be cherry-picked from branch A). With this option, such pairs of commits are excluded from the output.

--cherry-mark 

Like --cherry-pick (see belowabove) but mark equivalent commits with = rather than omitting them, and inequivalent ones with +.


Permanent solution #1

In order to permanently make git stop worrying about commits that were actually cherry-picked, you can always merge the other branh. The merge commit will be marked as a child revision of both the previous commit and the tip of the merged revision tree.

This tells the revision tree traversal to stop walking the history at that point. Doing so would only be safe when merging a revision from the 'other' branch IFF you **know that all it's parents have been merged (as far as you would ever want them merged).

Permanent solution #2

There is also some way to use grafts. This really means nothing more than that you'll tell git - out of band1 - that a certain revision is a child of another revision, without having to actually rebase onto/merge from it.

1 as in, a handwritten file with pairs of sha1 hashes :)

The positive thing about this is that you don't have to rewrite history for this to work. However, if you want to, you can use git filter-branch to make the grafts permanent. You no longer need the grafts file then, but of course, you'll be back with the disadvantages of having to rewrite the history (and possibly invalidating published revision ids).

Loose ends?

If all else fails, sometimes you can be stuck with remote (topic) branches that you frequently want to merge from, but there are differences that you simply never want to take. These would probably result in the same merge conflicts over and over.

In that case I'll just point at git-rerere (Reuse recorded resolution of conflicted merges) which can make life considerably easier, albeit more complicated

like image 70
sehe Avatar answered Dec 09 '22 14:12

sehe