summaryrefslogtreecommitdiff
path: root/Documentation/howto/using-topic-branches.txt
diff options
context:
space:
mode:
Diffstat (limited to 'Documentation/howto/using-topic-branches.txt')
-rw-r--r--Documentation/howto/using-topic-branches.txt264
1 files changed, 264 insertions, 0 deletions
diff --git a/Documentation/howto/using-topic-branches.txt b/Documentation/howto/using-topic-branches.txt
new file mode 100644
index 0000000000..52fa4c012a
--- /dev/null
+++ b/Documentation/howto/using-topic-branches.txt
@@ -0,0 +1,264 @@
+Date: Mon, 15 Aug 2005 12:17:41 -0700
+From: tony.luck@intel.com
+Subject: Some tutorial text (was git/cogito workshop/bof at linuxconf au?)
+
+Here's something that I've been putting together on how I'm using
+GIT as a Linux subsystem maintainer.
+
+I suspect that I'm a bit slap-happy with the "git checkout" commands in
+the examples below, and perhaps missing some of the _true-git_ ways of
+doing things.
+
+-Tony
+
+Linux subsystem maintenance using GIT
+-------------------------------------
+
+My requirements here are to be able to create two public trees:
+
+1) A "test" tree into which patches are initially placed so that they
+can get some exposure when integrated with other ongoing development.
+This tree is available to Andrew for pulling into -mm whenever he wants.
+
+2) A "release" tree into which tested patches are moved for final
+sanity checking, and as a vehicle to send them upstream to Linus
+(by sending him a "please pull" request.)
+
+Note that the period of time that each patch spends in the "test" tree
+is dependent on the complexity of the change. Since GIT does not support
+cherry picking, it is not practical to simply apply all patches to the
+test tree and then pull to the release tree as that would leave trivial
+patches blocked in the test tree waiting for complex changes to accumulate
+enough test time to graduate.
+
+Back in the BitKeeper days I achieved this my creating small forests of
+temporary trees, one tree for each logical grouping of patches, and then
+pulling changes from these trees first to the test tree, and then to the
+release tree. At first I replicated this in GIT, but then I realised
+that I could so this far more efficiently using branches inside a single
+GIT repository.
+
+So here is the step-by-step guide how this all works for me.
+
+First create your work tree by cloning Linus's public tree:
+
+ $ git clone rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git work
+
+Change directory into the cloned tree you just created
+
+ $ cd work
+
+Make a GIT branch named "linus", and rename the "origin" branch as linus too:
+
+ $ git checkout -b linus
+ $ mv .git/branches/origin .git/branches/linus
+
+The "linus" branch will be used to track the upstream kernel. To update it,
+you simply run:
+
+ $ git checkout linus && git pull linus
+
+you can do this frequently (as long as you don't have any uncommited work
+in your tree).
+
+If you need to keep track of other public trees, you can add branches for
+them too:
+
+ $ git checkout -b another linus
+ $ echo URL-for-another-public-tree > .git/branches/another
+
+Now create the branches in which you are going to work, these start
+out at the current tip of the linus branch.
+
+ $ git branch test linus
+ $ git branch release linus
+
+These can be easily kept up to date by merging from the "linus" branch:
+
+ $ git checkout test && git resolve test linus "Auto-update from upstream"
+ $ git checkout release && git resolve release linus "Auto-update from upstream"
+
+Set up so that you can push upstream to your public tree:
+
+ $ echo master.kernel.org:/ftp/pub/scm/linux/kernel/git/aegl/linux-2.6.git > .git/branches/origin
+
+and then push each of the test and release branches using:
+
+ $ git push origin test
+and
+ $ git push origin release
+
+Now to apply some patches from the community. Think of a short
+snappy name for a branch to hold this patch (or related group of
+patches), and create a new branch from the current tip of the
+linus branch:
+
+ $ git checkout -b speed-up-spinlocks linus
+
+Now you apply the patch(es), run some tests, and commit the change(s). If
+the patch is a multi-part series, then you should apply each as a separate
+commit to this branch.
+
+ $ ... patch ... test ... commit [ ... patch ... test ... commit ]*
+
+When you are happy with the state of this change, you can pull it into the
+"test" branch in preparation to make it public:
+
+ $ git checkout test && git resolve test speed-up-spinlocks "Pull speed-up-spinlock changes"
+
+It is unlikely that you would have any conflicts here ... but you might if you
+spent a while on this step and had also pulled new versions from upstream.
+
+Some time later when enough time has passed and testing done, you can pull the
+same branch into the "release" tree ready to go upstream. This is where you
+see the value of keeping each patch (or patch series) in its own branch. It
+means that the patches can be moved into the "release" tree in any order.
+
+ $ git checkout release && git resolve release speed-up-spinlocks "Pull speed-up-spinlock changes"
+
+After a while, you will have a number of branches, and despite the
+well chosen names you picked for each of them, you may forget what
+they are for, or what status they are in. To get a reminder of what
+changes are in a specific branch, use:
+
+ $ git-whatchanged branchname ^linus | git-shortlog
+
+To see whether it has already been merged into the test or release branches
+use:
+
+ $ git-rev-list branchname ^test
+or
+ $ git-rev-list branchname ^release
+
+[If this branch has not yet been merged you will see a set of SHA1 values
+for the commits, if it has been merged, then there will be no output]
+
+Once a patch completes the great cycle (moving from test to release, then
+pulled by Linus, and finally coming back into your local "linus" branch)
+the branch for this change is no longer needed. You detect this when the
+output from:
+
+ $ git-rev-list branchname ^linus
+
+is empty. At this point the branch can be deleted:
+
+ $ rm .git/refs/heads/branchname
+
+Some changes are so trivial that it is not necessary to create a separate
+branch and then merge into each of the test and release branches. For
+these changes, just apply directly to the "release" branch, and then
+merge that into the "test" branch.
+
+To create diffstat and shortlog summaries of changes to include in a "please
+pull" request to Linus you can use:
+
+ $ git-whatchanged -p release ^linus | diffstat -p1
+and
+ $ git-whatchanged release ^linus | git-shortlog
+
+
+Here are some of the scripts that I use to simplify all this even further.
+
+==== update script ====
+# Update a branch in my GIT tree. If the branch to be updated
+# is "linus", then pull from kernel.org. Otherwise merge local
+# linus branch into test|release branch
+
+case "$1" in
+test|release)
+ git checkout $1 && git resolve $1 linus "Auto-update from upstream"
+ ;;
+linus)
+ before=$(cat .git/HEAD)
+ git checkout linus && git pull linus
+ after=$(cat .git/HEAD)
+ if [ $before != $after ]
+ then
+ git-whatchanged $after ^$before | git-shortlog
+ fi
+ ;;
+*)
+ echo "Usage: $0 linus|test|release" 1>&2
+ exit 1
+ ;;
+esac
+
+==== merge script ====
+# Merge a branch into either the test or release branch
+
+pname=$0
+
+usage()
+{
+ echo "Usage: $pname branch test|release" 1>&2
+ exit 1
+}
+
+if [ ! -f .git/refs/heads/"$1" ]
+then
+ echo "Can't see branch <$1>" 1>&2
+ usage
+fi
+
+case "$2" in
+test|release)
+ if [ $(git-rev-list $1 ^$2 | wc -c) -eq 0 ]
+ then
+ echo $1 already merged into $2 1>&2
+ exit 1
+ fi
+ git checkout $2 && git resolve $2 $1 "Pull $1 into $2 branch"
+ ;;
+*)
+ usage
+ ;;
+esac
+
+==== status script ====
+# report on status of my ia64 GIT tree
+
+gb=$(tput setab 2)
+rb=$(tput setab 1)
+restore=$(tput setab 9)
+
+if [ `git-rev-tree release ^test | wc -c` -gt 0 ]
+then
+ echo $rb Warning: commits in release that are not in test $restore
+ git-whatchanged release ^test
+fi
+
+for branch in `ls .git/refs/heads`
+do
+ if [ $branch = linus -o $branch = test -o $branch = release ]
+ then
+ continue
+ fi
+
+ echo -n $gb ======= $branch ====== $restore " "
+ status=
+ for ref in test release linus
+ do
+ if [ `git-rev-tree $branch ^$ref | wc -c` -gt 0 ]
+ then
+ status=$status${ref:0:1}
+ fi
+ done
+ case $status in
+ trl)
+ echo $rb Need to pull into test $restore
+ ;;
+ rl)
+ echo "In test"
+ ;;
+ l)
+ echo "Waiting for linus"
+ ;;
+ "")
+ echo $rb All done $restore
+ ;;
+ *)
+ echo $rb "<$status>" $restore
+ ;;
+ esac
+ git-whatchanged $branch ^linus | git-shortlog
+done