Chapter 5
Getting Productive

Now that you understand the Git workflow, how to create a repository, and how to configure the local environment, I’ll show you how to use Git to start tracking and managing content. I’ll also further explain concepts such as SHA1, options for staging files, and forming good commit messages. First, though, I’ll discuss something that both new and experienced users need to know: how to get help.

Getting Help

Git includes two different forms of help: an abbreviated version and a full version. The abbreviated version is a short list of options with brief explanations that display one per line on the terminal screen. It is invoked by using the -h option after the command, as in git commit -h.

This is useful when you just need a quick reminder of what options are available or how to specify a particular option. Figure 5.1 shows an example of abbreviated on-screen help.

Image described by caption and surrounding text.

Figure 5.1 Abbreviated version of help invoked with the -h option

The full version is the man page for the command, which opens up in a browser on some systems. It is invoked by using one of two forms: either adding a --help after a command or using the help command itself as in git commit --help or git help commit.

With either of these forms, you have access to the full documentation on the command and all its options, with explanations and some examples, via the man page. This is useful when you need to understand more about an option or command.

The format for the help command is as follows:

git help [-a|--all] [-g|--guide]
           [-i|--info|-m|--man|-w|--web] [COMMAND|GUIDE]

The guide part of this command refers to some brief but helpful documentation on different aspects of using Git that you can select through help.

For example, here’s a command to display a built-in guide that is a glossary: git help glossary.

You can use the command git help -g to get a list of all available built-in guides. (Be aware that some of these guides might be out of date.)

The remaining options have to do with whether the help is displayed as a web page, man page, and so on. You can specify the format to use by setting the help.format setting—for example with the commands git config --global help.format man or git config --global help.format web.

Figure 5.2 shows part of a web man page for one Git command.

A screenshot of a part of a web man page for one Git command.

Figure 5.2 Git browser-based man page

Of course, you can always Google a particular command or option to find out more about it.

The Multiple Repositories Model

In Chapter 2, you explored several key design considerations for repositories, including repository scope and file scope. The factors I discussed there explained why Git works best with multiple, smaller repositories rather than larger, monolithic ones.

With this model, it is common to have each of the modules of your project housed in a different Git repository. As a result, you may need to clone several different repositories to get everything you need to work with locally. Each repository ends up in a separate directory tree on your disk.

Likewise, if you’re starting a new project, you may be creating new modules that are each targeted for a separate Git repository. As I discussed in Chapter 4, the git init command is used for creating new repositories, one per directory tree.

Although working with multiple repositories at the same time is common in Git, it is a different way of working for most people. Figure 5.3 shows a diagram that represents these kinds of scenarios. Here, some repositories are newly created by the init command, and some are cloned down from existing remote repositories. Notice that each repository is housed in a separate working directory where the actual repository is physically stored in the .git subdirectory tree within that directory.

Image described by caption and surrounding text.

Figure 5.3 Working with multiple repositories

In Chapter 4, I also talked about configuration for Git and the different levels: system, global, and local. To illustrate how that would work in a multiple repository model, you could group these directories into multiple users on the system with configuration files at the appropriate levels.

Figure 5.4 shows one possible organization. Note that each repository has its own local configuration as represented by the document icons in each directory. Further, each user has their own global configuration (for all of their repositories) as represented by the document icons in the user sections. Finally, there is one system configuration (for all users) as represented by the document icon next to the System title.

A schematic diagram of one possible organization of overlaying configuration files.

Figure 5.4 Overlaying configuration files on your model

Adding Content to Track—Add

I’ve already talked about adding content to Git with the add command. The dark arrow in Figure 5.5 reminds you where adding and staging fits within the overall promotion model workflow.

Image described by caption and surrounding text.

Figure 5.5 Where adding and staging fit in

It’s worth spending a moment here to discuss what I mean by three related terms: tracking, staging, and adding.

Tracking refers to having Git control and monitor a file. The first step in getting Git to track a file is staging it. Here, staging means that you tell Git to take the latest change from your working directory and put it in the staging area. You do this using the Git add command. This is why I sometimes refer to staging a file as adding a file and vice versa.

