1 Date: Mon, 15 Aug 2005 12:17:41 -0700
2 From: tony.luck@intel.com
3 Subject: Some tutorial text (was git/cogito workshop/bof at linuxconf au?)
5 Here's something that I've been putting together on how I'm using
6 GIT as a Linux subsystem maintainer.
10 Last updated w.r.t. GIT 0.99.5
12 Linux subsystem maintenance using GIT
13 -------------------------------------
15 My requirements here are to be able to create two public trees:
17 1) A "test" tree into which patches are initially placed so that they
18 can get some exposure when integrated with other ongoing development.
19 This tree is available to Andrew for pulling into -mm whenever he wants.
21 2) A "release" tree into which tested patches are moved for final
22 sanity checking, and as a vehicle to send them upstream to Linus
23 (by sending him a "please pull" request.)
25 Note that the period of time that each patch spends in the "test" tree
26 is dependent on the complexity of the change. Since GIT does not support
27 cherry picking, it is not practical to simply apply all patches to the
28 test tree and then pull to the release tree as that would leave trivial
29 patches blocked in the test tree waiting for complex changes to accumulate
30 enough test time to graduate.
32 Back in the BitKeeper days I achieved this my creating small forests of
33 temporary trees, one tree for each logical grouping of patches, and then
34 pulling changes from these trees first to the test tree, and then to the
35 release tree. At first I replicated this in GIT, but then I realised
36 that I could so this far more efficiently using branches inside a single
39 So here is the step-by-step guide how this all works for me.
41 First create your work tree by cloning Linus's public tree:
43 $ git clone rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git work
45 Change directory into the cloned tree you just created
49 Set up a remotes file so that you can fetch the latest from Linus' master
50 branch into a local branch named "linus":
52 $ cat > .git/remotes/linus
53 URL: rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
57 and create the linus branch:
61 The "linus" branch will be used to track the upstream kernel. To update it,
66 you can do this frequently (and it should be safe to do so with pending
67 work in your tree, but perhaps not if you are in mid-merge).
69 If you need to keep track of other public trees, you can add remote branches
73 $ cat > .git/remotes/another
74 URL: ... insert URL here ...
75 Pull: name-of-branch-in-this-remote-tree:another
82 Now create the branches in which you are going to work, these start
83 out at the current tip of the linus branch.
85 $ git branch test linus
86 $ git branch release linus
88 These can be easily kept up to date by merging from the "linus" branch:
90 $ git checkout test && git resolve test linus "Auto-update from upstream"
91 $ git checkout release && git resolve release linus "Auto-update from upstream"
93 Set up so that you can push upstream to your public tree (you need to
94 log-in to the remote system and create an empty tree there before the
97 $ cat > .git/remotes/mytree
98 URL: master.kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
103 and the push both the test and release trees using:
107 or push just one of the test and release branches using:
109 $ git push mytree test
111 $ git push mytree release
113 Now to apply some patches from the community. Think of a short
114 snappy name for a branch to hold this patch (or related group of
115 patches), and create a new branch from the current tip of the
118 $ git checkout -b speed-up-spinlocks linus
120 Now you apply the patch(es), run some tests, and commit the change(s). If
121 the patch is a multi-part series, then you should apply each as a separate
122 commit to this branch.
124 $ ... patch ... test ... commit [ ... patch ... test ... commit ]*
126 When you are happy with the state of this change, you can pull it into the
127 "test" branch in preparation to make it public:
129 $ git checkout test && git resolve test speed-up-spinlocks "Pull speed-up-spinlock changes"
131 It is unlikely that you would have any conflicts here ... but you might if you
132 spent a while on this step and had also pulled new versions from upstream.
134 Some time later when enough time has passed and testing done, you can pull the
135 same branch into the "release" tree ready to go upstream. This is where you
136 see the value of keeping each patch (or patch series) in its own branch. It
137 means that the patches can be moved into the "release" tree in any order.
139 $ git checkout release && git resolve release speed-up-spinlocks "Pull speed-up-spinlock changes"
141 After a while, you will have a number of branches, and despite the
142 well chosen names you picked for each of them, you may forget what
143 they are for, or what status they are in. To get a reminder of what
144 changes are in a specific branch, use:
146 $ git-whatchanged branchname ^linus | git-shortlog
148 To see whether it has already been merged into the test or release branches
151 $ git-rev-list branchname ^test
153 $ git-rev-list branchname ^release
155 [If this branch has not yet been merged you will see a set of SHA1 values
156 for the commits, if it has been merged, then there will be no output]
158 Once a patch completes the great cycle (moving from test to release, then
159 pulled by Linus, and finally coming back into your local "linus" branch)
160 the branch for this change is no longer needed. You detect this when the
163 $ git-rev-list branchname ^linus
165 is empty. At this point the branch can be deleted:
167 $ rm .git/refs/heads/branchname
169 Some changes are so trivial that it is not necessary to create a separate
170 branch and then merge into each of the test and release branches. For
171 these changes, just apply directly to the "release" branch, and then
172 merge that into the "test" branch.
174 To create diffstat and shortlog summaries of changes to include in a "please
175 pull" request to Linus you can use:
177 $ git-whatchanged -p release ^linus | diffstat -p1
179 $ git-whatchanged release ^linus | git-shortlog
182 Here are some of the scripts that I use to simplify all this even further.
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
191 git checkout $1 && git resolve $1 linus "Auto-update from upstream"
194 before=$(cat .git/refs/heads/linus)
196 after=$(cat .git/refs/heads/linus)
197 if [ $before != $after ]
199 git-whatchanged $after ^$before | git-shortlog
203 echo "Usage: $0 linus|test|release" 1>&2
208 ==== merge script ====
209 # Merge a branch into either the test or release branch
215 echo "Usage: $pname branch test|release" 1>&2
219 if [ ! -f .git/refs/heads/"$1" ]
221 echo "Can't see branch <$1>" 1>&2
227 if [ $(git-rev-list $1 ^$2 | wc -c) -eq 0 ]
229 echo $1 already merged into $2 1>&2
232 git checkout $2 && git resolve $2 $1 "Pull $1 into $2 branch"
239 ==== status script ====
240 # report on status of my ia64 GIT tree
244 restore=$(tput setab 9)
246 if [ `git-rev-tree release ^test | wc -c` -gt 0 ]
248 echo $rb Warning: commits in release that are not in test $restore
249 git-whatchanged release ^test
252 for branch in `ls .git/refs/heads`
254 if [ $branch = linus -o $branch = test -o $branch = release ]
259 echo -n $gb ======= $branch ====== $restore " "
261 for ref in test release linus
263 if [ `git-rev-tree $branch ^$ref | wc -c` -gt 0 ]
265 status=$status${ref:0:1}
270 echo $rb Need to pull into test $restore
276 echo "Waiting for linus"
279 echo $rb All done $restore
282 echo $rb "<$status>" $restore
285 git-whatchanged $branch ^linus | git-shortlog