Merge with gitk --parents change.
[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 I suspect that I'm a bit slap-happy with the "git checkout" commands in
9 the examples below, and perhaps missing some of the _true-git_ ways of
10 doing things.
11
12 -Tony
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 my 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 rsync://rsync.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 Make 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
56 The "linus" branch will be used to track the upstream kernel.  To update it,
57 you simply run:
58
59  $ git checkout linus && git pull linus
60
61 you can do this frequently (as long as you don't have any uncommited work
62 in your tree).
63
64 If you need to keep track of other public trees, you can add branches for
65 them too:
66
67  $ git checkout -b another linus
68  $ echo URL-for-another-public-tree > .git/branches/another
69
70 Now create the branches in which you are going to work, these start
71 out at the current tip of the linus branch.
72
73  $ git branch test linus
74  $ git branch release linus
75
76 These 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
81 Set 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
85 and then push each of the test and release branches using:
86
87  $ git push origin test
88 and
89  $ git push origin release
90
91 Now to apply some patches from the community.  Think of a short
92 snappy name for a branch to hold this patch (or related group of
93 patches), and create a new branch from the current tip of the
94 linus branch:
95
96  $ git checkout -b speed-up-spinlocks linus
97
98 Now you apply the patch(es), run some tests, and commit the change(s).  If
99 the patch is a multi-part series, then you should apply each as a separate
100 commit to this branch.
101
102  $ ... patch ... test  ... commit [ ... patch ... test ... commit ]*
103
104 When 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
109 It is unlikely that you would have any conflicts here ... but you might if you
110 spent a while on this step and had also pulled new versions from upstream.
111
112 Some time later when enough time has passed and testing done, you can pull the
113 same branch into the "release" tree ready to go upstream.  This is where you
114 see the value of keeping each patch (or patch series) in its own branch.  It
115 means 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
119 After a while, you will have a number of branches, and despite the
120 well chosen names you picked for each of them, you may forget what
121 they are for, or what status they are in.  To get a reminder of what
122 changes are in a specific branch, use:
123
124  $ git-whatchanged branchname ^linus | git-shortlog
125
126 To see whether it has already been merged into the test or release branches
127 use:
128
129  $ git-rev-list branchname ^test
130 or
131  $ git-rev-list branchname ^release
132
133 [If this branch has not yet been merged you will see a set of SHA1 values
134 for the commits, if it has been merged, then there will be no output]
135
136 Once a patch completes the great cycle (moving from test to release, then
137 pulled by Linus, and finally coming back into your local "linus" branch)
138 the branch for this change is no longer needed.  You detect this when the
139 output from:
140
141  $ git-rev-list branchname ^linus
142
143 is empty.  At this point the branch can be deleted:
144
145  $ rm .git/refs/heads/branchname
146
147 Some changes are so trivial that it is not necessary to create a separate
148 branch and then merge into each of the test and release branches.  For
149 these changes, just apply directly to the "release" branch, and then
150 merge that into the "test" branch.
151
152 To create diffstat and shortlog summaries of changes to include in a "please
153 pull" request to Linus you can use:
154
155  $ git-whatchanged -p release ^linus | diffstat -p1
156 and
157  $ git-whatchanged release ^linus | git-shortlog
158
159
160 Here 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
167 case "$1" in
168 test|release)
169         git checkout $1 && git resolve $1 linus "Auto-update from upstream"
170         ;;
171 linus)
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         ;;
184 esac
185
186 ==== merge script ====
187 # Merge a branch into either the test or release branch
188
189 pname=$0
190
191 usage()
192 {
193         echo "Usage: $pname branch test|release" 1>&2
194         exit 1
195 }
196
197 if [ ! -f .git/refs/heads/"$1" ]
198 then
199         echo "Can't see branch <$1>" 1>&2
200         usage
201 fi
202
203 case "$2" in
204 test|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         ;;
215 esac
216
217 ==== status script ====
218 # report on status of my ia64 GIT tree
219
220 gb=$(tput setab 2)
221 rb=$(tput setab 1)
222 restore=$(tput setab 9)
223
224 if [ `git-rev-tree release ^test | wc -c` -gt 0 ]
225 then
226         echo $rb Warning: commits in release that are not in test $restore
227         git-whatchanged release ^test
228 fi
229
230 for branch in `ls .git/refs/heads`
231 do
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
264 done