Another important point is that whether you are staging a completely new file that is not currently tracked by Git, or staging an update to a file already tracked by Git, you still use the add command. Think of it as always adding content into Git.

Staging Scope

As I discussed in Chapter 3, one of the purposes of the staging area is to allow you to build up a complete set of content to commit as a unit into the local repository. When it is done in stages like this, a user may be staging only a subset of eligible files at a time—some files may not be ready. As an example, I could do git add file1 followed by git add file2 followed by git add file *.

For users who don’t choose to use the staging area in this way, it is more common to just stage everything that is eligible. The command git add . does this for you. (Note that “.” is a required part of the command here.).

You can also supply a pattern to select groups of files from the directory structure, as with a command like git add *.c that selects only files with a “.c” extension.

By everything that is eligible above, I meant all files that are new or updated AND not ignored. New or updated is self-explanatory. Not ignored requires further explanation.

Ignoring Files

Typically, when working in a local directory tree on a project, there is some subset of files that you don’t want (or need) the source management system to track. Examples include those files I talked about in Chapter 2: generated output files that should be re-created from the source each time, or external dependencies that are stored and managed in another system (such as an artifact repository).

To tell Git to ignore certain files (meaning not to track them), you just need to list them in a Git ignore file. This is a text file named .gitignore that is placed at the root (top level directory) of the local environment. If this file exists locally, Git will read it and ignore files and directories that match the names and patterns specified within it.

The Git ignore file is covered in more detail in Chapter 10. While not strictly required, having a Git ignore file is considered a best practice for any project managed by Git.

Partial Staging

Before you begin, this section outlines functionality that can be useful but is not required for using Git. If you are only interested in basic staging of files, you may want to skip over this topic for now.

On the opposite end of the spectrum from staging all eligible files or sets of files, Git includes an option that allows for partial staging. This means choosing to take selected changes from a file, but not necessarily all of them. You can use the -p option to do this, as in git add -p <file or . or pattern>.

This command tells Git to treat the changes in any file being staged as one or more separate hunks. Here, a hunk is a change to a set of lines that is separated from other hunks by a set of unchanged lines. The number of hunks also depends somewhat on the size of the file. For small files, even those with several changes, Git may present the entire set of differences as a single hunk.

Through an interface that Git presents, users can choose which hunks they want to have staged and which they don’t, as well as other functionality. The interface will show the first hunk of the file, followed by a prompt. Here’s a simple example of output from the add with -p option:

diff --git a/file b/file
index SHA1..SHA1 filemode
--- a/file
+++ b/file
@@ -1,7 +1,7 @@
line 1
line 2
line 3
-line4
+line 4
line 5
line 6
line 7

Stage this hunk [y,n,q,a,d,/,s,e,?]?

What do you need to know from this? It is essentially a diff between the version in Git and the ­version in the working directory. These are represented as a and b in the header. The line, “@@ -1,7 +1,7 @@”, describes the range of differences for the two files. You can think of that line like this: Before the changes in this hunk, designated by the “-”, starting at line 1, you had 7 lines. After applying the changes in this hunk, designated by the “+”, there should be 7 lines.

In the actual listing, lines that are added show up with a “+” in front of them. Lines that are deleted show up with a “-” in front of them. In this particular case, I modified the same line, but here, Git shows it as one line being removed in the original version and another line being added in the new version. As a result, the before and after line counts are the same.

Now that you know how to interpret the hunk, you can decide what to do with it. If you select ? (or an option that isn’t supported), Git will display the meaning of the different available subcommands as follows:

y - stage this hunk
n - do not stage this hunk
q - quit; do not stage this hunk or any of the remaining ones
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 help

Let’s look at a couple of the most useful subcommands here. As implied by the help text, y tells Git to stage this hunk. This means that this portion of the file’s changes will be staged. Likewise, selecting n means that this portion of the file’s changes will not be staged. Essentially, you are selecting which changes you want to take from the file or files in your working directory and stage for a future commit into the repository.

