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