[PATCH] update howto/using-topic-branches.txt
[git.git] / Documentation / 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
5 Here's something that I've been putting together on how I'm using
6 GIT as a Linux subsystem maintainer.
7
8 -Tony
9
10 Last updated w.r.t. GIT 0.99.5
11
12 Linux subsystem maintenance using GIT
13 -------------------------------------
14
15 My requirements here are to be able to create two public trees:
16
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.
20
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.)
24
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.
31
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
37 GIT repository.
38
39 So here is the step-by-step guide how this all works for me.
40
41 First 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
45 Change directory into the cloned tree you just created
46
47  $ cd work
48
49 Set up a remotes file so that you can fetch the latest from Linus' master
50 branch 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
57 and create the linus branch:
58
59  $ git branch linus
60
61 The "linus" branch will be used to track the upstream kernel.  To update it,
62 you simply run:
63
64  $ git fetch linus
65
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).
68
69 If you need to keep track of other public trees, you can add remote branches
70 for 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
78 and run:
79
80  $ git fetch another
81
82 Now create the branches in which you are going to work, these start
83 out at the current tip of the linus branch.
84
85  $ git branch test linus
86  $ git branch release linus
87
88 These 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
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
95 first 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
103 and the push both the test and release trees using:
104
105  $ git push mytree
106
107 or push just one of the test and release branches using:
108
109  $ git push mytree test
110 or
111  $ git push mytree release
112
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
116 linus branch:
117
118  $ git checkout -b speed-up-spinlocks linus
119
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.
123
124  $ ... patch ... test  ... commit [ ... patch ... test ... commit ]*
125
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:
128
129  $ git checkout test && git resolve test speed-up-spinlocks "Pull speed-up-spinlock changes"
130
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.
133
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.
138
139  $ git checkout release && git resolve release speed-up-spinlocks "Pull speed-up-spinlock changes"
140
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:
145
146  $ git-whatchanged branchname ^linus | git-shortlog
147
148 To see whether it has already been merged into the test or release branches
149 use:
150
151  $ git-rev-list branchname ^test
152 or
153  $ git-rev-list branchname ^release
154
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]
157
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
161 output from:
162
163  $ git-rev-list branchname ^linus
164
165 is empty.  At this point the branch can be deleted:
166
167  $ rm .git/refs/heads/branchname
168
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.
173
174 To create diffstat and shortlog summaries of changes to include in a "please
175 pull" request to Linus you can use:
176
177  $ git-whatchanged -p release ^linus | diffstat -p1
178 and
179  $ git-whatchanged release ^linus | git-shortlog
180
181
182 Here 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
189 case "$1" in
190 test|release)
191         git checkout $1 && git resolve $1 linus "Auto-update from upstream"
192         ;;
193 linus)
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         ;;
206 esac
207
208 ==== merge script ====
209 # Merge a branch into either the test or release branch
210
211 pname=$0
212
213 usage()
214 {
215         echo "Usage: $pname branch test|release" 1>&2
216         exit 1
217 }
218
219 if [ ! -f .git/refs/heads/"$1" ]
220 then
221         echo "Can't see branch <$1>" 1>&2
222         usage
223 fi
224
225 case "$2" in
226 test|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         ;;
237 esac
238
239 ==== status script ====
240 # report on status of my ia64 GIT tree
241
242 gb=$(tput setab 2)
243 rb=$(tput setab 1)
244 restore=$(tput setab 9)
245
246 if [ `git-rev-tree release ^test | wc -c` -gt 0 ]
247 then
248         echo $rb Warning: commits in release that are not in test $restore
249         git-whatchanged release ^test
250 fi
251
252 for branch in `ls .git/refs/heads`
253 do
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
286 done