All of lore.kernel.org
 help / color / mirror / Atom feed
From: Stefan Karpinski <stefan.karpinski@gmail.com>
To: git <git@vger.kernel.org>
Subject: [RFC] post-commit hook to "fix" patches
Date: Wed, 11 Feb 2009 01:48:31 -0800	[thread overview]
Message-ID: <d4bc1a2a0902110148u4e13d77cs3dde64d27003e58c@mail.gmail.com> (raw)

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

             reply	other threads:[~2009-02-11  9:50 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-02-11  9:48 Stefan Karpinski [this message]
2009-02-11  9:56 ` [RFC] post-commit hook to "fix" patches Stefan Karpinski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d4bc1a2a0902110148u4e13d77cs3dde64d27003e58c@mail.gmail.com \
    --to=stefan.karpinski@gmail.com \
    --cc=git@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.