Documenting the 'rebase -i' workflow

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

I used to find it hard to resolve conflicts during complex interactive
rebases, and I asked Jonathan for help off-list.  I found the response
very useful.  I thought I should reproduce the original email here so
that everyone on the list can benefit from it.  Please feel free to
add to it.

Also, we should document this somewhere.

-- 8< --
Ramkumar Ramachandra wrote:
> How did you manage to make the rebase look so effortless?  I tried it
> too, but I always end up messing up the conflict resolution, and
> aborting many times before I get it right.  Even after that, I run
> tests on all the patches and correct the pending mistakes by hand.

True, this workflow is underdocumented.  The most important details
are

       [merge] conflictstyle = diff3
       [rerere] enabled

in ~/.gitconfig.  I used to use "git checkout --conflict=diff3"
explicitly instead, which also works.

If you are lucky, a conflict hunk will look something like this:

       <<<<<<< ours
       A
       B
       C
       ||||||| parent of theirs
       B
       =======
       B
       C
       D
       >>>>>>> theirs

It can be merged blindly by following the rule "whenever a feature
is the same between the ancestor and one of the competing versions,
delete it from them".  For example, both the ancestor and "theirs"
have 'B', so:

       <<<<<<< ours
       A
       B
       C
       ||||||| parent of theirs
       =======
       C
       D
       >>>>>>> theirs

Our side and their side both added C independently and from the
context we know that a second 'C' would be redundant.  So we are ready
to resolve the conflict after thinking a little.

       A
       B
       C
       D

Unfortunately sometimes the diff3 conflict style makes conflicts huge
and unmanageable.  That's no good.  I dream of a conflict style that
would show "our" version and the patch hunk to apply.  Since that
doesn't exist yet, often a good strategy is to fake it by looking at
the patch directly.  For example, patches to ChangeLog files rarely
merge cleanly and the conflicts don't tend to be very useful.

       git checkout HEAD ChangeLog
       vim ChangeLog
       :split .git/rebase-merge/patch

"git add" is used to mark good changes and "git diff" to see what's
left to do.  When ready, I build, run some simple tests, "git diff
--cached", "git rebase -i --continue", flinch at how git 1.7.6 broke
my muscle memory, and "git rebase --continue".

Usually I try to only make a single change in an interactive rebase
and let it ripple through, then rinse and repeat.  If something goes
wrong, I can "git rebase --abort" and previous unrelated changes are
not lost.

After a rebase, I use "git diff" to compare to the previous version,
to make sure the changes accumulated are good and nothing was lost.

Summary:

 - conflictstyle=diff3 makes 3-way merging require way less thought
  and history mining.  I don't know how I coped with
  conflictstyle=merge.

 - For thorny cases, "git checkout --ours file" unapplies the patch.
  Then one can

   (a) apply the patch by hand, if it is short.
   (b) fix up the patch by hand and apply it with "git apply", if
       it is long.

  The patch is in .git/rebase-merge/patch.

 - "git rerere forget" is a lifesaver.

 - Check for sanity at each step (by running manual or automatic
  tests) before continuing.

 - Inspect with "git log -p" and by diffing against a merge of the
  pre-rebase state with the new upstream when done.
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]