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