So I dun goofed one of my workmate's git branches and had to remove one commit from the history.
You may have noticed that this was buried under a whole stack of other commits...
Normally, if you've made an accidental commit and realised straight away, you can just do:
git reset HEAD^
This will pop off the latest commit but leave all of your changes to the files intact.
Because this commit is buried under a whole plethora of changes from other people, we need to do something else.
Using "git rebase", we can shift things around and keep the other unrelated changes in the history.
(From the git rebase help)
A---B---C topic
/
D---E---F---G master
Becomes:
A´--B´--C´ topic
/
D---E---F---G master
It's a bit hairy, but here's how you can pull it off:
- Checkout "master" branch for the project
- Pull everything in line with:
git submodule update --init
- Create a clean branch using:
git checkout -b 0000_fixed
- Checkout your broken branch
git checkout 0000_broken
- Update init to pull everything in line
git submodule update --init
- Create a copy of the broken branch
git checkout -b 0000_temp
- Rebase towards the clean target branch
git rebase -i 0000_fixed
- Now you get a chance to cherry-pick the commits. Remove any commits you don't want. This step should be easy, assuming you've entered in good commit messages.
- Save and exit.
- git rebase will now attempt to automatically shift your commits.
- If it worked, you'll see this:
Successfully rebased and updated refs/heads/0000_temp
- If not, you'll have some fun conflicts to deal with
Automatic cherry-pick failed. After resolving the conflicts,
mark the corrected paths with 'git add <paths>', and
run 'git rebase --continue'
Could not apply xxxxxxx... progress commit
- Treat this like a normal merge/conflict scenario.
- Do "git submodule update --init" again
- Go into each conflicted file and resolve the conflicts
- Go into each conflicted submodule and checkout your working branch
- Merge in the previous head so you get the incoming changes
- Go back to the project
- Re-commit the conflict resolutions (with the previous commit comment if possible)
- Type:
git rebase --continue
- Rinse and repeat until successful.