TransWikia.com

How to include the current Git commit ID and branch in my document?

TeX - LaTeX Asked by CL. on April 1, 2021

I use Git to track changes on my TEX files. When producing a PDF, it would be nice to include the current branch and commit ID somewhere in the document (e.g. on the title page or in a footer).

I know that the package gitinfo2 exists but I’d rather avoid adding any hooks to Git. Besides, I am aware of this question but I would prefer a solution that does not require enabling write18.

Given that the name of the current branch can be found in .git/HEAD and the current commit ID is stored in .git/refs/heads/[name of branch], is it possible to embed this information in the final document?

4 Answers

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.

Correct answer by CL. on April 1, 2021

A no-package approach (tested on mac os, modify it for Windows regarding extra needed dot perhaps) based on @CL.'s answer.

documentclass{article}

newcommanddotGitHEAD{}
newcommandbranch{}
newcommandcommit{}


makeatletterletmyfilehandle@inputcheckmakeatother

openinmyfilehandle=.git/HEADrelax

begingroupendlinechar-1
  globalreadmyfilehandle to dotGitHEAD
endgroup
closeinmyfilehandle

newcommandGetBranch{}
defGetBranch ref: refs/heads/#1relax{renewcommand{branch}{#1}}

expandafterGetBranchdotGitHEADrelax

openinmyfilehandle=.git/refs/heads/branchrelax

begingroupendlinechar-1
  globalreadmyfilehandle to commit
endgroup
closeinmyfilehandle

begin{document}
branch+++

commit+++

This revision: texttt{commit} on branch texttt{branch}.
end{document}

enter image description here



Package getcommit:

ProvidesPackage{getcommit}[2018/10/16 get current commit and branch (JFB)]

@ifundefined{branch}{}
   {PackageWarning{getcommit}{ATTENTION!^^J
    @spaces@spacesstringbranchspace macro was already
    defined. Overwritten.}}
@ifundefined{commit}{}
   {PackageWarning{getcommit}{ATTENTION!^^J
    @spaces@spacesstringcommitspace macro was already
    defined. Overwritten.}}

openin@inputcheck=.git/HEADrelax

begingroupendlinechar-1
  globalread@inputcheck to getcommit@HEAD
endgroup
closein@inputcheck

defgetcommit@GetBranch ref: refs/heads/#1relax{defbranch{#1}}

expandaftergetcommit@GetBranchgetcommit@HEADrelax

openin@inputcheck=.git/refs/heads/branchrelax

begingroupendlinechar-1
  globalread@inputcheck to commit
endgroup
closein@inputcheck
endinput

Example of use:

documentclass{article}

usepackage{getcommit}

begin{document}
+++branch+++

+++commit+++

%frenchspacing
This revision: texttt{commit} on branch texttt{branch}.
end{document}

Answered by user4686 on April 1, 2021

We can use input instead read primitive:

defgitdir{.git/}
defreadgitcommitA #1 {defgitcommit{#1}}
defreadgitbranchA #1 #2 {defgitbranch{#2}}
defreadgitcommit{expandafterreadgitbranchA input gitdir HEAD
  expandafterreadgitcommitA input gitdirgitbranchrelax}

readgitcommit

Now, the commit ID is in "gitcommit" macro.

Answered by wipet on April 1, 2021

If you are using latexmk, you can use an alternative approach to intialize gitinfo2, that does not require git hooks (https://github.com/rbarazzutti/gitinfo2-latexmk).

Setup:

$ git submodule add https://github.com/rbarazzutti/gitinfo2-latexmk gitinfo2-latexmk
$ echo "do './gitinfo2-latexmk/gitinfo2.pm';" >> latexmkrc

Usage:

usepackage[mark]{gitinfo2}

Answered by canochordo on April 1, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP