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?
git log
to retrieve recent commits, that will show full commit hash
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
.
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
.
git log
is porcelain and git rev-parse
is plumbing.
git checkout 33aa44; git log -n 1
gives me 33aa44
. What version of git are you using?
porcelain
in the git
man
pages for years, but had NO idea it was referring to a toilet! The porcelain is the toilet, and it's "closer to the user" (who figuratively sits on this toilet) than the plumbing, which is lower-level and farther from the user--ie: below the "porcelain"! Mind blown.
Another one, using git log:
git log -1 --format="%H"
It's very similar to the of @outofculture though a bit shorter.
HEAD
.
HEAD
points to this commit rather than a named branche know as detached head.
git --no-pager log -1 --format="%H"
To get the full SHA:
$ git rev-parse HEAD
cbf1b9a1be984a9f61b79a05f23b19f66d533537
To get the shortened version:
$ git rev-parse --short HEAD
cbf1b9a
git
commit
hashes are needed, such as one from the branch
you are currently working with and a master
branch
, you could also use git rev-parse FETCH_HEAD
if you need the hash for the master
commit
that you merge
d into your current branch
. e.g. if you have branch
es master
and feature/new-feature
for a given repo., while on feature/new-feature
you could use git fetch origin master && git merge FETCH_HEAD
and then git rev-parse --short FETCH_HEAD
if you needed the commit
hash from the master
you just merge
d in for any scripts you may have.
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.
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 a 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
master
, which is not necessarily true.
master
.
.git/HEAD
typically points to a ref, if you have a SHA1 in there, you are in detached head mode.
.git
subdirectory, which is not necessarily the case. See the --separate-git-dir
flag in the git init
man page.
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
git describe --long --dirty --abbrev=10 --tags
it will give me something like 7.2.0.Final-447-g65bf4ef2d4
which is 447 commits after the 7.2.0.Final tag and the first 10 digest of the global SHA-1 at the current HEAD are "65bf4ef2d4". This is very good for version strings. With --long it will always add the count (-0-) and the hash, even if the tag happens to match exactly.
git describe --always
will "show uniquely abbreviated commit object as fallback"
git describe --tags --first-parent --abbrev=11 --long --dirty --always
. The --always
option means it provides a result (hash) even if there are no tags. The --first-parent
means it doesn't get confused by merge commits and only follows items on the current branch. Note also that --dirty
will append -dirty
to the result if the current branch has uncommitted changes.
Use git rev-list --max-count=1 HEAD
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);
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
sh
. Half an hour of documentation comments later, and here's a Gist of it: gist.github.com/Fordi/29b8d6d1ef1662b306bfc2bd99151b07
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
--match "NOT A TAG"
. Tested in git 2.18.0 as well as 2.7.4. Is there any situation where this argument is needed?
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
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
git show
is what's known as a porcelain command (i.e. user-facing), and so should not be used in scripts because its output is subject to change. The answer above (git rev-parse --short HEAD
) should be used instead.
git help show
for porcelain
.
--porcelain
, which is why this is confusing. You can find the details in this great answer by VonC
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.
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.
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.
show-ref
seems to me to be the best option for scripting, since it's a plumbing command and thus guaranteed (or at least very likely) to remain stable in future releases: other answers use rev-parse
, show
, describe
, or log
, which are all porcelain commands. And in cases where speed is not of the essence, the note from the show-ref
manpage applies: ‘Use of this utility is encouraged in favor of directly accessing files under the .git directory.’
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
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.
Pretty print of main git repo, and sub-modules:
echo "Main GIT repo:"
echo $(git show -s --format=%H) '(main)'
echo "Sub-modules:"
git submodule status | awk '{print $1,$2}'
Example output:
3a032b0992d7786b00a8822bbcbf192326160cf9 (main)
7de695d58f427c0887b094271ba1ae77a439084f sub-module-1
58f427c0887b01ba1ae77a439084947de695d27f sub-module-2
d58f427c0887de6957b09439084f4271ba1ae77a sub-module-3
How I would do it in python (based on @kenorb's bash answer)
def get_git_sha():
# Which branch are we on?
branch = open(".git/HEAD", "r").read()
# Parse output "ref: refs/heads/my_branch" -> my_branch
branch = branch.strip().split("/")[-1]
# What's the latest commit in this branch?
return open(f".git/refs/heads/{branch}").read().strip()
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
Here is another way of doing it with :)
git log | grep -o '\w\{8,\}' | head -n 1
echo "printing last commit id# for current branch:";
git reflog
https://i.stack.imgur.com/B1t2F.jpg
Success story sharing
--verify
implies that:The parameter given must be usable as a single, valid object name. Otherwise barf and abort.
git rev-parse --short HEAD
returns the short version of the hash, just in case anyone was wondering.--short
, such as--short=12
, to get a specific number of digits from the hash.--short=N
is about minimal number of digits; git uses larger number of digits if shortened one would be undistinguishable from shortened other commit. Try e.g.git rev-parse --short=2 HEAD
orgit log --oneline --abbrev=2
.git rev-parse HEAD | GREP_COLORS='ms=34;1' grep $(git rev-parse --short=0 HEAD)