git rebase, reflog, and force push - the nice way to deal with your own branches and keep a clean git history.Warning: don't do this on branches that other people are working on - the force push does nasty things. In that case, it's better to coordinate, collect changes, make a new branch, whatever.
So you've been working on a branch (let's call it
ben.foo) and you're ready to squash a bunch of commits and push it back up to master.
* bring your checkout up to date by getting the heads of all branches
git fetch* set your upstream to master
git branch --set-upstream ben.foo origin/master* rebase all your changes that are different from master
** this brings your branch up to date and puts all your branch's commits after the most recent commit to master
git rebase* squash all your commits
** this automatically chooses only the commits that don't exist in master
git rebase -i* push them up, forcing your branch to remove your previous more verbose commits
** the + sign before the branch name means force push only this branch - much safer than --force, which forces all branches
git push origin +ben.fooWhee!! You're done!
Let's do this another way.We don't really care about master for most of this process - we're really just interested in squashing our own commits, then we can merge or do a PR or whatever like normal.
* Look for the commit before the place we started our branch. I'll assume it's visually easy to find - often the last commit by someone else before a long string of my own commits. Note the commit ID of the not-my-branch commit:
git log* Do an interactive git rebase from that commit on
git rebase -i abcd1234* squash all but the first commit (or however you want to collapse your commit history)
2Gv}:s/^pick/squash/<ret>:wq* push this up, using the same +branch force in the previous example, overwriting the remote repository's messy history
git push origin +ben.fooVoila! Your commit history is now clean
If you screw up any of these steps...git reflog to the rescue.
git reflog ben.fooThis is a complete history of the changes you've made to the branch. Choose the commit ID you want to backtrack to (eg abcd1234) and run
git reset --hard abcd1234Further Reading:
* Two good posts about git reflog
* Many thanks to Brad Kittenbrink for going over this with me.