Using git-describe output for version pinning

The fact that tj-actions/changed-files was compromised is kind of old news at this point, but I had an insight the other day about this problem and its remediation that I haven't seen mentioned yet.

To recap - the issue is that many GitHub Actions users were doing something like uses: tj-actions/changed-files@$TAG, but the commit that $TAG actually points at can be changed (which isn't a behavior specific to GitHub Actions, for what it's worth). The solution is to do something like uses: tj-actions/changed-files@$COMMIT_SHA. This gets us the same commit every time, but now we have the problem of not being able to see at a glance which version $COMMIT_SHA refers to! One solution to that would be to add a simple comment:

uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46.0.5

...but the problem with this solution is nothing makes you keep that comment up-to-date when you change the commit SHA, so they can (and often do) end up diverging.

So I was thinking "oh man, wouldn't it be nice if a Git revision could specify the expected commit SHA, along with an annotation for the intended tag?"

...and then I remembered that's exactly what git describe gives us!

For those of you who aren't familiar, git describe outputs a "human-readable name based on an available ref" - it's often in the format $TAG-$NUM_COMMITS_PAST_TAG-g$COMMIT_SHA. So to use our earlier example, ed68ef82c095e0d48ec87eccea555d944a631a4c becomes v46.0.5-0-ged68ef82c095e0d48ec87eccea555d944a631a4c. And this format is understood by git rev-parse, so it's understood by all Git commands, as well as uses clauses in GitHub Actions.

To get this kind of revision for a given tag, you just need to use git describe --long --abbrev=40 $TAG - the --long is so git describe doesn't just give you the name of the tag, and the --abbrev=40 is to get the full commit SHA.

However, there is a small caveat: unfortunately, while the $COMMIT_SHA part does get verified (which is, in my opinion, the important part!), the $TAG and $NUM_COMMITS_PAST_TAG parts are ignored - so you could still have the problem where you just change the $COMMIT_SHA part and it no longer matches $TAG. But, since it's part of the actual workflow YAML rather than just a comment, it would be easier to write a linter for this, and whipping up a script to verify those parts would be trivial. GitHub themselves could even add this to Actions!

Published on 2025-04-12