[1] Skip to Main Content [2] Viget • [3] Work • [4] Services • [5] Articles • [6] Careers • [7] Contact • Open Menu Navigation [9] Viget Close • Practice • [11] Work • [12] Services • [13] Articles We’re a full-service digital agency that’s been helping clients make lasting change since 1999. [14] Contact Us People • [15]Company • [16]Careers • [17]Code of Ethics • [18]Diversity & Inclusion More • [19]Pointless Corp. • [20]Explorations • [21]Code at Viget Featured [22] Read the Article: Revolutionizing the Web Newsletter Revolutionizing the Web [23] Read the Article: Elephants, Squirrels, Porcupines, and Zombies Can Help Your Team Thrive Article Elephants, Squirrels, Porcupines, and Zombies Can Help Your Team Thrive Simple Commit Linting for Issue Number in GitHub Actions [Git-Tips-030718] [24] David Eisinger [25]David Eisinger, Development Director Article Categories: [26] #Code, [27] #Tooling Posted on April 28, 2023 • [28] Share • [29] Share • [30] Post Including relevant ticket numbers in your git commit messages is a gift to your future self. Here's how to ensure you do it consistently. I n c l u d i n g r e l e v a n t t i c k e t n u m b e r s i n y o u r g i t c o m m i t m e s s a g e s i s a g i f t t o y o u r f u t u r e s e l f . H e r e ' s h o w t o e n s u r e y o u d o i t c o n s i s t e n t l y . I don't believe there is a right way to do software; I think teams can be effective (or ineffective!) in a lot of different ways using all sorts of methodologies and technologies. But one hill upon which I will die is this: referencing tickets in commit messages pays enormous dividends over the long haul and you should always do it. As someone who regularly commits code to apps created in the Obama era, nothing warms my heart like running [31]:Git blame on some confusing code and seeing a reference to a GitHub Issue where I can get the necessary context. And, conversely, nothing sparks nerd rage like fix bug or PR feedback or, heaven forbid, oops. In a recent [32]project retrospective, the team identified that we weren't being as consistent with this as we'd like, and decided to take action. I figured some sort of commit linting would be a good candidate for [33] continuous integration — when a team member pushes a branch up to GitHub, check the commits and make sure they include a reference to a ticket. I looked into [34]commitlint, but I found it a lot more opinionated than I am — I really just want to make sure commits begin with either [#XXX] (an issue number) or [n/a] — and rather difficult to reconfigure. After struggling with it for a few hours, I decided to just DIY it with a simple inline script. If you just want something you can drop into a GitHub Actions YAML file to lint your commits, here it is (but stick around and I'll break it down and then show how to do it in a few other languages): steps: - name: Checkout code uses: actions/checkout@v3 with: fetch-depth: 0 - name: Set up ruby 3.2.1 uses: ruby/setup-ruby@v1 with: ruby-version: 3.2.1 - name: Lint commits run: | git log --format=format:%s HEAD ^origin/main | ruby -e ' $stdin.each_line do |msg| next if /^\[(#\d+|n\/a)\]/.match?(msg) warn %(Commits must begin with [#XXX] or [n/a] (#{msg.strip})) exit 1 end ' A few notes: • That fetch-depth: 0 is essential in order to be able to compare the branch being built with main (or whatever you call your primary development branch) — by default, your Action only knows about the current branch. • git log --format=format:%s HEAD ^origin/main is going to give you the first line of every commit that's in the source branch but not in main; those are the commits we want to lint. • With that list of commits, we loop through each message and compare it with the regular expression /^\[(#\d+|n\/a)\]/, i.e. does this message begin with either [#XXX] (where X are digits) or [n/a]? • If any message does not match, print an error out to standard error (that's warn) and exit with a non-zero status (so that the GitHub Action fails). If you want to try this out locally (or perhaps modify the script to validate messages in a different way), here's a docker run command you can use: echo '[#123] Message 1 [n/a] Message 2 [#122] Message 3' | docker run --rm -i ruby:3.2.1 ruby -e ' $stdin.each_line do |msg| next if /^\[(#\d+|n\/a)\]/.match?(msg) warn %(Commits must begin with [#XXX] or [n/a] (#{msg.strip})) exit 1 end ' Note that running this command should output nothing since these are all valid commit messages; modify one of the messages if you want to see the failure state. Other Languages [35]# Since there's a very real possibility you might not otherwise install Ruby in your GitHub Actions, and because I weirdly enjoy writing the same code in a bunch of different languages, here are scripts for several of Viget's other favorites: JavaScript [36]# git log --format=format:%s HEAD ^origin/main | node -e " let msgs = require('fs').readFileSync(0).toString().trim().split('\n'); for (let msg of msgs) { if (msg.match(/^\[(#\d+|n\/a)\]/)) { continue; } process.stderr.write('Commits must begin with [#XXX] or [n/a] (' + msg + ')'); process.exit(1); } " To test: echo '[#123] Message 1 [n/a] Message 2 [#122] Message 3' | docker run --rm -i node:18.15.0 node -e " let msgs = require('fs').readFileSync(0).toString().trim().split('\n'); for (let msg of msgs) { if (msg.match(/^\[(#\d+|n\/a)\]/)) { continue; } process.stderr.write('Commits must begin with [#XXX] or [n/a] (' + msg + ')'); process.exit(1); } " PHP [37]# git log --format=format:%s HEAD ^origin/main | php -r ' while ($msg = fgets(STDIN)) { if (preg_match("/^\[(#\d+|n\/a)\]/", $msg)) { continue; } fwrite(STDERR, "Commits must begin with #[XXX] or [n/a] (" . trim($msg) . ")\n"); exit(1); } ' To test: echo '[#123] Message 1 [n/a] Message 2 [#122] Message 3' | docker run --rm -i php:8.2.4 php -r ' while ($msg = fgets(STDIN)) { if (preg_match("/^\[(#\d+|n\/a)\]/", $msg)) { continue; } fwrite(STDERR, "Commits must begin with #[XXX] or [n/a] (" . trim($msg) . ")\n"); exit(1); } ' Python [38]# git log --format=format:%s HEAD ^origin/main | python -c ' import sys import re for msg in sys.stdin: if re.match(r"^\[(#\d+|n\/a)\]", msg): continue print("Commits must begin with #[xxx] or [n/a] (%s)" % msg.strip(), file=sys.stderr) sys.exit(1) ' To test: echo '[#123] Message 1 [n/a] Message 2 [#122] Message 3' | docker run --rm -i python:3.11.3 python -c ' import sys import re for msg in sys.stdin: if re.match(r"^\[(#\d+|n\/a)\]", msg): continue print("Commits must begin with #[xxx] or [n/a] (%s)" % msg.strip(), file=sys.stderr) sys.exit(1) ' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ So there you have it: simple GitHub Actions commit linting in most of Viget's favorite languages (try as I might, I could not figure out how to do this in [39]Elixir, at least not in a concise way). As I said up front, writing good tickets and then referencing them in commit messages so that they can easily be surfaced with git blame pays huge dividends over the life of a codebase. If you're not already in the habit of doing this, well, the best time to start was Initial commit, but the second best time is today. [40] David Eisinger [41]David is Viget's managing development director. From our Durham, NC, office, he builds high-quality, forward-thinking software for PUMA, the World Wildlife Fund, NFLPA, and many others. [42]More articles by David Related Articles • [43] Thoughts on Remix Article Thoughts on Remix Solomon Hawk • [44] Going Headless in 2024: A View of the Headless CMS Landscape Article Going Headless in 2024: A View of the Headless CMS Landscape Andrew Mosby • [45] Maintenance Matters: Good Tests Article Maintenance Matters: Good Tests David Eisinger The Viget Newsletter Nobody likes popups, so we waited until now to recommend our newsletter, featuring thoughts, opinions, and tools for building a better digital world. [46]Read the current issue. [47]Subscribe Here (opens in new window) Site Footer Have an unsolvable problem or audacious idea? Let’s get to work [48] Contact Us [49] hello@viget.com [50] 703.891.0670 • Practice • [51]Work • [52]Services • [53]Articles • People • [54]Company • [55]Careers • [56]Code of Ethics • [57]Diversity & Inclusion • More • [58]Pointless Corp. • [59]Explorations • [60]Code at Viget Sign Up For Our Newsletter A curated periodical featuring thoughts, opinions, and tools for building a better digital world. [61] Check it out Social Links [62] Viget • [63] • [64] • [65] • [66] • [67] • [68] Office Locations • [69]Washington DC Metro • [70]Durham, NC • [71]Boulder, CO • [72]Chattanooga, TN © 1999 – 2024 Viget Labs, LLC. [73]Terms [74]Privacy [75]MRF • [76]Home • [77]Articles • [78]Simple Commit Linting for Issue Number in GitHub Actions [79] Subscribe (opens in a new window) Share • [81] Share this page • [82] Share this page • [83] Post this page References: [1] https://www.viget.com/articles/simple-commit-linting-for-issue-number-in-github-actions/#content [2] https://www.viget.com/ [3] https://www.viget.com/work/ [4] https://www.viget.com/services/ [5] https://www.viget.com/articles/ [6] https://www.viget.com/careers/ [7] https://www.viget.com/contact/ [9] https://www.viget.com/ [11] https://www.viget.com/work/ [12] https://www.viget.com/services/ [13] https://www.viget.com/articles/ [14] https://www.viget.com/contact/ [15] https://www.viget.com/about/ [16] https://www.viget.com/careers/ [17] https://www.viget.com/code-of-ethics/ [18] https://www.viget.com/diversity-equity-and-inclusion/ [19] https://pointlesscorp.com/ [20] https://explorations.viget.com/ [21] https://code.viget.com/ [22] https://www.viget.com/newsletter/revolutionizing-the-web/ [23] https://www.viget.com/articles/elephants-squirrels-porcupines-and-zombies-can-help-your-team-thrive/ [24] https://www.viget.com/about/team/deisinger/ [25] https://www.viget.com/about/team/deisinger/ [26] https://www.viget.com/articles/category/code/ [27] https://www.viget.com/articles/category/tooling/ [28] https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fwww.viget.com%2Farticles%2Fsimple-commit-linting-for-issue-number-in-github-actions%2F [29] http://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fwww.viget.com%2Farticles%2Fsimple-commit-linting-for-issue-number-in-github-actions%2F [30] https://x.com/intent/tweet?text=Including%20relevant%20ticket%20numbers%20in%20your%20git%20commit%20messages%20is%20a%20gift%20to%20your%20future%20self.%20Here%27s%20how%20to%20ensure%20you%20do%20it%20consistently.%20https%3A%2F%2Fwww.viget.com%2Farticles%2Fsimple-commit-linting-for-issue-number-in-github-actions%2F [31] https://github.com/tpope/vim-fugitive#fugitivevim [32] https://www.viget.com/articles/get-the-most-out-of-your-internal-retrospectives/ [33] https://www.viget.com/articles/maintenance-matters-continuous-integration/ [34] https://commitlint.js.org/ [35] https://www.viget.com/articles/simple-commit-linting-for-issue-number-in-github-actions/#other-languages [36] https://www.viget.com/articles/simple-commit-linting-for-issue-number-in-github-actions/#javaScript [37] https://www.viget.com/articles/simple-commit-linting-for-issue-number-in-github-actions/#php [38] https://www.viget.com/articles/simple-commit-linting-for-issue-number-in-github-actions/#python [39] https://elixir-lang.org/ [40] https://www.viget.com/about/team/deisinger/ [41] https://www.viget.com/about/team/deisinger/ [42] https://www.viget.com/about/team/deisinger/ [43] https://www.viget.com/articles/thoughts-on-remix/ [44] https://www.viget.com/articles/a-view-of-the-headless-cms-landscape/ [45] https://www.viget.com/articles/maintenance-matters-good-tests/ [46] https://www.viget.com/newsletter [47] http://eepurl.com/gtHqsj [48] https://www.viget.com/contact/ [49] mailto:hello@viget.com?subject=Hello%2C%20Viget%21 [50] tel:7038910670 [51] https://www.viget.com/work/ [52] https://www.viget.com/services/ [53] https://www.viget.com/articles/ [54] https://www.viget.com/about/ [55] https://www.viget.com/careers/ [56] https://www.viget.com/code-of-ethics/ [57] https://www.viget.com/diversity-equity-and-inclusion/ [58] https://pointlesscorp.com/ [59] https://explorations.viget.com/ [60] https://code.viget.com/ [61] https://www.viget.com/newsletter/ [62] https://www.viget.com/ [63] http://x.com/viget [64] https://github.com/vigetlabs [65] https://dribbble.com/viget [66] https://www.instagram.com/viget/ [67] https://www.linkedin.com/company/viget-labs [68] https://vimeo.com/viget/collections [69] https://www.viget.com/dc-metro-hq/ [70] https://www.viget.com/durham/ [71] https://www.viget.com/boulder/ [72] https://www.viget.com/chattanooga/ [73] https://www.viget.com/terms-conditions/ [74] https://www.viget.com/privacy-policy/ [75] https://individual.carefirst.com/individuals-families/mandates-policies/machine-readable-file.page [76] https://www.viget.com/ [77] https://www.viget.com/articles [78] https://www.viget.com/articles/simple-commit-linting-for-issue-number-in-github-actions/#hero [79] http://eepurl.com/gtHqsj [81] https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fwww.viget.com%2Farticles%2Fsimple-commit-linting-for-issue-number-in-github-actions%2F [82] http://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fwww.viget.com%2Farticles%2Fsimple-commit-linting-for-issue-number-in-github-actions%2F [83] https://x.com/intent/tweet?text=Including%20relevant%20ticket%20numbers%20in%20your%20git%20commit%20messages%20is%20a%20gift%20to%20your%20future%20self.%20Here%27s%20how%20to%20ensure%20you%20do%20it%20consistently.%20https%3A%2F%2Fwww.viget.com%2Farticles%2Fsimple-commit-linting-for-issue-number-in-github-actions%2F