As stated in the question, the branch name can be extracted from .git/HEAD
and given [branch name]
, the commit ID can be found in .git/refs/heads/[branch name]
.
The package catchfile
provides the command \CatchFileDef
, which allows us to read .git/HEAD
into a macro. As HEAD
has no file extension, MiKTeX users have to add a trailing dot to the file name:
\CatchFileDef{\headfull}{.git/HEAD.}{}
This assigns something like ref: refs/heads/master
to \headfull
. As this string has a trailing whitespace character, we use \StrGobbleRight
from the xstring package to trim it:1
\StrGobbleRight{\headfull}{1}[\head]
In order to extract only the branch name (master
in the example) from this string, we can use \StrBehind
:
\StrBehind[2]{\head}{/}[\branch]
This saves the branch name in \branch
. Finally, we can use \CatchFileDef
again, to save the commit ID in \commit
:
\CatchFileDef{\commit}{.git/refs/heads/\branch.}{}
There are some edge cases where .git/refs/heads/\branch.
does not exist: After running git pack-refs
(which is a side effect of git gc --aggressive
, for example), the heads are packed into the file .git/packed-refs
instead of individual branchname
files. As a workaround, check if the file exists before trying to read it:
\IfFileExists{.git/refs/heads/\branch.}{%
\CatchFileDef{\commit}{.git/refs/heads/\branch.}{}}{%
\newcommand{\commit}{\dots~(in \emph{packed-refs})}}
As a fallback, this creates the (not-so-useful) output "... (in packed-refs)" instead of a commit ID – but this only lasts until the next commit, when the file heads/branchname
is recreated for the affected branch.
(A more ambitious workaround could parse packed-refs
, of course.)
Full MWE:
\documentclass{article}
\usepackage{xstring}
\usepackage{catchfile}
\CatchFileDef{\headfull}{.git/HEAD.}{}
\StrGobbleRight{\headfull}{1}[\head]
\StrBehind[2]{\head}{/}[\branch]
\IfFileExists{.git/refs/heads/\branch.}{%
\CatchFileDef{\commit}{.git/refs/heads/\branch.}{}}{%
\newcommand{\commit}{\dots~(in \emph{packed-refs})}}
\begin{document}
This revision: \texttt{\commit} on branch \texttt{\branch}.
\end{document}
Sample output:
This revision: d92dc1386e48e04ceecb85461ed3b232146e6a32
on branch
master
.
1 Using the last optional argument of \StrGobbleRight
(name
) to assign the trimmed string to a macro (\head
) is necessary to allow further manipulation of the string using the xstring
functions – see here for a discussion.