Reverting Bad Merges

I haven't pushed the merge

If you haven't pushed the merge yet, this is easy. "git reset --hard PRE_MERGE_SHA" where PRE_MERGE_SHA is the SHA of the commit prior to the merge. Warning: This completely destroys the merge and anything committed since. It's as if it never happened. Use with caution. If you have commits after the merge that you'd like to save, you can use "git format-patch" and "git am" to store them away and re-apply them. The general technique looks something like this. BAD_MERGE_SHA is the SHA of the merge itself. CURRENT_HEAD_SHA1 is the current head of the branch. If you don't have commits after the merge, skip the "format-patch" and "am" steps.

git format-patch --stdout BAD_MERGE_SHA..CURRENT_HEAD_SHA > my.rescue
git reset --hard PRE_MERGE_SHA
git am my.rescue

The merge was pushed

This is Hard.

You can just revert the merge. Here's the official why and how to do it. However, this leaves Git with the erroneous belief that the merged commits are still on the target branch. That leaves two landmines waiting to surprise developers: 1. A future attempt to redo the merge, or perhaps cherrypick parts of it over will silently drop commits (after all, they're already applied) and 2. If you ask "Is this commit part on this branch?" you'll get "yes" for commits that were reverted as part of the merge. As such, it may be the wrong answer. On the up side, it's relatively straightforward. If the merge is relatively small, it's probably the right solution.

If you need to "really" revert the change, the following steps will walk you through it. For this example, the merge target branch is V7_4-branch. Change it, and the commit SHAs to whatever you're actually doing.

Commit Notes
584e2bb18f4e038066e44b53cddd9945e0b9dbbb Last good commit on V7_4-branch before the merge
80fc0a87a790657756aed97dd3d4bdc852e50081 The bad merge
63964181bbe027cfead32e3a6886349dbfab61a7 The head of V7_4-branch

  1. Send out email to everyone who might be working with our Git repo, warning them to stop pulling or pushing the relevant branch. The sooner this happens, the easier it should be. "Everyone" is probably condor-devel and condor-team.

  2. Create a ticket to track this work. You'll use it later. Document what went wrong, noting the relevant branches and commit SHAs.

  3. Save good work on the V7_4-branch. The version numbers are the bad merge and the head.
    git checkout V7_4-branch
    git format-patch --stdout 80fc0a87a790657756aed97dd3d4bdc852e50081..63964181bbe027cfead32e3a6886349dbfab61a7 > v7.4-rescue
    

  4. Back V7_4-branch to the commit immediately before the bad merge.
    git reset --hard 584e2bb18f4e038066e44b53cddd9945e0b9dbbb
    

  5. Reapply the good work
    git am v7.4-rescue
    

  6. Push the correction upstream. Note that this actually deletes the branch upstream, then pushes the corrected version. This is because our upstream is a "bare" repository. (A bare repository lacks a working tree, and is a good idea for a repo that no-one uses directly.) If it wasn't bare, we could have used "git push --force origin V7_4-branch"
    git push origin :V7_4-branch
    git push origin +V7_4-branch
    

  7. Flesh out the ticket with information on how to update local repositories. Here's a template; remember to put the correct branch name and SHAs! You can also look at #1084 as a live example of this.
    The changes documented below involve versions of HTCondor that were never released.  Customers do not need to worry about them.
    
    V7_5-cream_hardening-branch was merged into V7_4-branch in commit 80fc0a87a790657756aed97dd3d4bdc852e50081.  This is probably wrong.  Notably, V7_5-cream_hardening-branch has repeatedly had master merged into it, so V7_4-branch now contains all of the master (7.5.x) work!
    
    This has been undone, but it has ramifications for anyone working with out Git repository.
    
    All developers will need to check to make sure they don't have the bad merge lurking in their repositories. If you haven't done a "git pull" or fetch since December 20th, you're probably okay, but check anyway.
    
    To check, on any local branch you have that is based on V7_4-branch, do the following, repleacing V7_4-branch with your local branch name.
    
    1: Check if you have the bad merge on the branch:
    {code}
    git rev-list V7_4-branch | grep 80fc0a87a790657756aed97dd3d4bdc852e50081
    {endcode}
    1: Check the output and return code ("echo $?") of the previous command:
    *::If there is *no output* and a *non-zero return code*, all is well.  This branch is safe.  Go back to the start and repeat for other branches based on V7_4-branch.  If you're out of branches, you're done!
    *:: If the *return code is 0* and the *output is "80fc0a87a790657756aed97dd3d4bdc852e50081"*, then you have the bad merge.  If this is the case, you *must* destroy and recreate the branch, otherwise you could reinfect the central repository.  Continue:
    1: You'll need to delete your infected V7_4-branch and recreate it.  Do you have committed changes to V7_4-branch that you haven't pushed?
    *:: *No un-pushed changes:* Just run the following to delete and recreate the local branch:
    {code}
    git checkout master
    git branch -D V7_4-branch
    git branch V7_4-branch origin/V7_4-branch
    {endcode}
    *::*Un-pushed changes:* You will want to store your good changes away and reapply them. Be careful to not accidentally drag in the bad merge!  You can _not_ use git stash for this, as git stash will just stash away the bad merge.  You can do this by hand, or you can use "git format-patch" and "git am" to store them away and re-apply them.   Use "gitk" or similar to find the ranges of SHAs that contain your changes.  Be sure to _not_ include 80fc0a87a790657756aed97dd3d4bdc852e50081 in the range!  If you have multiple ranges, simply call "git format-patch" repeatedly, appending to the same file.  Once you have your ranges, use the following, or something similar:
    {code}
    git format-patch --stdout EARLIEST_GOOD_SHA1..CURRENT_GOOD_SHA1 > v7.4-rescue
    git checkout master
    git branch -D V7_4-branch
    git branch V7_4-branch origin/V7_4-branch
    git checkout V7_4-branch
    git am v7.4-rescue
    {endcode}
    

  8. Email everyone to let them know that they must update their local repositories before doing any more commits, pulls, or pushes. Here's a template. Be sure to replace the link with a link to the ticket you made.
    If you're using our Git repository, THIS IS IMPORTANT!  If you're
    not, my apologies for the bother.
    
    Before making any more commits, and definitely before doing any
    pushes, you _must_ follow the directions at
    http://condor-wiki.cs.wisc.edu/index.cgi/tktview?tn=1084
    
    That page explains what happened, what steps you need to take,
    and if you're curious, what corrective measures were taken.
    

  9. Close the ticket.