The Git commit command stores copies of the changes from your working directory in your Git repository. But it can also be used to amend existing commits and to revert commits, too.
A basic requirement of any version control system is to store different versions of files for you. In Git, the command that does this is
commit. Here’s everything you need to know.
What Is a Commit in Git?
Commits are the series of snapshots made throughout the lifecycle of a project that make up its development history. Commits are what allow us to extract a version of the project as it was at different points in the past. Why is that important?
Version control systems (VCSs) are most commonly used with software source code and development projects. But they can be used successfully with any collection of text files, such as Markdown files containing chapters of a book.
You might not want every file in your project directories to be handled by the VCS, so you need to be able to nominate the files you want to be version controlled. This adds them to the version control view of the project. They’ll be monitored for changes.
Another way to achieve this is to use an ignore list. This tells Git which files, directories, or types of files it should always ignore.
Over time, as new files are added to the project, some will require being added to the version control system. In Git, this is handled by the
add command. Actually, the
add command does double service, as we’ll see.
In order to maintain a history of the changes that have been made to the project, you’ll periodically ask Git to store a snapshot of the state of the project, using the
commit command. This is where the
add command reappears in our workflow. We use the
add command to tell Git which changed files we want to have included in the snapshot. Then we use
commit to tell Git to create the snapshot.
Configuring the commit Command
Information about the commit is stored with it, so that it’s always possible to know who made the commit, when, and what the commit contains. Some of this metadata is captured at commit-time, such as the commit message.
Metadata relating to the identity of the members of the development team can be configured by each user, to prevent repeatedly providing the same information.
To set your name globally for all repositories on your computer, use this command.
git config --global user.name "Dave McKay"
To verify your name has been set, use this command.
git config --global user.name
If you need to use a different name on a particular repository, change into the project’s directory and use the same command without the
git config user.name "McKay, David"
git config user.name
We’ve now got a different default user name for this repository, and our global name is still used for other repositories.
In a similar fashion, we can set an email address either globally or for a single repository by including or omitting the
git config user.email "[email protected]"
git config --global user.email "[email protected]"
git config user.email
git config --global user.email
These settings are held in config files. Global Git settings are held in “~/.gitconfig”, and repository-specific settings are held in the repository’s “.git/config” file.
commit command references and uses these values as it operates.
Using the commit Command
The basic use of the
commit command is to take the files that are in the staging area, known as the index, and store them as a commit in the current branch of the repository.
A Basic Commit
We’ve got a project with a changed file. We’ll use the
add command to stage the file, then commit it. We’re using the
-m (commit message) option so that we can provide a short description of the purpose of the changes. If we don’t use this option, we’re prompted for a commit message as the commit takes place. It’s more convenient to add one on the command line.
git add jibber.c
git commit -m "Updated help text"
If we use the
git log command we can review the details of the commits, in chronological order, with the most recent commit at the top of the list.
The commits are displayed in
The commit has been tagged with the name and email address we provided earlier, and our commit message is recorded too.
Staging many files can take a little time. A different approach is to use the
-A (all) option with
This automatically stages all modified files along with all currently untracked files. The staging of untracked files respects the settings in your “.gitignore” file. Git won’t stage files you’ve told it you don’t want to be included. Finally, files in the index that are no longer in the working directory are removed from the index.
-A option can cause a lot to happen all at once. The
--dry-run option gives you a preview of the changes without actually performing them.
git add -A --dry-run
In our example, it’ll stage two modified existing files, and two new files. Let’s go ahead and use the
-A option before we use the
git add -A
git commit -m "Enhanced parsing"
We can see that altogether four files are changed. Two of them are the newly created files, which are listed.
Staging and Committing at the Same Time
commit command has a lowercase
-a (all) option. This performs the staging and the committing of files in one step.
commit -a option stages and commits modified existing files, and removes files from the index if they have been removed from your working directory. It doesn’t automatically stage untracked files.
add command, the commit command has a
--dry-run option that allows you to preview its actions before executing it.
git commit -a --dry-run
Now let’s carry out the command.
git commit -a --dry-run
The files are staged and committed for us.
Committing to a Different Branch
If you’ve made some changes to files in your work directory then realize you didn’t checkout the correct branch, you need to get your changes committed to the correct branch without affecting the current branch.
Git doesn’t have a command for committing to a different branch. But you can rectify this situation with a little bit of Git dexterity.
We’ll use the Git
stash command to make a copy of the changes. Then we’ll check out the correct branch and apply the changes from the stash. To apply the stashed changes we’re using the
pop command rather than the
apply command. The
pop command applies the changes and also removes them from the stash.
We’ve made some changes in our repository’s
new-parser branch. They should have been made in the
git checkout classic-parser
git stash pop
We can now perform a
commit, and update this branch.
git commit -a -m "Added pre-parser functions"
If we return to the
new-parser branch we can see that it is up to date, meaning the changes have been removed from your working directory, and your repository and files are in sync.
git checkout new-parser
RELATED: How To Update and Maintain Separate Git Branches
Making Changes to Commits
If you need to improve your commit message—perhaps you’ve spotted a typo in it—or you forgot to stage a file that should have been included in the commit, you can use the
--amend option to put things right. The caveat is, this shouldn’t be used on commits that have been pushed to a remote repository.
In our last commit message, “fraze” should have been “phrase.” If we use
git log we can see this.
To correct this, we’ll use the
--amend option like this.
git commit --amend -m "Optimized phrase identification"
If we use
git log once more, we can see the old commit has been replaced by a new one with the corrected commit message.
If we want to add a file that we forgot to stage, we can commit that file so that it appears as part of the previous commit.
add to stage the file, then make a commit with the
--amend option. The
--no-edit option means we don’t need to provide a new commit message. The previous commit message is retained.
git add jibber.c
git commit --amend --no-edit
Removing Changes From a Commit
If you’ve inadvertently staged and committed a file that you didn’t intend to, you can remove that file from the commit using the
reset command. We’ll reset the commit back to the staging area, or index. Then we’ll remove the file, and re-commit the rest of the files.
To reset the last commit to the staging area, we use the
reset --soft command.
HEAD~ is shorthand for “the commit behind the HEAD of the project commit timeline”, or in English, “the last commit.”
git reset --soft HEAD~
To remove the file that shouldn’t have been included, we use the
reset --mixed command. This resets those changes back into the working directory, recreating the modified file as an unstaged, uncommitted file.
git reset --mixed jibber.c
We need to commit the other files that are left in the index.
git commit -m "Experimental tweaks"
The other two files that were in the original commit are re-committed for us.
RELATED: How to Fix, Edit, or Undo Git Commits (Changing Git History)
Reverting an Entire Commit
Sometimes undoing an entire commit is the easiest thing to do. It puts your working directory and repository back to the state they were in before you committed.
We need to use the commit’s hashed reference ID. We can find this using
Copy that reference and use it in the
git revert e5bd4560aef8164c6ca9d6d4620b9db7f66aecc8
This will open your default editor so you can edit a revert message. There is a default message entered for you. You can either use this, or edit it to your liking.
When you’re happy with your revert message, save the file and exit the editor. In nano, you do this with “Ctrl+O”, and “Ctrl+X.”
git log once more, we can see that a new commit has been added that undoes the changes of the reverted commit.
The Git Swiss Army Knife
commit is one of the most important Git commands. It can do a lot, so there’s a lot to learn. Getting to grips with its lesser-used features is time well spent. When you need to correct a mistake—right now—you’ll be glad you’ve prepared in advance.
RELATED: How to Use Git merge