Most of the other subcommands are for doing bulk operations with hunks or navigating around the set of hunks. If you select g and have multiple hunks, Git presents you with a list of the available hunks identified by number and allows you to select which one you want to work with next. If you type a “/” and specify text found in the file, Git will jump you to the hunk with that text.

Two other subcommands of the patch staging interface are s for split and e for edit. I’ll briefly ­discuss the use of each one.

The split subcommand tells Git to split the file into smaller, separate hunks during an add operation with the patch option. This is useful if you have a fairly small file and Git presents it initially as one single hunk. Note that if you do not see an s in the prompt list, this means that Git has already split it down as small as it reasonably can. This subcommand can be useful to let you get finer-grained control to stage or not stage smaller changes instead of having to try and deal with one big change.

Editing a hunk allows you to modify the lines within it. When you choose this option, Git brings up the configured editor with the hunk in the patch format. The idea is to make your edits, save the file, and exit the editor.

Each line of a hunk is indented one space in the editor. The first column is used as a way to specify the changes to make. Based on the existing changes between the two versions of a file, lines to be added have a “+” in the first column and lines to be deleted have a “-” in the first column. To remove one of these lines, the built-in help suggests deleting the line if it has a “+” or changing the “-” to a “ ” if you want to remove a line starting with a “-”. Other changes can be made in the patch, but they will increase the probability of the problems I’ll talk about next.

Figure 5.6 shows an example of a session for editing a hunk.

A screenshot of an edit session for a hunk.

Figure 5.6 An edit session for a hunk

The Problems with Editing Hunks

Editing hunks via the Git command line is not recommended for beginners. The reason for this is that you are essentially editing a patch to be applied against a file. However, this patch is based on a starting place in the file and an expected number of lines (that is, the information between the @@ signs in the header).

It is very easy to make an edit that will cause the patch to not align with the starting line and the expected number of lines. When that happens, the patch will not apply. After you exit the editor, you will see a message that says something like this: “Your edited hunk does not apply. Edit again (saying “no” discards!) [y/n]?”. This message may also be accompanied by an equally dubious one such as this: “fatal: corrupt patch at line ##”.

This means that some change you made in the editor caused the patch (this hunk) to not be able to merge into the rest of the file. This is an easy state to get into and a hard state to get out of, especially because modifications in an earlier patch can affect the expected starting line and line counts for later patches. To make this all work from the command line in all but the simplest cases requires some calculations on where a particular patch should start, the number of lines affected, and so on.

A better option is to stage those hunks that are ready, and not stage the ones that need further edits. You then edit the entire file in an editor, make the edits as needed, and stage those updated changes. (If needed and available, the split subcommand can further reduce the size of hunks before doing this.)

Interactive Staging of Commits

There is one more variant of the staging (add) and commit functions that is available to users: interactive staging. This option presents a different command line interface that lists the various files and available staging functions and assigns a letter or number to each one. You then choose content and perform operations by entering the corresponding letters or numbers at an interactive prompt.

To invoke this function, you must add the --interactive option at the time you execute the command. Here are some examples:

$ git add --interactive
$ git add --interactive *.c
$ git commit -m "update" --interactive
$ git commit --interactive
$ git commit --interactive -m "my change" file1.java

In short, you can add the --interactive option on any add or commit command line to use this interface.

The interface actually performs the same function whether you are running it as part of an add command or a commit command—it allows control over what is in the staging area using a more concise interface.

As a brief example of how the interface works, consider a case where you have a new Git repository with three files (file1.txt, file2.txt, and file3.txt) that have not yet been added to Git. In this state, the files are called untracked files (more on that in the next chapter).

Now if you run the add command with the interactive option, you are presented with the interactive listing and prompt.

$ git add --interactive

*** Commands ***
  1: status       2: update       3: revert       4: add untracked
  5: patch        6: diff         7: quit         8: help
What now>

