TL;DR: see the end
There is a "recipe" at the end; scroll down to find it (and then up a bit to find the description and explanation and slightly safer method).
Good news and bad news
In a significant sense, merges don't exactly have a "direction". (The direction you "see" when you look at a merge is a product of your imagination, plus the merge commit's message, plus one more important thing that will be our "bad news"—but it's not fatally bad, in the end.)
Consider this diagram of a pair of branches with commit *
as their merge base:
o--o--...--o <-- branch1
/
...--o--*
\
o--o--...--o <-- branch2
The process of merging ("merge as a verb") branch1
and branch2
is achieved by:
- comparing, i.e.,
git diff
, the merge base commit *
to the tip commit of branch1
;
- comparing the merge base to the tip of
branch2
;
- then, starting from the base, combining both sets of changes.
Hence the actual merge itself should look like this:
o--o--...--o
/ \
...--o--* M
\ /
o--o--...--o
(I named the merge commit M
since we don't know, or really care, what crazy Git hash ID deadbeef
or badc0ffee
or whatever it will have.) The eventual merge commit M
is the merge ("merge as a noun"); it stores the final source tree, based on the merge-as-a-verb combining process.
Which "direction" is this merge? Well, that depends, at least in part, on what labels we stick on it, doesn't it? :-) Note that I carefully stripped away both branch1
and branch2
. Let's put them back:
o--o--...--o <-- branch1?
/ \
...--o--* M <-- branch1? branch2?
\ /
o--o--...--o <-- branch2?
This might look confusing. It probably is confusing. It's a big part of the whole issue. The bad news is, it's not the whole thing. There's something we cannot quite capture in these drawings. It may not matter to you, and if it does, it's not that big a deal anyway; we'll fix it up by making one more merge commit. But for now, let's just press on.
Making the merge commit
Once we make the merge commit M
itself, we have to choose—or have Git choose-which branch it's on. In a simple, unconflicted merge, we always end up having Git choose this. What Git does is simple: whatever branch we are on, when we start the git merge
command, is the branch that gets the merge commit. So:
git checkout branch1
git merge branch2
means that the final picture is:
o--o--...--o
/ \
...--o--* M <-- branch1
\ /
o--o--...--o <-- branch2
which we can re-draw as:
...--o--*--o--...--o--M <-- branch1
\ /
o---...---o <-- branch2
which makes it obvious that we merged branch2 into branch1, not vice versa. Nonetheless, the source code attached to commit M
does not depend on this "merge direction".
Sidebar: Conflicted merges
Conflicted merges are just like unconflicted merges in terms of final result. It's just that Git can't do the merge on its own. It stops and makes you resolve the conflicts, and then run git commit
to make the merge commit. That final git commit
step makes merge commit M
.
The new merge commit goes on the current branch, just like any other commit. So that's how M
winds up on branch1
. Note that the merge commit's message also says something about which branch name was merged into which other branch name—but you have a chance to edit this while you make the commit, so you can change that to suit whatever whim you may have. :-)
(In fact, this is no different from the unconflicted case: both run git commit
to make the final merge commit, and both give you a chance to edit the message.)
The bad news
The bad news is that these diagrams omit something that may matter to you. Git has a notion of first parent: a merge commit like M
has two parents, so one of these is the first parent and one is not.1 That first parent is how you tell which branch you were on when you made the merge.
Hence, while these diagrams, and the merge-as-a-verb process, show that there isn't exactly a "merge direction", this first-parent notion proves that there is. If you will ever use this first-parent notion, you will care about this, and want to get it right. Fortunately, there is a solution. (In fact, there are multiple solutions, but I'll show the klunky-but-straightforward ones first.)
1Obviously, the other one is the second parent: there are only two parents. Git allows, however, merge commits with three or more parents. You can enumerate all parents whenever you have to; but Git considers the first especially important, and has --first-parent
flags to various commands, so as to follow "the original branch".
Getting the merge we want
Let's go ahead and make the "wrong" merge commit:
# git add ... (if needed)
git commit
Now we have:
o--o--...--o <-- [old branch1 tip]
/ \
...--o--* M <-- branch1
\ /
o--o--...--o <-- branch2
where M
's first parent is the old branch1
tip.
What we want now is to make a new merge commit (with different ID) that's the same as M
except that:
branch2
points to it
- its first parent is the tip of
branch2
- its second parent is the previous tip of
branch1
The trick is to save commit M
somehow—that's easy enough, we'll use a temporary name so we don't have to copy down M
's hash ID—and then reset branch1
:
git branch temp # or git tag temp
git reset --hard HEAD~1 # move branch1 back, dropping M
(note that this is the same as brehonia's answer, so far). We now have this graph, which is quite unchanged except for the labels attached to each commit:
o--o--...--o <-- branch1
/ \
...--o--* M <-- temp
\ /
o--o--...--o <-- branch2
Now check out branch2
and run the merge over again; it will fail with conflicts as before:
git checkout branch2
git merge branch1 # use --no-commit if Git would commit the merge
The commit we have not yet made is the same, in a sense, as the merge commit M
—but once we make it, its first parent will be the current tip of branch2
, and its second parent will be the current tip of branch1
. We just need to get the right source to go with this commit we're going to make.
Now we use the merge result we saved with the name temp
. This assumes you're in the top level of your tree, so that .
names everything:
git rm -rf -- . # remove EVERYTHING
git checkout temp -- . # get it all back from temp
We are now using the merge result we committed earlier. We do not even have to git add
anything as this form of git checkout
updates the index, so:
git commit
and we have our new merge M2
, on branch branch2
, as desired:
o--o--...--o__ <-- branch1
/ \ \
...--o--* M \ <-- temp
\ / \
o--o--...--o-----M2 <-- branch2
Now we can delete the temporary branch or tag:
git branch -D temp # or git tag -d temp
and we are all done. With the temporary name gone, we can't see the original merge M
any more.
Sneaky plumbing method
There's actually a shorter way to do all this, using Git's "plumbing" commands, but it's a bit tricky. Once we have everything git add
-ed and have run git commit
, we have the right tree, we just have a commit that has the wrong first and second parent IDs. You may wish to edit the commit message as well, so that it looks like you're merging branch1 into branch2 in the message. Then:
# git add ... (if / as needed, as above)
# git commit (make the merge)
git branch -f branch2 $(git log --pretty=format:%B --no-walk HEAD |
git commit-tree -p HEAD^2 -p HEAD^1 -F -)
git reset --hard HEAD^1
The git commit-tree
step makes a new merge commit that's a copy of the one we just made, but with the two parents swapped. We then make branch2
point to this commit, using git branch -f
. Be sure you get the name (branch2
) right at this step. The HEAD^1
and HEAD^2
names refer to the two (first and second) parents of the current commit, which is of course the merge commit we just made. That has the right tree, and the right commit message text; it just has the wrong first and second parent hashes.
Once we have the new commit safely added to branch2
, we simply reset our current (branch1
) branch back to remove the merge commit we made.