Skip to content
Eric Bouchut edited this page Nov 30, 2022 · 61 revisions

Commit

In this section

  • <commit-ish> denotes any revision that refers to a commit. To learn more, read this.

How to write a git commit message

Retrieve the short version of SHA1

The short version of a SHA1 is composed of its first 7 characters. In order to transform a long SHA1 into a short one, we can use cut like so:

# Long SHA1
git rev-parse master
242d362cf1b5ccce4be5e23e10f1fa3474cdf828

# Short SHA1
git rev-parse --short master
242d362

# Short SHA1
git rev-parse master | cut -c 1-7
242d362

This example displays the long and short version of the SHA1 of the local masterbranch.

View the diff of changes while editing the commit message

git commit -v

The option -v of git commit launches the editor with the usual list of modified files plus the difference (git diff) below, so that you can take a look at the changes while writing the commit message. Do not worry the diff is not part of the commit message when you save the file.

Cherry-Pick a commit and replay it on the current branch

git cherry-pick  1234567

Add the commit with the SHA-1 1234567 to the tip of the current branch. The new commit has the same commit message and modification but a different SHA-1, date.

Cherry-Pick multiple consecutive commits

Assuming we want to pick the commits a, b, c (ordered by date) to rebase them on the current branch.

git log -3 c   # ordered by reverse chronological order (most recent first) 
  c
  b
  a

Here is how to do this.

git cherry-pick  a^..c

Add the commits from SHA-1 a up to and including c to the tip of the current branch. Commit a must be older than c.

FYI, a..c denotes the commits b and c, that is from a (not included) up to and including c. This is why I append a caret after a to make sure it is included in the range.

Generate a patch for a commit

  • Generate a patch file for a commit (say the commit with the SHA-1 1234567 for instance).
git format-patch -1  1234567 --stdout  > file.patch
  • Apply the patch
# Show patch stats
  git apply --stat file.patch

# Check for error before applying 
  git apply --check file.patch 

# Apply the patch
  git am < file.patch

Change the author e-mail of the most recent commit

This may be useful when the very last commit does not contain the correct (user name or) user email because you made a commit with the wrong user name and/or email. This can be changed provided you did not pushed the commit a remote repository.

Say for instance, I have on my computer both personal and corporate repositories. I need to use a distinct e-mail address for each kind:

I configured user.email and/or user.email globally with my personal name and email address like so.

git config --global user.name "Eric Bouchut"
git config --global user.email eric@perso.example.org

Then I clone a corporate repository, commit a change. I notice immediately after while running git log that I forgot to set my corporate e-mail address (eric@corp.example.com) for this project.

git log -1

commit 3c7abd382b653fc58f3ca890f220cb4de9adb65a
Author: Eric Bouchut <eric@perso.example.org>
Date:   Fri Mar 4 14:45:18 2016 +0100                                                                  │
Change settings

The last commit (git log -1) contains my personal email address eric.perso.example.org instead of the corporate one eric@corp.example.com!

Assuming I did not pushed this commit to any remote repository, here how to fix this. First, when in the repository I set my corporate e-mail address for this corporate repository.

# cd into the repository beforehand
#
# git config user.name "Eric Bouchut"
git config user.email eric@corp.example.com  

I then fix the author name and email of the very last commit, like so

git commit --amend --reset-author --no-edit

The option --amend asks git to change the most recent commit, --no-edit left the commit message unchanged and --reset-author replaces the author user name and e-mail address with the one in the local git configuration, that is Eric Bouchut <eric@corp.example.com>. The above command basically does the same thing as:

git commit --amend --no-edit --author "Eric Bouchut <eric@corp.example.com>" 

This is now fixed, as I can see the email address changed.

git log -1

commit 77f5b4bd0f7813379dd9a2f6d8d2658a55e9cadc
Author: Eric Bouchut <eric@corp.example.com>
Date:   Fri Mar 4 14:49:01 2016 +0100                                                                  │
Change settings

Cancel the current commit while editing the commit message in vim

Say you are in the middle of editing the commit message in vim, and you want to cancel the commit. Typing :q!<CR> will not prevent the commit from being made. You have two options:

  • Make sure the commit message is empty and save it using :wq<CR>
  • or type :cquit!<CR>

The latter does:

  • not save the file
  • exit with an error code

Git will then figure out vim failed and cancel the commit.

git commit
# You are now in vim typing your commit message 
# and figure out you would like to prevent the commit from being made
# Type this:

:cquit!<CR>

How to refer to a commit

See girevisions(7) and Revisions Selection in the Pro-Git book.

Convert a Ref-name into a SHA-1, back and forth

To get the SHA-1 that corresponds to a ref-name like master.

# Convert ref-name ==> SHA-1
# master ==> ?

git rev-parse master
43dc2f87931f720f348c9a6ab4c67aa825afac18

You can also use this to get the SHA-1 of a tag.

To get the list of ref-names that correspond to a SHA-1:

# Convert SHA-1 ==> ref-name(s)
# 43dc2f87931f720f348c9a6ab4c67aa825afac18 ==> ?

git name-rev --name-only 43dc2f87931f720f348c9a6ab4c67aa825afac18
master

git describe --all --contains 43dc2f87931f720f348c9a6ab4c67aa825afac18
master

Show the raw content of a commit

For the raw commit information associated with the git revision (SHA1, ref, branch name) passed as argument:

  • SHA1 of the commit
  • SHA1 of the tree
  • SHA1 of each parent
  • Author
  • Author Date
  • Committer
  • Committer Date
  • Commit Message
 git show --pretty=raw HEAD                                                                                                            

