2179
votes

I would like to retain (for now) the ability to link Git changesets to workitems stored in TFS.

I already wrote a tool (using a hook from Git) in which I can inject workitem identifiers into the message of a Git changeset.

I would also like to store the hash of the Git commit in a custom TFS workitem field. This way I can examine a workitem in TFS and see what Git changesets are associated with the workitem.

How can I easily retrieve the hash from the current commit from Git?

20

20 Answers

3218
votes

To turn arbitrary extended object reference into SHA-1, use simply git-rev-parse, for example

git rev-parse HEAD

or

git rev-parse --verify HEAD

You can also retrieve the short version like this

git rev-parse --short HEAD

Sidenote: If you want to turn references (branches and tags) into SHA-1, there is git show-ref and git for-each-ref.

466
votes

If you only want the shortened commit hash:

git log --pretty=format:'%h' -n 1

Furthermore, using %H is another way to get the long commit hash, and simply -1 can be used in place of -n 1.

172
votes

Another one, using git log:

git log -1 --format="%H"

It's very similar to the of @outofculture though a bit shorter.

136
votes

To get the full SHA:

$ git rev-parse HEAD
cbf1b9a1be984a9f61b79a05f23b19f66d533537

To get the shortened version:

$ git rev-parse --short HEAD
cbf1b9a
77
votes

For completeness, since no-one has suggested it yet. .git/refs/heads/master is a file that contains only one line: the hash of the latest commit on master. So you could just read it from there.

Or, as as command:

cat .git/refs/heads/master

Update:

Note that git now supports storing some head refs in the pack-ref file instead of as a file in the /refs/heads/ folder. https://www.kernel.org/pub/software/scm/git/docs/git-pack-refs.html

57
votes

Commit hash

git show -s --format=%H

Abbreviated commit hash

git show -s --format=%h

The -s flag is same as --no-patch and stands for "Suppress diff output".

Click here for more git show examples.

55
votes

There's always git describe as well. By default it gives you --

john@eleanor:/dev/shm/mpd/ncmpc/pkg (master)$ git describe --always
release-0.19-11-g7a68a75
30
votes

Use git rev-list --max-count=1 HEAD

24
votes

If you need to store the hash in a variable during a script, you can use

last_commit=$(git rev-parse HEAD);

Or, if you only want the first 10 characters (like github.com does)

last_commit=$(git rev-parse --short=10 HEAD);
19
votes

If you want the super-hacky way to do it:

cat .git/`cat .git/HEAD | cut -d \  -f 2`

Basically, git stores the location of HEAD in .git/HEAD, in the form ref: {path from .git}. This command reads that out, slices off the "ref: ", and reads out whatever file it pointed to.

This, of course, will fail in detached-head mode, as HEAD won't be "ref:...", but the hash itself - but you know, I don't think you expect that much smarts in your bash one-liners. If you don't think semicolons are cheating, though...

HASH="ref: HEAD"; while [[ $HASH == ref\:* ]]; do HASH="$(cat ".git/$(echo $HASH | cut -d \  -f 2)")"; done; echo $HASH
16
votes

The most succinct way I know:

git show --pretty=%h 

If you want a specific number of digits of the hash you can add:

--abbrev=n
15
votes

Perhaps you want an alias so you don't have to remember all the nifty details. After doing one of the below steps, you will be able to simply type:

$ git lastcommit
49c03fc679ab11534e1b4b35687b1225c365c630

Following up on the accepted answer, here are two ways to set this up:

1) Teach git the explicit way by editing the global config (my original answer):

 # open the git config editor
 $ git config --global --edit
 # in the alias section, add
 ...
 [alias]
   lastcommit = rev-parse HEAD
 ...

2) Or if you like a shortcut to teach git a shortcut, as recently commented by Adrien:

$ git config --global alias.lastcommit "rev-parse HEAD"

From here on, use git lastcommit to show the last commit's hash.

15
votes

I needed something a little more different: display the full sha1 of the commit, but append an asterisk to the end if the working directory is not clean. Unless I wanted to use multiple commands, none of the options in the previous answers work.

Here is the one liner that does:
git describe --always --abbrev=0 --match "NOT A TAG" --dirty="*"
Result: f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe*

Explanation: describes (using annotated tags) the current commit, but only with tags containing "NOT A TAG". Since tags cannot have spaces, this never matches a tag and since we want to show a result --always, the command falls back displaying the full (--abbrev=0) sha1 of the commit and it appends an asterisk if the working directory is --dirty.

If you don't want to append the asterisk, this works like all the other commands in the previous answers:
git describe --always --abbrev=0 --match "NOT A TAG"
Result: f5366ccb21588c0d7a5f7d9fa1d3f85e9f9d1ffe

8
votes
git show-ref --head --hash head

If you're going for speed though, the approach mentioned by Deestan

cat .git/refs/heads/<branch-name>

is significantly faster than any other method listed here so far.

8
votes

Here is one-liner in Bash shell using direct read from git files:

(head=($(<.git/HEAD)); cat .git/${head[1]})

You need to run above command in your git root folder.

This method can be useful when you've repository files, but git command has been not installed.

If won't work, check in .git/refs/heads folder what kind of heads do you have present.

6
votes

in your home-dir in file ".gitconfig" add the following

[alias]
sha = rev-parse HEAD

then you will have an easier command to remember:

$ git sha
59fbfdbadb43ad0b6154c982c997041e9e53b600
5
votes

On git bash, simply run $ git log -1

you will see, these lines following your command.

commit d25c95d88a5e8b7e15ba6c925a1631a5357095db .. (info about your head)

d25c95d88a5e8b7e15ba6c925a1631a5357095db, is your SHA for last commit.
2
votes

git rev-parse HEAD does the trick.

If you need to store it to checkout back later than saving actual branch if any may be preferable:

cat .git/HEAD

Example output:

ref: refs/heads/master

Parse it:

cat .git/HEAD | sed "s/^.\+ \(.\+\)$/\1/g"`

If you have Windows then you may consider using wsl.exe:

wsl cat .git/HEAD | wsl sed "s/^.\+ \(.\+\)$/\1/g"

Output:

refs/heads/master

This value may be used to git checkout later but it becomes pointing to its SHA. To make it to point to the actual current branch by its name do:

wsl cat .git/HEAD | wsl sed "s/^.\+ \(.\+\)$/\1/g" | wsl sed "s/^refs\///g"  | wsl sed "s/^heads\///g"

Output:

master
0
votes

Here is another direct-access implementation:

head="$(cat ".git/HEAD")"
while [ "$head" != "${head#ref: }" ]; do
  head="$(cat ".git/${head#ref: }")"
done

This also works over http which is useful for local package archives (I know: for public web sites it's not recommended to make the .git directory accessable):

head="$(curl -s "$baseurl/.git/HEAD")"
while [ "$head" != "${head#ref: }" ]; do
  head="$(curl -s "$baseurl/.git/${head#ref: }")"
done
0
votes

Here is another way of doing it with :)

git log | grep -o '\w\{8,\}' | head -n 1