Secret Lives of Patches

Tay Ray Chuan rctay89@gmail.com

2014 Mar 1

Source: http://www.dccomics.com/characters/justice-league

Context

  • source code tracked by Git
    though can apply to distributed version control

  • code contribution model: email-based patch model
    though can apply to Github pull requests as well

Patch Lifecycle

  • encounter bug/itch in open source project
  • hack away → patch
  • submit patch!
  • ...profit?

Source: http://www.alibaba.com/product-detail/Bed-of-Roses_800016222.html

Source: http://en.wikipedia.org/wiki/File:Rose_Prickles.jpg

Common approaches

git-rebase

$ git log -5
060056c fix bug (Tay Ray Chuan, Sat Feb 22 02:17:06 2014 +0800)
7e095ee clean up in prep for bugfix (Tay Ray Chuan, Sat Feb 22 01:09:2014 +0800)
...

$ git rebase -i master
# (in editor)
pick 7e095ee clean up in prep for bugfix
e 060056c fix bug # s/pick/e/

  • unable to annotate/describe changes
  • no history
  • (no, reflog doesn't count)

Sounds familiar?

A plan

guilt

quilt for git

quilt: grand daddy

quilt semantics in git

  • QUILT_PATCHES dir: .git/patches/<branch>
  • guilt new mypatch.diff: create a new patch
  • guilt refresh: regenerate patch from working tree changes
  • guilt push: apply patch as a commit

version control

$ guilt_dir() { p=$(git symbolic-ref --short HEAD); echo .git/patches/${p#guilt/}; }
$ alias ggit='git -C `guilt_dir`'
$ guilt refresh
$ ggit status
$ ggit commit -m 'check error code at delete() instead of init()' mypatch.diff
commit e9f6a3810217c5b76cc0d5630f2d0cb352db19f0
Author: Tay Ray Chuan <rctay89@gmail.com>
Date:   Wed Feb 26 03:03:49 2014 +0800

    PR_PORT: drop port arg

    It is dport exactly.

diff --git a/mypatch.diff b/mypatch.diff
index 67c64f7..7b90665 100644
--- a/mypatch.diff
+++ b/mypatch.diff
@@ -89,7 +89,7 @@ index 26fb5c5..031644a 100644

  /**
 diff --git a/main.cpp b/main.cpp
-index 34b0789..8051dbe 100644
+index 34b0789..9885472 100644
 --- a/main.cpp
 +++ b/main.cpp
 @@ -17,6 +17,8 @@
@@ -156,13 +156,13 @@ index 34b0789..8051dbe 100644
  }

 +#ifdef MULTIIN_DEBUG
-+#define PR_PORT(prefix,port_inst,port,suffix) \
++#define PR_PORT(prefix,port_inst,suffix) \
 +      (fprintf(stderr, "%s%d (%d) %d->%d%s", \
 +              (prefix), \
 +              (port_inst)->linked_node->node->id, \
 +              (port_inst)->linked_node->node->type, \
 +              (port_inst)->sport, \
-+              (port), \
++              (port_inst)->dport, \
 +              (suffix)))
 +#endif
 +

Review

  • does what we want
  • tad complicated

stgit

Stacked Git

--ff

  • based on quilt too
  • very rich porcelain

TopGit

quilt - not

  • no diffs on diffs
    (just hack on working tree and commit)
  • tg patch
  • magic files eg. .topmsg for patch message
    (patch text is available for tracking)
$ tg create t/cleanup
tg: Automatically marking dependency on master
tg: Creating t/cleanup base from master...
$ # hack on patch
$ git commit
$ tg create t/bugfix
tg: Automatically marking dependency on t/cleanup
tg: Creating t/bugfix base from t/cleanup...
$ # hack on patch
$ git commit

Review

I like!
I like!
  • works on commit in project; no inception-like diff-on-diff
  • some magic unlike plain files in guilt, but ok

Summary

track patches

...like how you track code

  • annotation
  • collaboration
    (others can pick up where you left off)

Rule of Thumb

start tracking after one patch revision

Future work

workflow for contributors; what about maintainers?