Notice that the prompt is asking what you want to do now. You indicate which operation by entering either the number or the first letter (highlighted) of the command from the listing. In this case, you’ll add (stage) some of the currently untracked files. To do this, you start the operation by choosing 4 or a.

What now> a
  1: file1.txt
  2: file2.txt
  3: file3.txt
Add untracked>>

You’re presented with a list of the untracked files in the directory. Each file has been assigned a number by which you can refer to it. In this case, you’ll add (stage) files 1 and 3. You could do this via two separate inputs, or via a comma-separated list. Here, you’ll use the latter format.

Add untracked>> 1,3
* 1: file1.txt
  2: file2.txt
* 3: file3.txt

After you do this, Git tells you that you’ve staged the two files by putting the “*” in front of their names. Because you’re done with this command, you can just press Enter/Return with nothing after the prompt to return to the main prompt. Git tells you that two paths (files) were added.

Add untracked>>
added 2 paths

*** Commands ***
  1: status       2: update       3: revert       4: add untracked
  5: patch        6: diff         7: quit         8: help
What now>

If you now choose the status command, Git displays in this concise format what you have in the staging area and how it relates to what you have in your working directory.

What now> s
           staged     unstaged path
  1:        +1/-0      nothing file1.txt
  2:        +1/-0      nothing file3.txt

*** Commands ***
  1: status       2: update       3: revert       4: add untracked
  5: patch        6: diff         7: quit         8: help

Let’s take a closer look at how to read this status for the first file.

           staged     unstaged path
  1:        +1/-0      nothing file1.txt

The number in front (1) is just an identifier that you can use to reference this item in the staging area if you update it further using this interface.

The numbers under staged represent the number of lines added since you started staging this file and the number deleted. In this instance, file1.txt only contained one line, so you see one line added and zero lines deleted.

Under unstaged you see nothing, which, of course, indicates that nothing is unstaged. Think of this as what’s different between the staging area and the working directory or what’s new in the working directory for this file. Because you don’t have any changes in the file in the working directory that aren’t staged, the version in the working directory and the version in the staging area are the same, so nothing is different. If there were differences, they would be in the same +/- format as used for the staged column.

Finally you have the path name, which, in this case, is just the filename.

Now, suppose you add a line in your working directory to file1.txt so that it has two lines instead of one. (This would be done outside of the interactive interface.) If you want to see what’s different between the version you have staged and the updated one, you can use the diff command here.

What now> d
           staged     unstaged path
  1:        +1/-0        +1/-0 file1.txt
  2:        +1/-0      nothing file3.txt
Review diff>> 

You get a summary status. Notice that the unstaged section now shows +1/-0 because the staged and unstaged versions in the directory are different. The way to read this is that in the unstaged version of the file, one new line has been added (which I did previously) and no lines deleted.

Your prompt has also changed to be relative to the command you selected and to allow you to choose which file you want to diff further (if you do). If you want to look at the actual diff for the file you changed, you can input 1 and get output like the following:

Review diff>> 1
diff --git a/file1.txt b/file1.txt
new file mode 100644
index 0000000..257cc56
--- /dev/null
+++ b/file1.txt
@@ -0,0 +1 @@
+newline
*** Commands ***
  1: status       2: update       3: revert       4: add untracked
  5: patch        6: diff         7: quit         8: help
What now> 

This is the same type of patch format that I talked about earlier in the section, “Partial Staging.” Now, to get your updated content in the staging area, you can use the update command. The workflow will be as it was for the other commands.

  1. You will get the same kind of list of what is eligible to update.
  2. You can then select the number that corresponds to the item you want to update and you’ll get the “*” marker to indicate it was done.
  3. You can then just press Enter/Return to exit the update mode.

The sequence looks like this:

What now> 2
           staged     unstaged path
  1:        +1/-0        +1/-0 file1.txt
Update>> 1
           staged     unstaged path
* 1:        +1/-0        +1/-0 file1.txt
Update>>
updated one path

*** Commands ***
  1: status       2: update       3: revert       4: add untracked
  5: patch        6: diff         7: quit         8: help

If you now take a look at the status after this update, you’ll see the following:

