git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[RFC] post-commit hook to "fix" patches

From
Stefan Karpinski <stefan.karpinski@gmail.com>
Date
Feb 11, 2009, 09:48 UTC
Message-ID
<d4bc1a2a0902110148u4e13d77cs3dde64d27003e58c@mail.gmail.com>

I just wrote the following post-commit hook that I thought others might find interesting or useful. It's a non-intrusive, efficient and IMO elegant solution to the problem that I was trying to solve here:

  http://thread.gmane.org/gmane.comp.version-control.git/98228

The post-commit hook calls a named "git-fix-patch", presumed to be in the path somewhere, which munges a git diff to enforce whatever stylistic rules a project might have (typically whitespace)---but only in added lines. The hook creates a new commit with the same effect as the HEAD commit, but without the added style errors.

That part's easy. What's much more interesting is making sure that the workspace is left essentially the way it was, but reflecting the changes wrought by the "enforcer." This involves generating reverse patches, fixing them up, and then applying the fixed up patch in reverse. I had to think about this for a long time (and draw a bunch of commutative diagrams) to grok that this was what needed to be done, but it seems to work quite nicely and generally.

Here's the post-commit hook:

== >8 == #!/bin/sh

if test -z "$GIT_POST_COMMIT_HOOK_RUNNING"
then
  export GIT_POST_COMMIT_HOOK_RUNNING=true
  x=$(git rev-parse HEAD)
  git reset -q $x^
  git diff -U0 $x^ $x | git-fix-patch | \
    git apply --unidiff-zero --cached
  if git diff --cached --quiet $x
  then
    git reset -q $x
  else
    echo "Automatically amending style errors..."
    git commit -q -C $x
    if git diff -R -U0 $x | git-fix-patch | \
      git apply -R --unidiff-zero --cached --check 2>/dev/null
    then
      git diff -R -U0 $x | git-fix-patch | \
        git apply -R --unidiff-zero --cached 2>/dev/null
      git checkout-index -a -f
      git reset -q
    else
      echo "WARNING: Failed patching uncommitted changes."
    fi
  fi
  unset GIT_POST_COMMIT_HOOK_RUNNING
fi
== >8 ==
I also wrote a sample git-fix-patch script that enforces the following
coding styles:
  1. no trailing whitespace
  2. all leading indentation with tabs (assumed to have width $t, below)
  3. indentation only with spaces after the initial indentation

== >8 == #!/usr/bin/env perl

$t=4;
while (<>) {
  if (m{^\+}) {
    s{\s*$}{\n};
    while (s{\t}{" "x($t-((length($`)-1)%$t))}e) {0}
    s{^\+((?: {$t})+)}{"+"."\t"x(length($1)/$t)}e;
  }
  print;
}
== >8 ==

I'd be really interested in reactions or thoughts about this. Maybe it can even go into the collection of contrib scripts.

Stefan
Next: Stefan Karpinski
Message 1 of 2 in “[RFC] post-commit hook to "fix" patches”
  1. Stefan KarpinskiFeb 11, 2009
  2. Stefan KarpinskiFeb 11, 2009

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.