I have two branches in repository: feature and master. I have merged master into feature and pushed result to remote feature branch:
git merge master
because it contains necessary changes of external interfaces. Than I have discovered that merge conflicts were resolved wrong and I have reverted this merge with:
git revert -n -m 1 78e7ebfa8237
So I'm back on feature not merged. But according to history merge already happened and feature branch already contains necessary changes. Can I try merge branches again (inspecting conflicts more carefully and not commiting before checking build)?
If you have not published the bad merge and its reversion, you can remove them and publish a correct merge instead.
If you have published (pushed or otherwise given out) the bad merge, your best bet is probably to work out a correct merge by creating a new branch starting from just before the bad merge. For instance, suppose the commit graph fragment looks like this:
where merge commit
m
is the one that went wrong, andw
(m
upside down1) is the reversion ofm
. (Note: if you have a more complex history, you probably should use a different strategy; see the link in the footnote.)Here, the idea would be to check out commit
j
directly:You are now in "detached HEAD" mode. At this point you can run a new
git merge
:This will (based on your mention of merge conflicts) stop with a merge conflict, since it's repeating the step that got you bad-merge-
m
. (If it won't stop on its own, add--no-commit
to the merge command.)Now resolve the conflicts correctly this time :-) and
add
andcommit
as needed. This makes a new merge which I'll callM
, and I will draw the new graph like this:This new commit
M
is not (yet) on any branch, and in fact, you don't really need it to be on any branch: what you want is the tree you obtained at this point.Now we'll make this a new (but temporary) branch to remember the SHA-1 of commit
M
:(we could have done this earlier; you can do it at the "check out commit
j
" step if you like; but I have some other, un-tested, methods in mind that I'll outline below). Now let's get back onfeature
and make a new commit that usesM
's tree, rather than that ofm
orw
. There are several ways to do this, but I will illustrate this one since it's pretty simple:The first of these,
checkout feature
, simply gets us back on branchfeature
. The second empties out the index (the "next commit")—this step is only necessary ifM
is missing some file(s) that are inm
andw
—and then the third extracts the entire tree from commitM
into the index and work-tree.Now we're ready to commit the result:
The graph now looks like this:
The files under commit
n
are the same as those under commitM
. We no longer need commitM
and branchtemp
at all, so we can simply delete them (git branch -D temp
), giving:If you're comfortable with using lower level git commands, there's a simpler (?) way to copy the tree from
M
to a new commit we'll put onfeature
. In particular we just need to make a new commit whose parent isw
and whose tree is that ofM
. We can do that in one step while still onM
and the anonymous HEAD, withgit commit-tree
:Assuming this works (I haven't tested this particular form and you might have to use
git rev-parse
to convert the namefeature
to a raw SHA-1), we can then usegit update-ref
to makerefs/heads/feature
contain id$id
:after which it's safe to simply
git checkout feature
to get back on the (updated) branch.This being git, there are more ways to do it, e.g., when on the anonymous branch, you could do this:
which is probably simpler than the
git commit-tree
method (thecommit-tree
method is just what I thought of first, due to having recently written a complicated shell script that usedcommit-tree
for a fancy repo shadowing thing). The way this works is that thesymbolic-ref
puts you back on branchfeature
but does not touch the index (nor work-tree) at all, so it/they still match the tree for commitM
. Then we make a new commit in the ordinary way, using the current index; and since nothing remains to point to commitM
, the garbage-collector will eventually delete that commit (but not the tree itself, which is now safely saved on branchfeature
).1The
m
andw
thing is stolen directly from Linus Torvalds and Junio Hamano.If you execute the git revert, it will undo the merge, so I do not think the feature contains necessary changes. I will goes to the state before merge only with some additional git log. So you can freely merge it. But, if you do not want the additional git log, you can use git reset.
Check which is your wanted previous state:
git log
git reset {commit-id-founded}
resolve your conflicts
merge again