What now> s
           staged     unstaged path
  1:         +2/-0      nothing file1.txt
  2:         +1/-0      nothing file3.txt

Note that you have two lines added for the file since you started staging it. Also, you are back to nothing unstaged because all of the changes made in the working directory have been added to the staging area.

Lastly, if you decide you want to unstage a set of changes, you can use the revert command to do so. The sequence is the same as for the others: select the command, select the file, and the operation is executed.

*** Commands ***
  1: status       2: update       3: revert       4: add untracked
  5: patch        6: diff         7: quit         8: help
What now> 3
           staged     unstaged path
  1:         +2/-0      nothing file1.txt
  2:         +1/-0      nothing file3.txt
Revert>> 1
           staged     unstaged path
* 1:         +2/-0      nothing file1.txt
  2:         +1/-0      nothing file3.txt
Revert>>
rm 'file1.txt'
reverted one path

A status command now shows only the one file remaining in the staging area.

*** Commands ***
  1: status       2: update       3: revert       4: add untracked
  5: patch        6: diff         7: quit         8: help
What now> s
           staged     unstaged path
  1:        +1/-0      nothing file3.txt

For the remaining commands, patch will launch a similar workflow that allows for partial staging (as described in the section, “Partial Staging”). Also, as the name implies, help provides a quick summary of what the main commands do.

Once you quit the interactive staging process, Git provides a brief status summary.

What now> q
Bye.
[master 6a43d7e] update file3.txt
 1 file changed, 3 insertions(+)
 

Bypassing the Staging Area

In Chapter 3, I discussed the various uses and reasons for the staging area as a separate level in the Git promotion model. However, if you don’t need to have your changes staged as a separate step in the process, there is a shortcut that Git provides—although it is qualified.

The shortcut is to use the -am option on the command line when doing a commit, as in git commit -am “comment”.

I’ll talk more about the commit operation shortly, but the -am option effectively tells Git to stage and commit the updated content in one operation. It’s a nice convenience when you don’t need to hold the change in the staging area for any reason.

The one caveat with the -am shortcut is that it will not work for new content or files. The first time a file is added to Git, it must have the git add command done first.

Some IDEs will also provide a shortcut for doing the add and commit for files in their projects—for example, being able to drag and drop content to add and commit in one step.

Finalizing Changes—Commit

After content is staged, the next step is the commit into the local repository. This is done with the commit command. The syntax is shown below.

git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]
          [--dry-run] [(-c | -C | --fixup | --squash) <commit>]
          [-F <file> | -m <msg>] [--reset-author] [--allow-empty]
          [--allow-empty-message] [--no-verify] [-e] [--author=<author>]
          [--date=<date>] [--cleanup=<mode>] [--[no-]status]
          [-i | -o] [-S[<keyid>]] [--] [<file>…]

The dark arrow in Figure 5.7 reminds you where you are in the overall promotion model.

A schematic diagram of overall promotion model with a dark arrow for where commit fits in.

Figure 5.7 Where commit fits in

You can think of the commit action here as committing to make the change permanent. Committing always operates by promoting content from the staging area. (Even if you use the shortcut noted in the previous section on the commit command, you are not bypassing the staging area; you’re just moving content from the working directory to the staging area and then committing it with one command.)

A key point to remember is that a commit commits changes into the local repository only. Nothing gets updated or changed in the remote repository. As I noted earlier, and as indicated in the promotion model figures, there are entirely separate commands for synchronizing content with the remote repository (discussed in Chapter 13). So, none of the changes the user commits will show up in the remote repository until those other commands are used to push them over. They are two different and distinct environments.

Prerequisites

In addition to having content in the staging area, it’s best to have the username and user e-mail configured as discussed in Chapter 4. As a reminder, the commands to configure these settings on the command line are git config --global user.name "Your Name" and git config --global user.email <your email address>.

If you don’t do this, then Git will attempt to figure out who you are based on the logged-in userid and the system name. If it can’t, you’ll be forced to set these values then. If you don’t explicitly set them, then you may see a message like the following one after your first commit:

 [master sha1] comment
 Committer: username <username@hostname>
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.

