mlthlschr

Git workflow - how to keep commits clean

git

When commiting my changes, I like to keep the commits as simple and atomic as possible. My basic workflow for that is to check all the changed files, choose the respective lines which have been changed, add them to the commit and commit all of my selected changes.

Jetbrains IDEs incorporate a beautiful commit GUI, where you can do all of that. But as there are days where I am not using a Jetbrains IDE, I asked myself how such a workflow might be possible using the tools at hand - the tools offered by the git command.

File lifecycle

In order to be able to follow the mentioned workflow, it is good to have a better understanding of the git file lifecycle.

Untracked    Unmodified     Modified        Staged
|= add file ===============================>|
|            |= edit file =>|               |
|            |              |= stage file =>|
|            |<==================== commit =|

Pro Git, Chapter 2.2, Figure 8.1

Edited files are in the state of ‘modified’, but are part of a commit only when they have been added to the staging area.

Adding files to staging area

There are several ways to add files and their content to the staging area.

Shotgun

The easiest and fastest way to add files to the staging area is via

git add file

or even easier

git add .

This is the shotgun method - you hit your target but might also hit something else. You have to make sure that your files contain only the information you also want to have in your commit.

More specific

Most of the times, you need to select single lines for a certain commit.

You can also do that via CLI

git add --patch file
git add -p file

Consecutive hunks2 of your changes whithin that file will be shown to you. You can select y or n to add the specific hunk to the staging area or leave it in the modified area.

In case the given hunk is too big, you can split it up by choosing s. Depending on the hunk, the given hunks could contain a single line or a few. The workflow with these smaller hunks is the same as before.

Line by line

If the given choice is still too broad, e.g. you have multiple consecutive lines changed together, an additional split might not be possible. What if you still want to split these lines into different commits? This is where the the manual edit comes into play, by choosing e.

This opens your favorite text editor with the contents of the hunk, which looks more or less like this:

-deleted line
+added instead
 unchanged line
+we want to keep this addition here

Let’s assume you want to add the last line to the commit, but not the deletion and the addition of the first two lines. We have to bring the document to the state it has been before - thus replacing the - of the deleted line with a space and removing the added line completely. Why a space? Space means unchanged (see the unchanged line, it also has a space in front), and exactly thats what we want.

That’s how it looks now:

 deleted line
 unchanged line
+we want to keep this addition here

We can now save and close the editor to apply our custom hunk. There will be a validity check when you save, e.g. you deleted a deletion or added some text which has not been there before. In case there was a problem, you get another chance to edit your selections.

Removing files from staging area

In case you noticed that you added too many files to the staging area, you can simply

git reset filename

This will remove the file from the staging area, but not revert your local changes (as it just changes the file’s lifecycle state from staged back to modified). Now you can start to add it to staging area again or continue committing the rest.

Committing

Before committing, I always like to check what I am about to commit. The best way to do that, is of course via git status, connected with git diff for specific files in the staging area. If you keep your commits light and atomic, then you even might want to try the verbose status

git status -v

to skip the diff part. This will show you all textual changes of all files.

Too much text? Maybe your commit is too big :-)

If you are happy, go ahead and commit!

Losing overview?

I have to admit, you can quickly lose overview over your hunks and you find yourself in a loop of git status and git add -p.

This is where git gui comes in handy. What, leaving CLI? Using GUI? Only noobs use GUI?! Come on, in this case a good visualisation comes in handy.

You can do all the above mentioned steps in the gui by either adding whole files with CTRL+T, adding single hunks by right clicking and adding them, or by marking single lines and adding/removing them.

When you are done with that, you can check the staged items and commit them conveniently.

Commit, push, run!


  1. Pro Git ↩︎

  2. Gnu diffutils: hunks are groups of differing lines in between sequences of lines common to two files. ↩︎