lost9123193
lost9123193

Reputation: 11030

Fixing Merge Conflicts with Git Rebase and Exporting

I've run into a few merge conflicts with git rebase.

My question is, if I fix the conflicts, do I then do something like this:

git add files
git commit "fixed merge conflicts"

then continue with

git rebase --continue

My other question is if I mess up, can I do

git rebase --abort 

and will that remove all the commits?

Upvotes: 0

Views: 68

Answers (2)

torek
torek

Reputation: 488453

Based on your comment on jready's answer, your real question is whether you should save your original chain of commits somewhere / somehow.

Rebase, at a sort of fundamental level, works by copying (because commits can never be changed—this includes their backwards-looking links). Branch names simply point to some specific commit. If we draw the commits as nodes in a graph, what we have looks like this:

...--F--G--H--I   <-- origin/whatever
         \
          J--K--L   <-- your-branch

If you run git checkout your-branch && git rebase origin/whatever, Git must copy commit J, by turning it into a set of changes vs its parent G, and apply those changes to commit I (where origin/whatever points). Having copied J to J', it then tries to copy K to a new commit K', and so on. The eventual result, after you resolve any conflicts but before Git "peels the name off" commit L, is:

                J'-K'-L'  <-- HEAD
               /
...--F--G--H--I   <-- origin/whatever
         \
          J--K--L   <-- your-branch

The very last step of git rebase is to remove the name your-branch from where it is pasted right now, pointing to commit L, and make it point instead to commit L'—the last copy that rebase made:

                J'-K'-L'  <-- your-branch (HEAD)
               /
...--F--G--H--I   <-- origin/whatever
         \
          J--K--L   [abandoned]

If you use git rebase --abort instead of continuing, Git just abandons the copied chain instead, leaving the name your-branch still pointing to L:

                J'-K'-L'  [abandoned]
               /
...--F--G--H--I   <-- origin/whatever
         \
          J--K--L   <-- your-branch (HEAD)

Before you start the rebase, or any time in the middle of the rebase when your-branch still points to commit L, you can add a new name to remember the raw hash ID of commit L:

                J'-K'  <-- HEAD
               /
...--F--G--H--I   <-- origin/whatever
         \
          J--K--L   <-- your-branch, extra-name

which you might do with git branch extra-name your-branch for instance. That way, after you finish the rebase, assuming you do finish it, you end up with:

                J'-K'-L'  <-- your-branch (HEAD)
               /
...--F--G--H--I   <-- origin/whatever
         \
          J--K--L   <-- extra-name

You don't have to do this, because secretly, git rebase sets up a special name, ORIG_HEAD, to remember where your branch name was before it yanked it off L and pasted it onto L'. But the name ORIG_HEAD will be overwritten by whatever other Git command you use later (maybe another rebase) that yanks a label around like this, so that's sort of a short-term stop-gap you can use to recover if you don't like the result.

Your Git also records, in something called the reflog for the branch, the previous value of the branch name, i.e., the fact that your-branch used to point to commit L instead of L'. These reflog entries last for 30 or 90 days.1 They're not the easiest things to use, though:

git reflog your-branch

will spill out all of them, but what you get is the one-line summary you used in each commit, and when you use git rebase you generally copy the original one-line summary from commit L to commit L', so it can be hard to tell which one is which.

Still, some combination of ORIG_HEAD and the reflogs will usually let you recover without an extra name. Use the extra name if it makes you more comfortable. I do it a lot: if I am working on feature/X, and need to rebase, I create feature/X.0 and then rebase. My original series of commits are now available as the dot-zero version. A few days later, if I need to do another rebase, I create feature/X.1 and then rebase. So feature/X is the latest, and feature/X.<number> is the older one, with more older ones remaining until I collect them up and toss them out myself.


1Technically, the ones that expire in 30 days are using the expireUnreachable time: these are commits that are not reachable from the current value of the reference. Rebase generally makes this kind of reference, so the default 30 day expiration is the one you should concentrate on.

(Reflog entries that are reachable get the 90 day default.)

Upvotes: 2

jaredready
jaredready

Reputation: 2678

git rebase --abort will just back out of the rebase entirely, essentially reverting your repository back to the point in time right before you started the rebase. The only commits that are lost will be the brand new commits that git rebase had created (since git rebase replays your original commits, thus forming new commits).

The original commits are never touched regardless of whether you abort or not.

Upvotes: 0

Related Questions