Documentation / howto / using-topic-branches.txton commit Merge branch 'fk/usage' (b0d3e9b)
   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.9f
  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 by 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 \
  46 master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6.git work
  47
  48Change directory into the cloned tree you just created
  49
  50 $ cd work
  51
  52Set up a remotes file so that you can fetch the latest from Linus' master
  53branch into a local branch named "linus":
  54
  55 $ cat > .git/remotes/linus
  56 URL: master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
  57 Pull: master:linus
  58 ^D
  59
  60and create the linus branch:
  61
  62 $ git branch linus
  63
  64The "linus" branch will be used to track the upstream kernel.  To update it,
  65you simply run:
  66
  67 $ git fetch linus
  68
  69you can do this frequently (and it should be safe to do so with pending
  70work in your tree, but perhaps not if you are in mid-merge).
  71
  72If you need to keep track of other public trees, you can add remote branches
  73for them too:
  74
  75 $ git branch another
  76 $ cat > .git/remotes/another
  77 URL: ... insert URL here ...
  78 Pull: name-of-branch-in-this-remote-tree:another
  79 ^D
  80
  81and run:
  82
  83 $ git fetch another
  84
  85Now create the branches in which you are going to work, these start
  86out at the current tip of the linus branch.
  87
  88 $ git branch test linus
  89 $ git branch release linus
  90
  91These can be easily kept up to date by merging from the "linus" branch:
  92
  93 $ git checkout test && git merge "Auto-update from upstream" test linus
  94 $ git checkout release && git merge "Auto-update from upstream" release linus
  95
  96Set up so that you can push upstream to your public tree (you need to
  97log-in to the remote system and create an empty tree there before the
  98first push).
  99
 100 $ cat > .git/remotes/mytree
 101 URL: master.kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
 102 Push: release
 103 Push: test
 104 ^D
 105
 106and the push both the test and release trees using:
 107
 108 $ git push mytree
 109
 110or push just one of the test and release branches using:
 111
 112 $ git push mytree test
 113or
 114 $ git push mytree release
 115
 116Now to apply some patches from the community.  Think of a short
 117snappy name for a branch to hold this patch (or related group of
 118patches), and create a new branch from the current tip of the
 119linus branch:
 120
 121 $ git checkout -b speed-up-spinlocks linus
 122
 123Now you apply the patch(es), run some tests, and commit the change(s).  If
 124the patch is a multi-part series, then you should apply each as a separate
 125commit to this branch.
 126
 127 $ ... patch ... test  ... commit [ ... patch ... test ... commit ]*
 128
 129When you are happy with the state of this change, you can pull it into the
 130"test" branch in preparation to make it public:
 131
 132 $ git checkout test && git merge "Pull speed-up-spinlock changes" test speed-up-spinlocks
 133
 134It is unlikely that you would have any conflicts here ... but you might if you
 135spent a while on this step and had also pulled new versions from upstream.
 136
 137Some time later when enough time has passed and testing done, you can pull the
 138same branch into the "release" tree ready to go upstream.  This is where you
 139see the value of keeping each patch (or patch series) in its own branch.  It
 140means that the patches can be moved into the "release" tree in any order.
 141
 142 $ git checkout release && git merge "Pull speed-up-spinlock changes" release speed-up-spinlocks
 143
 144After a while, you will have a number of branches, and despite the
 145well chosen names you picked for each of them, you may forget what
 146they are for, or what status they are in.  To get a reminder of what
 147changes are in a specific branch, use:
 148
 149 $ git-whatchanged branchname ^linus | git-shortlog
 150
 151To see whether it has already been merged into the test or release branches
 152use:
 153
 154 $ git-rev-list branchname ^test
 155or
 156 $ git-rev-list branchname ^release
 157
 158[If this branch has not yet been merged you will see a set of SHA1 values
 159for the commits, if it has been merged, then there will be no output]
 160
 161Once a patch completes the great cycle (moving from test to release, then
 162pulled by Linus, and finally coming back into your local "linus" branch)
 163the branch for this change is no longer needed.  You detect this when the
 164output from:
 165
 166 $ git-rev-list branchname ^linus
 167
 168is empty.  At this point the branch can be deleted:
 169
 170 $ git branch -d branchname
 171
 172Some changes are so trivial that it is not necessary to create a separate
 173branch and then merge into each of the test and release branches.  For
 174these changes, just apply directly to the "release" branch, and then
 175merge that into the "test" branch.
 176
 177To create diffstat and shortlog summaries of changes to include in a "please
 178pull" request to Linus you can use:
 179
 180 $ git-whatchanged -p release ^linus | diffstat -p1
 181and
 182 $ git-whatchanged release ^linus | git-shortlog
 183
 184
 185Here are some of the scripts that I use to simplify all this even further.
 186
 187==== update script ====
 188# Update a branch in my GIT tree.  If the branch to be updated
 189# is "linus", then pull from kernel.org.  Otherwise merge local
 190# linus branch into test|release branch
 191
 192case "$1" in
 193test|release)
 194        git checkout $1 && git merge "Auto-update from upstream" $1 linus
 195        ;;
 196linus)
 197        before=$(cat .git/refs/heads/linus)
 198        git fetch linus
 199        after=$(cat .git/refs/heads/linus)
 200        if [ $before != $after ]
 201        then
 202                git-whatchanged $after ^$before | git-shortlog
 203        fi
 204        ;;
 205*)
 206        echo "Usage: $0 linus|test|release" 1>&2
 207        exit 1
 208        ;;
 209esac
 210
 211==== merge script ====
 212# Merge a branch into either the test or release branch
 213
 214pname=$0
 215
 216usage()
 217{
 218        echo "Usage: $pname branch test|release" 1>&2
 219        exit 1
 220}
 221
 222if [ ! -f .git/refs/heads/"$1" ]
 223then
 224        echo "Can't see branch <$1>" 1>&2
 225        usage
 226fi
 227
 228case "$2" in
 229test|release)
 230        if [ $(git-rev-list $1 ^$2 | wc -c) -eq 0 ]
 231        then
 232                echo $1 already merged into $2 1>&2
 233                exit 1
 234        fi
 235        git checkout $2 && git merge "Pull $1 into $2 branch" $2 $1
 236        ;;
 237*)
 238        usage
 239        ;;
 240esac
 241
 242==== status script ====
 243# report on status of my ia64 GIT tree
 244
 245gb=$(tput setab 2)
 246rb=$(tput setab 1)
 247restore=$(tput setab 9)
 248
 249if [ `git-rev-list release ^test | wc -c` -gt 0 ]
 250then
 251        echo $rb Warning: commits in release that are not in test $restore
 252        git-whatchanged release ^test
 253fi
 254
 255for branch in `ls .git/refs/heads`
 256do
 257        if [ $branch = linus -o $branch = test -o $branch = release ]
 258        then
 259                continue
 260        fi
 261
 262        echo -n $gb ======= $branch ====== $restore " "
 263        status=
 264        for ref in test release linus
 265        do
 266                if [ `git-rev-list $branch ^$ref | wc -c` -gt 0 ]
 267                then
 268                        status=$status${ref:0:1}
 269                fi
 270        done
 271        case $status in
 272        trl)
 273                echo $rb Need to pull into test $restore
 274                ;;
 275        rl)
 276                echo "In test"
 277                ;;
 278        l)
 279                echo "Waiting for linus"
 280                ;;
 281        "")
 282                echo $rb All done $restore
 283                ;;
 284        *)
 285                echo $rb "<$status>" $restore
 286                ;;
 287        esac
 288        git-whatchanged $branch ^linus | git-shortlog
 289done