DEV Community

Bryce Wray
Bryce Wray

Posted on • Updated on • Originally published at

Get good Git info from Hugo

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. 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
Enter fullscreen mode Exit fullscreen mode

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, in production, you will need to deploy your site using a GitHub Action (or other CI/CD), 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.]

This is because (a.) hosts’ Git configurations for builds typically are set to so-called shallow-clone behavior; and, apparently, (b.) no host allows altering this in either its built-in UI or any optional config files (e.g., netlify.toml with Netlify or vercel.json with Vercel). Shallow-clone behavior causes problems with using .GitInfo data as described in this post, so keep this in mind if you typically deploy via your host’s built-in user interface rather than with CI/CD.

Note from the future: In testing for a later article, I found that, in fact, Netlify and DigitalOcean App Platform exhibit deep-clone behavior where Git is concerned, so you likely can use the information herein with their native UIs rather than having to deploy to them via CI/CD.

To make use of this answer in a GitHub Action, you could just add a with section to the GitHub Action’s Checkout default branch step:

      - name: Checkout default branch
        uses: actions/checkout@v3
          fetch-depth: 0
Enter fullscreen mode Exit fullscreen mode

. . . and, indeed, that fixes the glitch.

You might also want to test for whether a post’s day of original publication and its “last-modified” day are the same --- e.g., when you fix a typo or otherwise edit something while it’s still the same day as when you first issued the post --- and, if so, 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 here’s how you could accomplish this in an 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 -}}
Enter fullscreen mode Exit fullscreen mode

Within the paragraph, if the two are not equal (ne), this shows the “Last modified” statement; otherwise, it just inserts 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. The following example displays .AbbreviatedHash while the link is an exampleuser repo link plus /commit/ plus .Hash:

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

(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.)

And, yes, the previous advisory still applies: i.e., you have to deploy to your host via CI/CD in order to see the correct Git commit data for each post.


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. 

Top comments (2)

suchintan profile image

Nice information Bryce 🙂, if someone is not familiar with Git or Github they can refer to this blog as well.

Here's the link 👉 Git and Github Tutorial: Beginner to Advanced

brycewray profile image
Bryce Wray

Thanks, and good luck with that series!