You can suppress this message by setting them explicitly with the commands I reminded you about above. After doing this, you may fix the identity used for this commit as described in the section Resetting the Author Information later in this chapter.

Commit Scope

The most common form of the commit command is git commit -m "<commit message>".

Here, the -m is the abbreviated form of the --message option. Git requires a message (also referred to as a comment) when doing a commit. If the commit message has spaces, it must be enclosed in quotes.

In this form, without any specific set of files or content specified, Git takes everything in the staging area and commits it. Most of the time this is what you want. (Again, the general idea is to build up a set of content in the staging area that should be committed as a unit.) However, it is also possible to commit only a selected set of content, as in git commit -m "<commit message>" file1.c or git commit -m "<commit message>" *.c.

Putting It All Together

Figure 5.8 provides a visual way to think about the add and commit workflow. This is not exactly how things happen internally, but it is a convenient way to think about the overall process.

A schematic diagram of basic workflow for multiple commits.

Figure 5.8 The basic workflow for multiple commits

In part A, you start out with your local stack: local repository, staging area, and working directory. The working directory contains three files.

In part B, you specifically stage (add) one of the files, moving it into the staging area, and creating a snapshot.

In part C, you stage the remaining files by using the git add command, updating your snapshot. Recall that this form of the command (with the “.”) means to traverse the directory tree, and stage all of the files that are new or changed AND not ignored (via the .gitignore file). In this case, the other two files in the working directory match these criteria, so they are staged.

Next, you commit the set of files in the staging area to create a first commit in the local repository. This is illustrated in part D. Also here, the second file is modified again in the working directory.

Now, in part E, you stage the newly modified file, creating a new snapshot, and then commit it in part F. This creates a second commit. Git is smart enough as it manages storage to not create duplicate copies of everything from the first commit, but instead link to it.

Amending Commits

One of the advantages and challenges I noted with Git in Chapter 1 was the ability to rewrite ­history. The simplest form of rewriting history in Git is amending the last commit. This means you are updating the last commit with content from the staging area, rather than creating a new commit with the changes.

This is done using the --amend option with the next commit command. The basic syntax looks like this: git commit --amend <arguments>.

Staging the Updated Content for the Amend

The amend option tells Git to update the last commit in the local repository with whatever content is currently in the staging area. If no updated content is in the staging area, then only the commit message is updated (if the user chooses to supply a new one).

Figure 5.9 shows an example of this workflow.

Image described by caption and surrounding text.

Figure 5.9 Workflow for an amended commit

In part A, you are starting at the point where you have one commit in the local repository and a change (in File 2) in the working directory. In part B, you are staging this change with the git add command. In part C, you commit the change, but pass the --amend option.

Instead of creating a new commit, you can think of Git pulling back the last commit (part D), expanding it, overlaying it with what’s in the staging area (part E), and then updating the same commit back in the repository (part F).

Skipping the Edit of the Commit Message

While it is best practice to update the commit message when amending content, if there is a ­reason not to do so, you can use the --no-edit option on the amend, as in git commit --amend --no-edit.

Resetting the Author Information

The amend option can also come in handy if you forget to initially set the user.name or user.email configuration settings (or you have made a typo in one of them). To update the username and user e-mail captured in the previous commit, you reset the configuration settings to the desired values. You then add the --reset-author option to the commit command. After you run this command, the commit’s information should show the updated values.

$ git commit --amend –reset-author

Results of a Commit

Once a commit is executed, Git displays information like this on the command line interface:

$ git commit -m "add new files"

[master e3ff86b] add new files
 2 files changed, 2 insertions(+)
 create mode 100644 file1.java
 create mode 100644 file1.doc

I’ll break down this output so you understand what Git is telling you.

On the first line, master refers to the default branch in Git. Until you create other branches and switch to them, you’ll always be using master as your branch.

The e3ff86b is the first seven characters of the SHA1 value that was computed for the overall commit object—the snapshot I’ve referenced in previous chapters. This section is immediately followed by the commit message associated with this change.

