I just spent the last few hours resolving merge conflicts that resulted from merging
The short answer is that you can't (switch branches ... well, sort of, although you can, sort of, but it's not advisable—it involves monkeying directly with the innards of Git):
$ git checkout -b newbr foo.txt: needs merge error: you need to resolve your current index first
Your index is in this special "merging" state and therefore you cannot stash either. Fortunately, there is no need to do so. (If you resolve everything and then run
git checkout -b newbr and commit, you get a non-merge commit. You can use this, but let's not do it that way.)
What you should do is go ahead and finish the merge: this gives you the merge result you want. You can then re-start the merge in the branch you want, and grab the result you just committed as the result you want, if that's even necessary. You then discard the original merge commit entirely (if necessary). (This is also what you need to do if you accidentally wrecked the merge with a successful
git checkout -b as almost shown above.)
In some cases—including your case—the original merge's parent links are the ones you wanted, and it's just a matter of re-labeling the merge.
I'll show the recipe first, but then explain why it works:
... finish merging ... $ git commit # commit the merge $ git checkout -b AB-merge-branch # create the merge branch $ git checkout big-feature-branch-A # get back to other branch $ git reset --hard HEAD^ # take the merge off of it
Let's draw your setup as it was when you first started to merge:
o--...--o--o <-- big-feature-branch-A (HEAD) / ...--* \ o--...--o--o <-- big-feature-branch-B
That is, you were, as
git status would put it, "on branch big-feature-branch-A" and all was well. Each
o represents a commit (and I marked the merge base, for the merge, with an asterisk).
You then intended to run
git checkout -b AB-merge-branch. If you had done that, the picture would look like this:
o--...--o--o <-- big-feature-branch-A, AB-merge-branch (HEAD) / --* \ o--...--o--o <-- big-feature-branch-B
git merge, which failed with conflicts. You resolved (most of) the conflicts (you must resolve them all before you proceed). When you finally commit, you will get a new merge commit, and that will move the current branch (the one remembered by
o--...--o--o <-- big-feature-branch-A / \ --* M <-- AB-merge-branch (HEAD) \ / o--...--o--o <-- big-feature-branch-B
Not shown here (because it is too hard to show) is that the first parent of the new merge
M is the rightmost (latest) upper row commit, and the second is the lower. (This first vs second stuff matters later, if at all, when someone wants to follow the "main" branch vs "side features that were merged in": the main branch is always the first parent, by definition.)
You forgot to create a new branch name, so what happens now, instead, is this:
o--...--o--o / \ --* M <-- big-feature-branch-A (HEAD) \ / o--...--o--o <-- big-feature-branch-B
The first parent is still the top-and-right-most commit, the second parent is still the bottom such commit. The new merge commit
M is exactly the same. It's just that the label that moved, to point to new merge
big-feature-branch-A (the one that is HEAD), and not the nonexistent
AB-merge-branch (which obviously isn't HEAD).
So all you have to do now is create the labeling you wanted. Anything that makes the new branch name
AB-merge-branch, pointing to
M, suffices for that part. You can use
git checkout -b AB-merge-branch or
git branch AB-merge-branch to do that.
If you do use
git checkout -b you now have to get back to
big-feature-branch-A to fix it up using
git reset (there are other commands you could use, but I'm sticking with
reset here). If you use
git branch to create the new branch, your current branch is undisturbed: you are still on
In any case, you want this
big-feature-branch-A branch name to move back one step, to the first parent of
M, as if it had never moved forward to
M in the first place. So you get back on (or stay on) this branch. Once you're on this branch, you can use
git reset --hard HEAD^ to achieve this moving-back-one-step.
HEAD^ means "find the first parent of
HEAD names commit
M (it does)—means the rightmost upper row commit, which is where you want the branch to point. The
git reset command does this re-pointing of the branch, and also re-sets your index and work-tree (so that everything is cleanly on the new commit).