Combine git commits

When working on code, it is common to push many (even dozens or hundreds) whilst testing, particularly if the CI workflow is triggered by a post commit hook on the git server.

This is fine before a feature is released, however it is not desirable to have a large number of commits for a single feature rolled out to production (particularly if you get lazy with commit messages such as "typo", "syntax", "trying a different thing" etc).

1) Check the branch is clean (or add/commit as required)

[robbie@localhost pinball_machine]$ git status
# On branch robbie_freebeer_2018
nothing to commit, working directory clean

2) Check git log (Demonstrating the commits since I branched - I've cut a few from here to make it easier to read)

[robbie@localhost pinball_machine]$ git log --oneline
abcdefa syntax
bbbbbbb typo
ddddddd Fixed check condition for left flipper lane sensor
a723444 Merge pull request #19 in ROBBIE/pinball_machine from bugfix/leftflipper to master

3) Rebase the branch. Let's say I want to rollup the 'syntax' and 'typo' commits into the 'Fixed check condition for left flipper lane sensor' commit, I can perform an interactive rebase. I can either use relative 'HEAD~ {number}' , or specify the commit. In this case, I'd like to rebase from 4 commits ago (a723444), which is "HEAD~3"

We will squash the syntax and typo commits, so that the commit message of "Fixed check condition..." also includes the minor typo/syntax corrections.

This will open the commits in your editor (e.g. vim)

[robbie@localhost pinball_machine]$ git rebase -i HEAD~3

squash abcdefa syntax
squash bbbbbbb typo
pick ddddddd Fixed check condition for left flipper lane sensor

# Rebase a723444..ddddddd onto a723444
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

4) Save the temp file

:wq
[detached HEAD 944f772] Fixed check condition for left flipper lane sensor
1 file changed, 110 insertions(+), 97 deletions(-)
rewrite code/flipper.vbs (62%)

5) Check git log (to demonstrate the squashed commits)

[robbie@localhost pinball_machine]$ git log --oneline
944f772 Fixed check condition for left flipper lane sensor
a723444 Increase default highscore to 999,999,999

6) Force push (you will need to do this, as you're rewriting the branch history on the remote end)

[robbie@localhost pinball_machine]$ git push origin robbie_freebeer_2018 --force
Counting objects: 7, done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 800 bytes | 0 bytes/s, done.
Total 4 (delta 1), reused 0 (delta 0)
remote:
remote: Create pull request for robbie_freebeer_2018:
remote:   https://gitserver/projects/ROBBIE/repos/pinball_machine/compare/commits?sourceBranch=refs/heads/robbie_freebeer_2018
remote:
To ssh://git@gitserver:7999/ROBBIE/pinball_machine.git
+ abcdefa...a723444 robbie_freebeer_2018 -> robbie_freebeer_2018 (forced update)
[robbie@localhost pinball_machine]$