The next line gives you information about how many files were affected by this commit, and how many changes there were in terms of insertions and deletions versus what was in the local repository before this commit.

Next, you have a list of the files that were involved in this commit along with mode information. The create text here is an indication that these are new files. The 100644 mode indicates a standard file in the repository. This is the most common mode you’ll see, but other types exist for executable files, symbolic links, and so on.

Two of these pieces of information are worth discussing in more detail: the SHA1 for the commit and the commit message.

Commit SHA1s

I discussed what a SHA1 is in Chapter 4. As a reminder, SHA1 is an acronym for Secure Hashing Algorithm 1. It is a checksum or hash that Git computes for every object it stores in its internal ­content management system. It is also the key that Git uses internally to map to stored content.

Whenever a commit is done in Git, Git computes a SHA1 for each piece of the snapshot that it stores (each file, directory, and so on). However, it also computes a SHA1 for the overall commit. That commit SHA1 is the one that users see and work with. It serves as a handle or key to be able to reference that particular commit in the system. For any Git command that needs to point to a particular commit, it does that with the SHA1 value for that commit.

In terms of use, you can think of this as being similar to a version or revision number in other tracking systems—a system-generated value that identifies a particular version of a change stored in the repository.

Commit Messages

When you commit into the local repository, Git requires you to supply a commit message. If you are working on the command line, you can supply one via the -m or --message argument. If you don’t supply a commit message, Git will start up the default editor for your particular system for you to type in the message. Once you type in the commit message, you save the file and close the editor. The commit operation then completes.

When creating a commit message, it is important that it is meaningful—not just to the user doing the commit, but also to others who may be looking at it later. In general, a commit message should do the following:

  • Explain the reason for the change at a high level (for example, refactoring xyz class, adding new foo api, fixing bug 1234, and so on). Users can use Git to see what was changed, but they need information to understand why it was changed.
  • Have a meaningful first line. It is typical in many Git interfaces to display only the first lines of commit messages when looking at changes that have gone into the repository. For this reason, the first line should provide a brief, meaningful summary.
  • Incorporate a tracking ticket identifier in the first line if issues are being tracked via a ticketing system. Doing this provides another reference to a place to go to get more details for users scanning the first lines of commit messages.
  • Follow any standards or guidelines that the team or company may have for commit messages.

