Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove incorrect merges from repository

Tags:

git

git-branch

I'm not happy with the title but I think I overcomplicated my explanation and it is as simple as above in the end.

We are using a branching model with a central origin repo, a "develop" branch, with feature branches off this branch.

I had developed a local set of changes off the develop branch, something like:

develop (A)- (D1) - (D2)
         \ - (F1) - (F2) - (F3) - (F4)

At this point I slipped up in my git gui and, instead of pushing my feature branch as a remote branch to origin, I somehow pushed it back into origin/develop. So, we now had:

develop (A)- (D1) - (D2) -      -      (M1)
         \ - (F1) - (F2) - (F3) - (F4) /

Which we didn't want just yet. Since there was only my self and one other developer in on this particular day, I logged into the origin host and manipulated the develop head back to the D2 commit and my feature branch back to F4. I asked my colleague not to pull until I'd done this, and thought therefore that all was well.

(in actual fact I cloned the origin repo, made the head changes locally, and then force-pushed them back upstream. I don't actually remember the exact commands but the outcome was the repo as desired, as far as I could see).

What I had forgotten is that our continuous integration system was doing regular pulls and managed to get a copy of the merged heads. A week later I noticed some commits by cruisecontrol on the origin host and got a bad feeling. Sure enough it was merging the origin develop head into its local "feature branch merged" repo.

So we are now in a situation somewhat like this:

Cruisecontrol repo:

      (from origin/develop)            (C1) - (C2) - (C3)
develop (A)- (D1) - (D2) -      -      (M1) \ (M2) \ (M3)
         \ - (F1) - (F2) - (F3) - (F4) /

Origin repo:

develop (A)- (D1) - (D2) - (C1) - (C2) - (C3) 
         \ - (F1) - (F2) - (F3) - (F4)

Where C1 and C2 are commits made into the origin repo by us developers who have the "corrected" repo (ie after my head manipulations to undo my initial mistake), and M2 and M3 are the merge commits that the cruisecontrol repo now had to make.

Now I did something really stupid. I "git push"'ed in the cruisecontrol source repo. So our "origin" repo now has the M1 merge and the intervening M2 and M3 merges.

I've once again got my colleagues to not pull for a while. However, my git-foo is not strong enough to detangle the Mx and Cx commits from each other in the origin repo and restore things back to how they should be.

I think I need to do something clever with HEAD^(x) and HEAD~(y), but this is a difficult situation to explain succinctly and thus rather hard to google for.

All advice welcomed; I have a nightly backup of the repo running and can probably just restore from that and have everyone re-push their commits from today, but I'd like to know if this type of branch detangling is possible at all.

I think I should be able to end up with the origin repo as in the above origin diagram, and the cruisecontrol repo deleted and re-cloned, and the M series of commits ready to be garbage collected in the origin repo.

Thanks!

like image 731
Steven Dickinson Avatar asked Nov 04 '22 16:11

Steven Dickinson


1 Answers

all commits in git with the same hash are identical (and so is there history), so you should be able to use the same commands in both your origin and your CI repository (given that develop is checked out:

# on the current branch:
git reset --hard C3
# on your feature branch:
git branch -f feature F4

git push should not force-push by default, and you did not state that in your question where the CI -> origin push happened, so I'm assuming it was a fast-forward push (the default)

for the future I recommend your CI repository to do a git fetch + git reset --hard origin/develp, unless you want your branches merged together (possibly with commits only existing in the CI repo)

like image 133
knittl Avatar answered Nov 09 '22 14:11

knittl