{"thread":{"id":"17719","subject":"[RFC] post-commit hook to \"fix\" patches","startedAt":"2009-02-11T09:48:31Z","lastAt":"2009-02-11T09:56:23Z","messageCount":2,"participants":["Stefan Karpinski"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"104160","messageId":"d4bc1a2a0902110148u4e13d77cs3dde64d27003e58c@mail.gmail.com","threadId":"17719","inReplyTo":null,"subject":"[RFC] post-commit hook to \"fix\" patches","fromName":"Stefan Karpinski","fromEmail":"stefan.karpinski@gmail.com","sentAt":"2009-02-11T09:48:31Z","receivedAt":"2009-02-11T09:48:31Z","isPatch":false,"sender":{"key":"stefan.karpinski@gmail.com","avatar":"https://gravatar.com/avatar/780cfb8dd7d7dc749d7276a4ca2ec24e7f0482cfce509717c5ddd165fd2cc9d9?d=mp&s=160"},"body":"I just wrote the following post-commit hook that I thought others\nmight find interesting or useful. It's a non-intrusive, efficient and\nIMO elegant solution to the problem that I was trying to solve here:\n\n  http://thread.gmane.org/gmane.comp.version-control.git/98228\n\nThe post-commit hook calls a named \"git-fix-patch\", presumed to be in\nthe path somewhere, which munges a git diff to enforce whatever\nstylistic rules a project might have (typically whitespace)---but only\nin added lines. The hook creates a new commit with the same effect as\nthe HEAD commit, but without the added style errors.\n\nThat part's easy. What's much more interesting is making sure that the\nworkspace is left essentially the way it was, but reflecting the\nchanges wrought by the \"enforcer.\" This involves generating reverse\npatches, fixing them up, and then applying the fixed up patch in\nreverse. I had to think about this for a long time (and draw a bunch\nof commutative diagrams) to grok that this was what needed to be done,\nbut it seems to work quite nicely and generally.\n\nHere's the post-commit hook:\n\n== >8 ==\n#!/bin/sh\n\nif test -z \"$GIT_POST_COMMIT_HOOK_RUNNING\"\nthen\n  export GIT_POST_COMMIT_HOOK_RUNNING=true\n  x=$(git rev-parse HEAD)\n  git reset -q $x^\n  git diff -U0 $x^ $x | git-fix-patch | \\\n    git apply --unidiff-zero --cached\n  if git diff --cached --quiet $x\n  then\n    git reset -q $x\n  else\n    echo \"Automatically amending style errors...\"\n    git commit -q -C $x\n    if git diff -R -U0 $x | git-fix-patch | \\\n      git apply -R --unidiff-zero --cached --check 2>/dev/null\n    then\n      git diff -R -U0 $x | git-fix-patch | \\\n        git apply -R --unidiff-zero --cached 2>/dev/null\n      git checkout-index -a -f\n      git reset -q\n    else\n      echo \"WARNING: Failed patching uncommitted changes.\"\n    fi\n  fi\n  unset GIT_POST_COMMIT_HOOK_RUNNING\nfi\n== >8 ==\n\nI also wrote a sample git-fix-patch script that enforces the following\ncoding styles:\n  1. no trailing whitespace\n  2. all leading indentation with tabs (assumed to have width $t, below)\n  3. indentation only with spaces after the initial indentation\n\n== >8 ==\n#!/usr/bin/env perl\n\n$t=4;\n\nwhile (<>) {\n  if (m{^\\+}) {\n    s{\\s*$}{\\n};\n    while (s{\\t}{\" \"x($t-((length($`)-1)%$t))}e) {0}\n    s{^\\+((?: {$t})+)}{\"+\".\"\\t\"x(length($1)/$t)}e;\n  }\n  print;\n}\n== >8 ==\n\nI'd be really interested in reactions or thoughts about this. Maybe it\ncan even go into the collection of contrib scripts.\n\nStefan\n"},{"id":"104163","messageId":"d4bc1a2a0902110156nff21282q5fe0a6b7b656a0e6@mail.gmail.com","threadId":"17719","inReplyTo":"d4bc1a2a0902110148u4e13d77cs3dde64d27003e58c@mail.gmail.com","subject":"Re: [RFC] post-commit hook to \"fix\" patches","fromName":"Stefan Karpinski","fromEmail":"stefan.karpinski@gmail.com","sentAt":"2009-02-11T09:56:23Z","receivedAt":"2009-02-11T09:56:23Z","isPatch":false,"sender":{"key":"stefan.karpinski@gmail.com","avatar":"https://gravatar.com/avatar/780cfb8dd7d7dc749d7276a4ca2ec24e7f0482cfce509717c5ddd165fd2cc9d9?d=mp&s=160"},"body":"I'm CC'ing a couple people who replied to the thread I referenced\nearlier, in case they're interested and would otherwise miss this\nmessage.\n\nEspecially Marc Weber, who expressed interest in having a good\nsolution to this problem. Does this address what you wanted? I like it\nbecause it allows you to transparently and automatically enforce style\npolicy and:\n\n  - it doesn't require modifying git,\n  - it's efficient (no overhead except on commit),\n  - it doesn't pretend to be a clean/smudge filter (as people pointed\nout this isn't reversible),\n  - it's portable: everything's written in sh and perl.\n"}]}