We're new to git at my company, coming to git from Subversion, and over the weekend we ran in to a situation with a branch in our repository where commits were made to the public version of a branch that we didn't want there. We had:
A -> B
And then got the bad commits to put the branch at:
A -> B -> C -> D
C and D should never have been on that branch. The trouble is this branch was "closed" -- this was a released version of our software and there shouldn't have been any new commits to this branch.
In Subversion the only way out of this sort of situation was to commit !D and !C so you end up with:
A -> B -> C -> D -> !D -> !C
Which gets me back to B but keeps me moving forward on the timeline for the branch so anyone with a remote of the branch who syncs with the master repository would get C and D and then have them undone to end up at a logically similar version of B (but not B -- call it B').
I came across this solution for reverting commits in git which seemed ideal: it would put our public repository back to A -> B
. But it meant that any clone of this branch out on anyone's working machine would be very incorrect and everyone would need to re-clone. My fix amounted to:
git checkout thebranch
git reset --hard <<commit # associated with commit B>>
git push --force
I ended up going the route of the above link and it caused quite the stir that:
a) You can throw away commit history at the public repository with git like this, literally re-writing commit reality;
b) Everyone had to re-clone so they wouldn't risk re-injecting C -> D
on to the branch (or the new branch of that branch that we wanted to create).
I think I should have done:
git revert HEAD~2
git commit
git push
But this would have left the branch as A -> B -> C -> D -> E
and it really shouldn't have C -> D -> E
on it because it's supposed to be closed.
I've got three questions:
- How could I have handled the clean up better? Use
revert
instead ofreset
? What's the best practice here for branch pollution? - Did the
push --force
of the reverted branch really destroy the history at the public repository? Or did git roll back to B but keep a record ofC -> D
and that a revert was done back to B at some point by me? It definitely doesn't show the revert in the commit log, but maybe a record of my action is kept some place else? - How do you handle "closed" branches in git such that these changes couldn't have gotten on there in the first place? We did have a tag applied to the repository at commit B and people are supposed to use the branch + tag to get the source for the release, but this is still a scary thing to have changes show up on a branch line that should not have changes on it after commit B. And someone branching from the branch for a patch release could have easily missed the tag and pulled
C -> D
in to their new branch as well.