Tag Archives: git

Advanced Git Commits

This article will outline some advanced usage patterns for git commit

Skip Staging

When I was first learning Git, I had difficulty grasping the purpose of Git’s staging area. It seemed, at the time, a pointless step in the process of performing a commit. Later in this article, we will see some good reasons for using the staging area. In this section, I will show you how to skip the staging area when committing.

The standard process when committing is to first stage, then commit.

$ # Use a text editor to modify index.html
$ git add index.html # Add to staging area
$ git status         # We see that index.html has been staged
On branch master
Your branch is up-to-date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD ..." to unstage)

        modified:   index.html

$ # Commit with a message
$ git commit -m 'Added content to index.html' 
[master 1203be7] Added content to index.html
 1 file changed, 1 insertion(+)

In the above, we had to use git add index.html to stage the file. However, if we use the -a option of git-commit, we can eliminate this step:

$ git commit -am 'Added content to index.html' 

Here, the -a option causes all the modified files in the working directory to be added to staging automatically. This has the effect of putting the staging process behind the scenes.

Note that the -a is joined with the -m option for convenience. It could have been written like this:

$ git commit -a -m 'Added content to index.html' 

But that’s just more to type. Be sure, however, that the -m option is at the end since Git will expect the commit message to come directly after it.

Verbose Commits

Of course, to see what you are about to commit, you would use git diff. However, if you want to edit your commit message in a text editor (by omitting the -m option), it would be convenient to have the diff available to you in the editor for viewing.

Edit some files in your working tree and try this on for size.

$ git commit -av

As in the section Skip Staging, the -a option is used to add the files to staging automatically (of course, we could have used git add if we wanted to). The other option, -v, meaning verbose, appends a unified diff to the contents of the text editor. This is what I’m seeing in my text editor after I issued the above command.

Change content
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Your branch is up-to-date with 'origin/master'.
# Changes to be committed:
#   modified:   index.html
# ------------------------ >8 ------------------------
# Do not touch the line above.
# Everything below will be removed.
diff --git a/tmp/index.html b/tmp/index.html
index 4b8b391..0aca176 100644
--- a/tmp/index.html
+++ b/tmp/index.html
@@ -3,7 +3,6 @@
         <title>My Document</html>
-        <p>Some content.</p>
-        <p>Some more content.</p>
+        <p>Changed the content.</p>

This makes editing the commit message convenient because you can look at a the diff and comment on exactly what you’ve done. And, if you see something you don’t want committed, you can abandon the commit by leaving the commit message blank and exiting the editor.

Commit and Patch in One Command

One of my favorite features of Git is the ability to stage selected modifications in your working tree. I wrote an article about it here. Normally you would use git add -p to go through all your modifications selecting the ones you want to commit. This is good when you have more than a few modifications. However, when I have made a small modification, and I know there are modifications in my working tree that I don’t want to commit, I use this command:

$ git commit -p

This will first take you through the patch selection process, then put you in a your text editor to write a commit message. You can also add the -v option (which I always do) to get the diff in your editor.

$ git commit -pv

Amending Commits

If you noticed that you made a mistake with your last commit, it’s quite easy to correct it. You may have a typo in the commit message or you may have noticed there was something wrong with the code you committed. Either way, all you need to do is use the --amend option in your git commit.

$ git commit --amend

Your text editor will be launch and you can edit your commit message to whatever you like. When you leave your text editor, you will notice in git log that the last commit you did now has the updated commit message. (The commit’s SHA1 hash will also be different from the original since the commit’s timestamp and message have changed.) You can also modify the code changes in the commit simply by modifying and staging you code, as you normally would, and then committing them with the --amend option. The --amend options can also be conveniently mixed with the -a, -v and -p options described above.

Committing select parts of a file in Git

Have you ever made changes to a file and wanted to commit only some of those changes. Perhaps, along with with your modifications, you’ve also added a lot of instrumentation code to a source file which really shouldn’t be part of the commit. Or maybe you’ve worked on two features in one source file, each of which deserving of their own commit, but you forgot to commit the first feature, so now it appears you have to put the two features in one commit.

Well it turns out Git has a solution to this problem and it’s quite easy to learn how to use it. It’s also very much worth your while to learn it. Plus it helps to explain why Git has an index, unlike most other VCS’s.

So lets say you have a file called helloworld.c which has some changes you would like to commit and some you would rather not. Add it to the index by using the familiar git add command, but this time pas in the --patch option (or -p for short).

git add --patch helloworld.c

Git will then present you with “hunks” of helloworld.c and prompt you to indicate whether or not you want the hunk to be staged. Use y to indicate that you want to stage the hunk, and n to indicate you don’t want to stage the hunk.

Here is a complete list of the options:

  • y stage this hunk for the next commit
  • n do not stage this hunk for the next commit
  • q quit; do not stage this hunk or any of the remaining hunks
  • a stage this hunk and all later hunks in the file
  • d do not stage this hunk or any of the later hunks in the file
  • g select a hunk to go to
  • / search for a hunk matching the given regex
  • j leave this hunk undecided, see next undecided hunk
  • J leave this hunk undecided, see next hunk
  • k leave this hunk undecided, see previous undecided hunk
  • K leave this hunk undecided, see previous hunk
  • s split the current hunk into smaller hunks
  • e manually edit the current hunk
  • ? print hunk help

Now you can check what has been staged by diffing the index:

git diff --cached

If you noticed that you’ve staged a change that you don’t want, you can reverse the operation with this command:

git reset HEAD -p

This will do exactly what git add -p, except in reverse.

Once you have everything staged the way you want it, you can commit you changes like normal

git commit