Documentation / howto / using-topic-branches.txton commit [PATCH] fetch.c: Make process() look at each object only once (f9cff26)
   1Date: Mon, 15 Aug 2005 12:17:41 -0700
   2From: tony.luck@intel.com
   3Subject: Some tutorial text (was git/cogito workshop/bof at linuxconf au?)
   4Abstract: In this article, Tony Luck discusses how he uses GIT
   5 as a Linux subsystem maintainer.
   6
   7Here's something that I've been putting together on how I'm using
   8GIT as a Linux subsystem maintainer.
   9
  10-Tony
  11
  12Last updated w.r.t. GIT 0.99.5
  13
  14Linux subsystem maintenance using GIT
  15-------------------------------------
  16
  17My requirements here are to be able to create two public trees:
  18
  191) A "test" tree into which patches are initially placed so that they
  20can get some exposure when integrated with other ongoing development.
  21This tree is available to Andrew for pulling into -mm whenever he wants.
  22
  232) A "release" tree into which tested patches are moved for final
  24sanity checking, and as a vehicle to send them upstream to Linus
  25(by sending him a "please pull" request.)
  26
  27Note that the period of time that each patch spends in the "test" tree
  28is dependent on the complexity of the change.  Since GIT does not support
  29cherry picking, it is not practical to simply apply all patches to the
  30test tree and then pull to the release tree as that would leave trivial
  31patches blocked in the test tree waiting for complex changes to accumulate
  32enough test time to graduate.
  33
  34Back in the BitKeeper days I achieved this my creating small forests of
  35temporary trees, one tree for each logical grouping of patches, and then
  36pulling changes from these trees first to the test tree, and then to the
  37release tree.  At first I replicated this in GIT, but then I realised
  38that I could so this far more efficiently using branches inside a single
  39GIT repository.
  40
  41So here is the step-by-step guide how this all works for me.
  42
  43First create your work tree by cloning Linus's public tree:
  44
  45 $ git clone rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git work
  46
  47Change directory into the cloned tree you just created
  48
  49 $ cd work
  50
  51Set up a remotes file so that you can fetch the latest from Linus' master
  52branch into a local branch named "linus":
  53
  54 $ cat > .git/remotes/linus
  55 URL: rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
  56 Pull: master:linus
  57 ^D
  58
  59and create the linus branch:
  60
  61 $ git branch linus
  62
  63The "linus" branch will be used to track the upstream kernel.  To update it,
  64you simply run:
  65
  66 $ git fetch linus
  67
  68you can do this frequently (and it should be safe to do so with pending
  69work in your tree, but perhaps not if you are in mid-merge).
  70
  71If you need to keep track of other public trees, you can add remote branches
  72for them too:
  73
  74 $ git branch another
  75 $ cat > .git/remotes/another
  76 URL: ... insert URL here ...
  77 Pull: name-of-branch-in-this-remote-tree:another
  78 ^D
  79
  80and run:
  81
  82 $ git fetch another
  83
  84Now create the branches in which you are going to work, these start
  85out at the current tip of the linus branch.
  86
  87 $ git branch test linus
  88 $ git branch release linus
  89
  90These can be easily kept up to date by merging from the "linus" branch:
  91
  92 $ git checkout test && git resolve test linus "Auto-update from upstream"
  93 $ git checkout release && git resolve release linus "Auto-update from upstream"
  94
  95Set up so that you can push upstream to your public tree (you need to
  96log-in to the remote system and create an empty tree there before the
  97first push).
  98
  99 $ cat > .git/remotes/mytree
 100 URL: master.kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
 101 Push: release
 102 Push: test
 103 ^D
 104
 105and the push both the test and release trees using:
 106
 107 $ git push mytree
 108
 109or push just one of the test and release branches using:
 110
 111 $ git push mytree test
 112or
 113 $ git push mytree release
 114
 115Now to apply some patches from the community.  Think of a short
 116snappy name for a branch to hold this patch (or related group of
 117patches), and create a new branch from the current tip of the
 118linus branch:
 119
 120 $ git checkout -b speed-up-spinlocks linus
 121
 122Now you apply the patch(es), run some tests, and commit the change(s).  If
 123the patch is a multi-part series, then you should apply each as a separate
 124commit to this branch.
 125
 126 $ ... patch ... test  ... commit [ ... patch ... test ... commit ]*
 127
 128When you are happy with the state of this change, you can pull it into the
 129"test" branch in preparation to make it public:
 130
 131 $ git checkout test && git resolve test speed-up-spinlocks "Pull speed-up-spinlock changes"
 132
 133It is unlikely that you would have any conflicts here ... but you might if you
 134spent a while on this step and had also pulled new versions from upstream.
 135
 136Some time later when enough time has passed and testing done, you can pull the
 137same branch into the "release" tree ready to go upstream.  This is where you
 138see the value of keeping each patch (or patch series) in its own branch.  It
 139means that the patches can be moved into the "release" tree in any order.
 140
 141 $ git checkout release && git resolve release speed-up-spinlocks "Pull speed-up-spinlock changes"
 142
 143After a while, you will have a number of branches, and despite the
 144well chosen names you picked for each of them, you may forget what
 145they are for, or what status they are in.  To get a reminder of what
 146changes are in a specific branch, use:
 147
 148 $ git-whatchanged branchname ^linus | git-shortlog
 149
 150To see whether it has already been merged into the test or release branches
 151use:
 152
 153 $ git-rev-list branchname ^test
 154or
 155 $ git-rev-list branchname ^release
 156
 157[If this branch has not yet been merged you will see a set of SHA1 values
 158for the commits, if it has been merged, then there will be no output]
 159
 160Once a patch completes the great cycle (moving from test to release, then
 161pulled by Linus, and finally coming back into your local "linus" branch)
 162the branch for this change is no longer needed.  You detect this when the
 163output from:
 164
 165 $ git-rev-list branchname ^linus
 166
 167is empty.  At this point the branch can be deleted:
 168
 169 $ rm .git/refs/heads/branchname
 170
 171Some changes are so trivial that it is not necessary to create a separate
 172branch and then merge into each of the test and release branches.  For
 173these changes, just apply directly to the "release" branch, and then
 174merge that into the "test" branch.
 175
 176To create diffstat and shortlog summaries of changes to include in a "please
 177pull" request to Linus you can use:
 178
 179 $ git-whatchanged -p release ^linus | diffstat -p1
 180and
 181 $ git-whatchanged release ^linus | git-shortlog
 182
 183
 184Here are some of the scripts that I use to simplify all this even further.
 185
 186==== update script ====
 187# Update a branch in my GIT tree.  If the branch to be updated
 188# is "linus", then pull from kernel.org.  Otherwise merge local
 189# linus branch into test|release branch
 190
 191case "$1" in
 192test|release)
 193        git checkout $1 && git resolve $1 linus "Auto-update from upstream"
 194        ;;
 195linus)
 196        before=$(cat .git/refs/heads/linus)
 197        git fetch linus
 198        after=$(cat .git/refs/heads/linus)
 199        if [ $before != $after ]
 200        then
 201                git-whatchanged $after ^$before | git-shortlog
 202        fi
 203        ;;
 204*)
 205        echo "Usage: $0 linus|test|release" 1>&2
 206        exit 1
 207        ;;
 208esac
 209
 210==== merge script ====
 211# Merge a branch into either the test or release branch
 212
 213pname=$0
 214
 215usage()
 216{
 217        echo "Usage: $pname branch test|release" 1>&2
 218        exit 1
 219}
 220
 221if [ ! -f .git/refs/heads/"$1" ]
 222then
 223        echo "Can't see branch <$1>" 1>&2
 224        usage
 225fi
 226
 227case "$2" in
 228test|release)
 229        if [ $(git-rev-list $1 ^$2 | wc -c) -eq 0 ]
 230        then
 231                echo $1 already merged into $2 1>&2
 232                exit 1
 233        fi
 234        git checkout $2 && git resolve $2 $1 "Pull $1 into $2 branch"
 235        ;;
 236*)
 237        usage
 238        ;;
 239esac
 240
 241==== status script ====
 242# report on status of my ia64 GIT tree
 243
 244gb=$(tput setab 2)
 245rb=$(tput setab 1)
 246restore=$(tput setab 9)
 247
 248if [ `git-rev-tree release ^test | wc -c` -gt 0 ]
 249then
 250        echo $rb Warning: commits in release that are not in test $restore
 251        git-whatchanged release ^test
 252fi
 253
 254for branch in `ls .git/refs/heads`
 255do
 256        if [ $branch = linus -o $branch = test -o $branch = release ]
 257        then
 258                continue
 259        fi
 260
 261        echo -n $gb ======= $branch ====== $restore " "
 262        status=
 263        for ref in test release linus
 264        do
 265                if [ `git-rev-tree $branch ^$ref | wc -c` -gt 0 ]
 266                then
 267                        status=$status${ref:0:1}
 268                fi
 269        done
 270        case $status in
 271        trl)
 272                echo $rb Need to pull into test $restore
 273                ;;
 274        rl)
 275                echo "In test"
 276                ;;
 277        l)
 278                echo "Waiting for linus"
 279                ;;
 280        "")
 281                echo $rb All done $restore
 282                ;;
 283        *)
 284                echo $rb "<$status>" $restore
 285                ;;
 286        esac
 287        git-whatchanged $branch ^linus | git-shortlog
 288done