I have a branch (e.g. Feature-X) in a git repo.
What I did was the following
git checkout master
git merge Feature-X
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).
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")
branch2 is achieved by:
git diff, the merge base commit
*to the tip commit of
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
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
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.
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".
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
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 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".
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
M's first parent is the old
What we want now is to make a new merge commit (with different ID) that's the same as
M except that:
branch2points to it
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
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:
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.
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
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^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.