Get good Git info from Hugo

It’s easy to fetch and display your Hugo repo’s Git data.


Latest commit: 3354e2e3, 2022-12-24
881 words • Reading time: 4 minutes

Note: This post also appears on

Update from the future: Although the data and formatting in each page’s header differ from what’s described in this post, the code blocks contained herein are still accurate and usable.

While reading blog posts from other static site generator (SSG) users, I sometimes see that a post includes a link to the specific Git commit for that post’s most recent update. As you may have noticed, I’ve incorporated that here, too. In this post, I’ll show you how to do it in a Hugo site, in case you’re interested in doing the same. As an additional benefit, it’ll automate something you might have been doing manually up to now.

I got the idea yesterday, when I saw a post from Aleksandr Hovhannisyan. In it, he gave a fine tutorial about displaying this data in pages built with the Eleventy SSG. Hovhannisyan’s method employed JavaScript to fetch the necessary Git data for use by his Eleventy templates.

On the other hand: with a Hugo site, things are much easier, thanks to the built-in availability of Git info variables. Once you set Hugo to fetch these variables, they’re available from within a .GitInfo object.

In your project config file, set enableGitInfo to true (here, I’m showing the Hugo default of TOML, although my own config file is actually YAML):

enableGitInfo = true

As the setting’s name implies, this activates the presence of the Git info variables.

I’ll get to the part about displaying commit info shortly but, first, let’s note that making this setting may have just liberated you from a nit-picking duty involved in how you display your posts’ dates. If you’ve been using manual entries in your posts’ front matter to indicate when they were last modified, you no longer have to do that. The Git info will, by default, provide this data as .Lastmod.1

However, there’s a catch if you’re using a GitHub Action to deploy your site to your chosen host, as I’ve been doing lately. The problem is that, although these automated .Lastmod indications will be correct when you’re developing locally with hugo server, they’ll all take on the current date when you deploy. Fortunately, there’s an explanation and solution, from a thread2 on the Hugo Discourse forum:

By default, the GitHub “checkout” action only fetches a single commit (for the ref/SHA that triggered the workflow). This results in the behavior you describe — i.e.[,] the current date/time is used for .Lastmod.

If you modify the checkout action to fetch the entire history (by specifying fetch-depth: 0), then .GitInfo and .Lastmod [work] as expected[.]

[Stylistic edits and one link applied.]

After finding this answer, I simply added a with section to my GitHub Action’s Checkout default branch step:

   - name: Checkout default branch
	   uses: actions/[email protected]
       fetch-depth: 0

. . . and, indeed, that fixed the glitch.

Incidentally: I test for whether a post’s day of original publication and its “last-modified” day are the same — e.g., when I fix a typo or otherwise edit something while it’s still the same day as when I first issued the post — and, if so, I show only the “original-pub” listing, to avoid duplication. However, this requires comparing the formatted dates, since full timestamps clearly can never be the same down to the nanosecond; so this is in each applicable template:

	<strong>{{ .PublishDate.Format "January 2, 2006" }}</strong><br />
	{{- if ne (.PublishDate.Format "January 2, 2006") (.Lastmod.Format "January 2, 2006") }}
		Last modified {{ .Lastmod.Format "January 2, 2006" }}
	{{- else -}}
	{{- end -}}

Within the paragraph, if the two are not equal (ne), I show the “Last modified” statement; otherwise, I just put in a non-breaking space so the height of the line will be the same.

That takes care of Git info for dates; but what about the original subject of this post, namely how you can link to a page’s most recent Git commit?

Well, the .GitInfo object also provides two variables for each commit’s hash: the full hash (.Hash) and the more familiar abbreviated hash (.AbbreviatedHash). Adding this within the proper templates is pretty matter-of-fact. In my case, I display .AbbreviatedHash while the link is my repo link plus /commit/ plus .Hash:

	{{- if $.GitInfo -}}
		<strong>Latest commit</strong>: <a href="{{ .GitInfo.Hash }}" rel="noopener">{{ .GitInfo.AbbreviatedHash }}</a>
	{{- else -}}
	{{- end -}}

(The if $.GitInfo conditional prevents hugo server errors during local development while you’re working on content you haven’t yet committed.3 You can thank another Hugo Discourse forum answer for that one.)

So, now, you’ve automated both (a.) displaying that Lastmod stuff and (b.) linking to the commit from which each page’s latest version originates. Yet, you needed no additional tools, and very little extra code, to do it. Not bad for a few minutes’ worth of work in Hugo, eh?

Update, 2022-10-07: If you’re interested in displaying both per-page Git info and whole-site Git info in your Hugo site, check the solution suggested by Hugo expert/contributor Joe Mooring. Thanks to Rodrigo Alcaraz de la Osa for the Q&A session that led me toward this additional information!

  1. By default, Hugo will give higher priority to the Git info variable .Lastmod vs. other possibilities — including any manual Lastmod entries you may have already provided in your content’s front matter. ↩︎

  2. The original question dates from December 25, 2019, but it took another 21 months before an answer, much less the answer, appeared. Jeeeez. ↩︎

  3. The reason you don’t have to do this with the dates-display mentioned earlier is because, in that case, we’re simply using Lastmod (a variable Hugo already knows) rather than, specifically, .GitInfo.Lastmod, the absence of which for a given page gives Hugo fits. ↩︎

Next: Static Mastodon toots in Hugo

Previous: Fun with feeds