commit 7d35dc219fcbb98a293c3c7881e1dd80ab9151e1
tree 30695b87cce4814dcb04c61ecc502b3c2eb5feb8
parent caa1546c5266fba6deb9ce86b563623badefafcd
author Eric Bouchut <ebouchut@gmail.com> 1522153547 +0200
committer Eric Bouchut <ebouchut@gmail.com> 1522153551 +0200

    Git: Add git alias "untrack"

    This removes a file from the git index.
    The side effect is that the file will be removed from the repository
    on the next commit

diff --git a/tag-git/gitconfig b/tag-git/gitconfig
index d521135..9b4f290 100644
--- a/tag-git/gitconfig
+++ b/tag-git/gitconfig
@@ -33,6 +33,7 @@
        tags = !git tag -l | sort -V
        stashpp = ![[ -z $(git status --porcelain -uno) ]] && git pull || git stash && git pull && git stash pop
        aliases = !git config --get-regexp 'alias.*' | colrm 1 6 | sed 's/[ ]/ = /'
+       untrack = rm --cache --
 [apply]
        whitespace = nowarn
 [core]

Another option using the plumbing command cat-file.

 git cat-file -p HEAD                                                                                                                 

tree 30695b87cce4814dcb04c61ecc502b3c2eb5feb8
parent caa1546c5266fba6deb9ce86b563623badefafcd
author Eric Bouchut <ebouchut@gmail.com> 1522153547 +0200
committer Eric Bouchut <ebouchut@gmail.com> 1522153551 +0200

Git: Add git alias "untrack"

This removes a file from the git index.
The side effect is that the file will be removed from the repository
on the next commit

Show the content of a file at a given commit

Say you want to see what the file foo/bar/joe looks like at the commit 1234560.

git show 1234560:foo/bar/joe

If you omit the SHA-1 commit, HEAD is used instead. HEAD denotes the tip of the current branch, say master if you are on that branch.

git show :foo/bar/joe

# Same as
#   git show HEAD:foo/bar/joe

Show the content of the file README.md as present in the tag v1.9.3.

git show v1.9.3:CHANGELOG.md

Show the content of the file README.md as present in the branch origin/release/1.9.4.

git show origin/release/1.9.4:README.md

Retrieve the content of a file at a given commit

Say you want to get the file foo/bar/joe at the commit 1234560.

git checkout 1234560 -- foo/bar/joe

This will overwrite the working copy of the file foo/bar/joe with what it looked like at commit 1234560.

List all the files available at a given commit

git ls-tree --name-only -r <commit-ish>

git ls-tree --name-only -r HEAD

README.md
LICENSE

In the above example, the commit referenced by HEAD contains 2 files README.mdand LICENSE

List the files modified in a commit

git diff-tree --no-commit-id --name-only -r  <commit-ish>

There is at least two ways to get this:

git diff-tree --no-commit-id --name-only -r  HEAD

  README.md
git log --name-only -1 HEAD

  commit 36718c78caf9247c7dfb81a3844fa2c781bdee17                                                     
  Author: Eric Bouchut <eric@example.com>
  Date:   Mon Jan 26 22:19:49 2015 -0500

    Updated README

  README.md

Here the only file modified in the commit referenced by HEAD is README.md.

Search for the most recent commit whose message matches a regex

git show :/regex -- For instance here is how to search for the most recent commit whose message starts with Vim.

git show :/^Vim -- 

Search for commits where a string has been added/removed

git log -Sstring

Log commits where the string (factories in the below example) has been added or removed from a file.

git log -Sfactories

Revert to a given commit

I want to restore the working tree to the state it was in at commit 1234560 because what I have done after this commit is either buggy or does not work. I however do not want to rewrite the history by removing commits (1661fc2 and 59e2e45) because I already have pushed them upstream. git revert will undo the modifications up to but not including commit 1234560.

git log --oneline --decorate
  1661fc2 (HEAD, master) New layout engine
  59e2e45 Tweak settings panel
  1234560 Finalize UI
  ...
  3e06842 First commit
  • Ensure you working tree is clean by either ignoring, stashing or committing the files that are not yet in the repository.
  • Revert to the commit 1234560
git revert -n 1234560..HEAD

This modifies the working tree to cancel the changes done after commit 1234560 and up to the tip of the current branch (1661fc2 and 59e2e45). The -n flag asks git revert not to commit the changes which gives us the opportunity to review them.

  • Commit the changes to the repository
git commit -m "Revert to 1234560"

List the branches containing a commit

The below command search for the commit with SHA-1 123456 in all the branches and list their names:

git branch --all --contains 123456
 
* search_query
  remotes/origin/search_query

The branches search_query and origin/search_query contain the commit with the SHA-1 123456.

Remove a file from the git history

Say you comited a big file or a private file (including passwords...) a while ago. You now want to remove it from the repository so that it no longer exists.

http://stackoverflow.com/a/15729420/386517

Create an empty commit

git commit  -m "Description" --allow-empty

Making the very first commit an empty one may prove to be helpful should you need to amend/rebase the second commit. Without an empty commit you simply cannot do it. I often use this trick when creating the git repository of a Rails app where the message of the first/empty commit holds a short description of what the App is about.

Find the SHA1 of the Tree of a Commit

Replace HEAD with the SHA1 of a commit for which you want to know the SHA1 of the tree.

git rev-parse HEAD^{tree}
Clone this wiki locally