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