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