matt snider
matt snider

Reputation: 4083

How to merge amended commit in branches without conflict?

My work project uses Gerrit for per review and an amended commit model, where you keep amending and push one commit until it gets approved by the team, then it gets pulled into the remote master. This works well, until I push a changelist and while waiting for reviewers, I branch and start working on something else. Inevitably, the reviewers will ask for some change and the original commit gets amended. And when I want to merge it into the branch, I get merge conflicts.

Here is an example:

dd2e86 - 946992 [master]
           \
            76cada [branch]

Once I amend the commit 946992, it gets another hash. I believe git does something like this:

dd2e86 - c2ba32 [amended master]
    \
     946992 - 76cada [branch]

Regardless, I have tried rebasing master on the branch or cherrypicking the amended commit. Either one creates a headache of merge conflicts that have to be resolved each time I rebase, so multiple amends to master make things really difficult.

I have one work around, where I reset the branch ~1 and stash the changes, then reset another ~1 commit to get before the amended commit, then rebase master and replay my stash, but I feel there is a better way. Any solutions?

Upvotes: 2

Views: 799

Answers (1)

torek
torek

Reputation: 488453

Every time you "amend" a commit, you really just get a new commit, just as you believe: git takes whatever you have put into the index (git added) and makes a new commit from it, copying the previous HEAD commit's message, but makes the parent of the new commit be the previous HEAD commit's parent, and then makes the new commit the new HEAD. So your drawing of the subsequent commit-graph is correct.

If the "something else" you want to work on is independent of the other fix, the easy way to handle this is to make the fix based on the commit before the one you're waiting-for-approval-on:

         946992   <-- proposed-fix-A  # waiting for approval
          /
... - dd2e86      <-- origin/master (or whatever)
          \
         xxxxxx   <-- proposed-fix-B

instead of:

           xxxxxx <-- proposed-fix-B
             /
         946992   <-- proposed-fix-A  # waiting for approval
          /
... - dd2e86      <-- origin/master (or whatever)

That way, the parent commit of xxxxxx is dd2e86, which is not going to change, rather than 946992 which is (or might). Once proposed-fix-A is approved and pushed you can rebase proposed-fix-B on the final version, whatever its SHA-1 is then.

(If the "something else" really does require the first fix, you're pretty much stuck resolving conflicts.)


The way to get "proposed fix B" to be based on (i.e., to have as its parent commit) some commit other than the tip of the current branch is to tell git branch or git checkout -b where to start:

... work work work ...
git commit -m "proposed fix A"
# and submit it for review
# at this point, HEAD is proposed fix A, but
# now you want to create a new branch based
# on its parent commit, i.e., HEAD^, so:
git checkout -b fix-B HEAD^
... work work work ...
git commit -m "proposed fix B"

Repeat as desired for additional branches. Note that you can spell the SHA-1 of the starting point with any of the methods listed in gitrevisions, not just HEAD^. For instance, origin/master or origin/branch might be a suitable starting point.

Upvotes: 1

Related Questions