Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to re-merge an already merged branch?

Tags:

git

merge

I have a commit graph that looks something like the one below. Commits marked with * represent lots of commits.

   A*
   |
   B---------
   |        |
   C*       D*    <- old feature branch
   |        |
   E---------
   |
   F*
   |
   G      <- master

The merge commit E was done incorrectly and some changes (not all) in C* have been lost. How can I redo that merge to reintroduce the changes into the current master?

Everything has already been pushed (open source project), so changing history is not an option.

I tried creating a patch from the commits C* and apply that to the master, but because some of the changes from C* have been merged correctly and because the project evolved since that commit, about 80% of the patch fails.

Ideally, we would take all the changes in C*, apply them to master and resolve all conflicts. But because the branches have already been merged, git doesn't detect any changes and won't allow to merge again.

$ git checkout 5bc5295   # C
HEAD is now at 5bc5295... cleanup

$ git checkout -b "missing-commits"
Switched to a new branch 'missing-commits'

$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

$ git merge missing-commits
Already up-to-date.
like image 819
John M Avatar asked Mar 03 '17 15:03

John M


2 Answers

Ideally, we would take all the changes in C*, apply them to master and resolve all conflicts.

No, ideally you would rewind time, do the merge as it was back then (but correctly, this time), then reapply the F* changes and end up with a correct master.

You can do it like this:

git checkout missing-commits
git checkout -b correct-merge
git merge D    # do it right, this time around!
git checkout master
git checkout -b correct-master
git rebase --onto correct-merge wrong-merge correct-master # have fun with the mother of all rebases!

If you manage to handle all the conflicts during the rebase, you will end up with exactly what you wanted, originally, in the branch correct-master.

Since you do not want to change history, you could then create a big patch and apply that to your current master, but I like this approach more (assuming you did all your work in your working directory yourrepos):

cd yourrepos ; git checkout correct-master ; cd ..
cp -a yourrepos newrepos
rm -rf newrepos/.git
cd yourrepos ; git checkout master ; cd ..
cp -a yourrepos/.git newrepos/

Now, when you enter newrepos and do a git status, you will be on branch master and will see precisely all changes between master and correct-master, as if you had applied a patch. It will catch deleted files, new files, changed files, changed permissions, changed symlinks and so on.

Ideally, if everything went right, it will show exactly the missing commits from C. Use your favourite variant of git add and finally a nice git commit (or several, if you prefer), and you're done. No history has been rewritten.

like image 128
AnoE Avatar answered Sep 24 '22 11:09

AnoE


You can try by a cherry-pick:

git checkout master
git cherry-pick B..[last_commit_of_C*]

Git may ask you to confirm the cherry-pick since the commits are in the ancestors.

like image 5
Frodon Avatar answered Sep 24 '22 11:09

Frodon