Git

https://git-scm.com/

The de-facto standard version control system.

Getting Started

For a quick conceptual introduction see https://rachelcarmena.github.io/2018/12/12/how-to-teach-git.html

For a quick practical introduction see gittutorial.

Depending on your skill level, you might want to open both and alternate between them.

Advanced Git

Getting started with commit re-ordering and squashing

Commit re-ordering and squashing (combining multiple commits into a single commit) is achieved with git-rebase.

Warning

git-rebase is a branch history rewriting command, which can get complicated in some situations.

It is generally a good idea to make a backup branch before rebase.

Especially when you are new to rebasing.

You have ended up in a situation like:

* commit A
|
|     Add test for A
|
* commit B
|
|     Add feature X
|
* commit C
|
|     Fix test for A, turns out it was is wrong by
|     - not covering all the cases
|     - made wrong by rebasing on master
|     - missed documentation
|     - had typos
|     - etc

In this situation, commit C is added noise and it complicates review process where reviewer is looking at each commit separately, in order.

Therefore, you want merge commit C into commit A to end up with:

* commit A'
|
|     Add test for A
|
* commit B
|
|     Add feature X

Achieving commit A' that contains changes of both commits A and C making these a single, correct, coherent commit instead of having commit A effectively being a draft and commit C the draft finalization in your pull request.

Another common situation is:

* Commit A
|
|     Add A
|
* Commit B
|
|     WIP
|
* Commit C
|
|     Fix A

You want to merge commit C into A for the reasons above but now you also want to continue progress on commit B. Squashing C into A early makes commit B the HEAD of the branch enabling the more comfortable use of git commit --amend.

How to actually do a rebase squash

Assuming your HEAD is commit C, run:

git rebase -i HEAD~3

which opens your ${EDITOR} with prompt like:

pick commit A
pick commit B
pick commit C

which reflects the current commit order.

First you need to re-order the commits to put C before B and on top of A:

pick commit B
pick commit A
pick commit C

Then instruct git to squash commit C into the previous commit:

pick commit B
pick commit A
squash commit C

Hint

Also see git-rebase --autosquash option.

Hint

For the meaning of HEAD~3 see gitrevisions

Hint

If your HEAD is a branch, you can use git rebase -i master