Chris Beams (http://chris.beams.io/posts/git-commit/) puts it this way:

  • Separate the subject from the body with a blank line.
  • Limit the subject line to 50 characters.
  • Capitalize the subject line.
  • Do not end the subject line with a period.
  • Use the imperative mood in the subject line (for example, fix bug 1234 rather than fixed bug 1234). This matches the tense used in automatic commit messages that Git generates itself for certain operations.
  • Wrap the body at 72 characters.
  • Use the body to explain what and why versus how.

Like well-formed comments in code, well-formed commit messages can help to ensure that you and others will find it easier to understand and maintain your changes over time. In fact, some in the Git community advocate for never using the -m option on a commit. The idea is that the -m option only suggests a short message format with less information, as opposed to always using an editor to enter the message so that more information about the commit (such as that outlined here) can be included.

Advanced Topics

In this section, you’ll look at how to use templates for commit messages, as well as how to use Git’s Autocorrect and Auto Execute options.

One way to help standardize commit messages and ensure good form is by using commit message templates. A commit message template is simply a text file with text and comments that suggest the type and form of content to include in the commit message. Here’s an example:

$ cat ~/.gitmessage
Replace this line with a one-line meaningful summary


Why this change is needed:
# Explain why this change is needed


What this change accomplishes:
# Explain what this change does:

# This is our company's default commit message template.
# You should follow the following guidelines:
# Guideline 1
# Guideline 2
# Guideline 3

This is only one example, and obviously more could be done to make it more self-explanatory (and add real guidelines). However, this should spark some ideas. Once the template file is created, it can be saved to a global area (under the user’s home directory in this example) or even to a more publicly accessible location for use among multiple users.

There are three ways for a user to tell Git to include a commit message template at the time of doing a commit:

  1. Use the -t (--template) option on the commit command itself.
    $ git commit -t <template file location>
  2. Configure the default location of the template file globally.
    $ git config --global commit.template <template file> location>
  3. Use a special hook in Git that will run at commit time. (See the section on commit hooks in Chapter 15.)

By default, information in the commit message (including from the template file) that starts with a “#” character is considered a comment and is stripped out of the commit message when the commit is actually done (as are leading and trailing whitespace and any extra blank lines).

Using the Verbose Option

Git commit includes a --verbose option. This option is designed to insert diff command output from levels in the local environment as additional information for the user while the commit message is being edited. The information is not saved as part of the final commit message; it is only inserted for the user’s benefit while the commit message is being edited.

The first time this option is used on the command line, it results in the diff output between the staging area and the local repository being included. If the option is specified a second time on the same invocation, then the diff output between the working directory and staging area is also included.

The Full Commit Message Experience

Figure 5.10 shows what an editor session for the commit message looks like if you use the commit message template file described earlier and also two instances of the --verbose option. Note the parts added from your template file, added from Git, and introduced because of the --verbose options.

A screenshot of editor session for a commit message using a template fi le and the --verbose --verbose options.

Figure 5.10 The editor session for a commit message using a template file and the --verbose --verbose options

After the commit is done, the summary line appears in the commit output. If you look at the most recent commit message in the log, you’ll see all of the text you entered. Note that the content added by Git and the comment lines that I included in the template have been stripped out.

$ git commit -t ~/.gitmessage --verbose --verbose
[master bc1466b] This is an example change summary line.
 1 file changed, 1 insertion(+), 1 deletion(-)

$ git log -1
commit bc1466b01125c99bb5e15f3c2242c90b923fde62
Author: User Name <email address>
Date:   Sun Apr 10 20:51:26 2016 -0400

    This is an example change summary line.

    Why this change is needed:
    The purpose of this change is to demo the commit message template file.

    What this change accomplishes:
    Updates commit message template file with example text.

Autocorrect and Auto Execute

From time to time, everyone misspells a command. Normally, Git just stops and gives you its best guess about what you meant. For example, notice what happens when you leave the i out of commit:

$ git commt file2.txt
git: 'commt' is not a git command. See 'git --help'.

Did you mean this?
        Commit

That's helpful, but what if you want to simply trust Git and have it execute the command that it thinks you intended? You can tell it to do this by changing the configuration setting help.autocorrect to a desired value. The value you set actually specifies an amount of time that Git waits before proceeding to execute its best guess of what you intended. The trick here is that whatever value you provide specifies a number of seconds multiplied by 0.1. So, a value of 50 means that Git waits 5 seconds to give the user a chance to cancel out before executing.

$ git config help.autocorrect 50

$ git commt file2.txt
WARNING: You called a Git command named 'commt', which does not exist.
Continuing under the assumption that you meant 'commit'
in 5.0 seconds automatically…

Summary

In this chapter, you started to learn what you need to get productive using Git. I covered getting help and reinforced the multiple repositories model. From there, I dove into some details on staging changes, and described some items related to commits, including SHA1s and commit messages so you could tie the entire workflow together.

I also explained how to amend commits and how to use some advanced techniques such as commit message template files to improve commit messages.

In the next chapter, you’ll take a closer look at tracking changes as they move through the Git ­workflow—including how to tell what content is at each level and how to see differences between the levels. Prior to reading Chapter 6, I recommend that you complete Connected Lab 2.

About Connected Lab 2: Creating and Exploring a Git Repository and Managing Content

Connected Lab 2 is your next step to reinforce the concepts covered here. It is important to work through this lab to get the hands-on experience you’ll need to better understand the key concepts that will help you through the rest of this book.

The lab also includes a set of optional steps that provide more detail about the repository structure and how it evolves as content is managed in Git. This is not necessary to understand Git, but it can help you better understand how Git works.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset