diff options
Diffstat (limited to 'Documentation/howto')
-rw-r--r-- | Documentation/howto/dangling-objects.txt | 109 | ||||
-rw-r--r-- | Documentation/howto/isolate-bugs-with-bisect.txt | 65 | ||||
-rw-r--r-- | Documentation/howto/make-dist.txt | 52 | ||||
-rw-r--r-- | Documentation/howto/rebase-and-edit.txt | 81 | ||||
-rw-r--r-- | Documentation/howto/rebase-from-internal-branch.txt | 165 | ||||
-rw-r--r-- | Documentation/howto/rebuild-from-update-hook.txt | 87 | ||||
-rw-r--r-- | Documentation/howto/revert-branch-rebase.txt | 193 | ||||
-rw-r--r-- | Documentation/howto/separating-topic-branches.txt | 91 | ||||
-rw-r--r-- | Documentation/howto/setup-git-server-over-http.txt | 256 | ||||
-rw-r--r-- | Documentation/howto/update-hook-example.txt | 172 | ||||
-rw-r--r-- | Documentation/howto/using-topic-branches.txt | 296 |
11 files changed, 1567 insertions, 0 deletions
diff --git a/Documentation/howto/dangling-objects.txt b/Documentation/howto/dangling-objects.txt new file mode 100644 index 0000000000..e82ddae3cf --- /dev/null +++ b/Documentation/howto/dangling-objects.txt @@ -0,0 +1,109 @@ +From: Linus Torvalds <torvalds@linux-foundation.org> +Subject: Re: Question about fsck-objects output +Date: Thu, 25 Jan 2007 12:01:06 -0800 (PST) +Message-ID: <Pine.LNX.4.64.0701251144290.25027@woody.linux-foundation.org> +Archived-At: <http://permalink.gmane.org/gmane.comp.version-control.git/37754> +Abstract: Linus describes what dangling objects are, when they + are left behind, and how to view their relationship with branch + heads in gitk + +On Thu, 25 Jan 2007, Larry Streepy wrote: + +> Sorry to ask such a basic question, but I can't quite decipher the output of +> fsck-objects. When I run it, I get this: +> +> git fsck-objects +> dangling commit 2213f6d4dd39ca8baebd0427723723e63208521b +> dangling commit f0d4e00196bd5ee54463e9ea7a0f0e8303da767f +> dangling blob 6a6d0b01b3e96d49a8f2c7addd4ef8c3bd1f5761 +> +> +> Even after a "repack -a -d" they still exist. The man page has a short +> explanation, but, at least for me, it wasn't fully enlightening. :-) +> +> The man page says that dangling commits could be "root" commits, but since my +> repo started as a clone of another repo, I don't see how I could have any root +> commits. Also, the page doesn't really describe what a dangling blob is. +> +> So, can someone explain what these artifacts are and if they are a problem +> that I should be worried about? + +The most common situation is that you've rebased a branch (or you have +pulled from somebody else who rebased a branch, like the "pu" branch in +the git.git archive itself). + +What happens is that the old head of the original branch still exists, as +does obviously everything it pointed to. The branch pointer itself just +doesn't, since you replaced it with another one. + +However, there are certainly other situations too that cause dangling +objects. For example, the "dangling blob" situation you have tends to be +because you did a "git add" of a file, but then, before you actually +committed it and made it part of the bigger picture, you changed something +else in that file and committed that *updated* thing - the old state that +you added originally ends up not being pointed to by any commit/tree, so +it's now a dangling blob object. + +Similarly, when the "recursive" merge strategy runs, and finds that there +are criss-cross merges and thus more than one merge base (which is fairly +unusual, but it does happen), it will generate one temporary midway tree +(or possibly even more, if you had lots of criss-crossing merges and +more than two merge bases) as a temporary internal merge base, and again, +those are real objects, but the end result will not end up pointing to +them, so they end up "dangling" in your repository. + +Generally, dangling objects aren't anything to worry about. They can even +be very useful: if you screw something up, the dangling objects can be how +you recover your old tree (say, you did a rebase, and realized that you +really didn't want to - you can look at what dangling objects you have, +and decide to reset your head to some old dangling state). + +For commits, the most useful thing to do with dangling objects tends to be +to do a simple + + gitk <dangling-commit-sha-goes-here> --not --all + +which means exactly what it sounds like: it says that you want to see the +commit history that is described by the dangling commit(s), but you do NOT +want to see the history that is described by all your branches and tags +(which are the things you normally reach). That basically shows you in a +nice way what the danglign commit was (and notice that it might not be +just one commit: we only report the "tip of the line" as being dangling, +but there might be a whole deep and complex commit history that has gotten +dropped - rebasing will do that). + +For blobs and trees, you can't do the same, but you can examine them. You +can just do + + git show <dangling-blob/tree-sha-goes-here> + +to show what the contents of the blob were (or, for a tree, basically what +the "ls" for that directory was), and that may give you some idea of what +the operation was that left that dangling object. + +Usually, dangling blobs and trees aren't very interesting. They're almost +always the result of either being a half-way mergebase (the blob will +often even have the conflict markers from a merge in it, if you have had +conflicting merges that you fixed up by hand), or simply because you +interrupted a "git fetch" with ^C or something like that, leaving _some_ +of the new objects in the object database, but just dangling and useless. + +Anyway, once you are sure that you're not interested in any dangling +state, you can just prune all unreachable objects: + + git prune + +and they'll be gone. But you should only run "git prune" on a quiescent +repository - it's kind of like doing a filesystem fsck recovery: you don't +want to do that while the filesystem is mounted. + +(The same is true of "git-fsck-objects" itself, btw - but since +git-fsck-objects never actually *changes* the repository, it just reports +on what it found, git-fsck-objects itself is never "dangerous" to run. +Running it while somebody is actually changing the repository can cause +confusing and scary messages, but it won't actually do anything bad. In +contrast, running "git prune" while somebody is actively changing the +repository is a *BAD* idea). + + Linus + diff --git a/Documentation/howto/isolate-bugs-with-bisect.txt b/Documentation/howto/isolate-bugs-with-bisect.txt new file mode 100644 index 0000000000..926bbdc3cb --- /dev/null +++ b/Documentation/howto/isolate-bugs-with-bisect.txt @@ -0,0 +1,65 @@ +From: Linus Torvalds <torvalds () osdl ! org> +To: git@vger.kernel.org +Date: 2005-11-08 1:31:34 +Subject: Real-life kernel debugging scenario +Abstract: Short-n-sweet, Linus tells us how to leverage `git-bisect` to perform + bug isolation on a repository where "good" and "bad" revisions are known + in order to identify a suspect commit. + + +How To Use git-bisect To Isolate a Bogus Commit +=============================================== + +The way to use "git bisect" couldn't be easier. + +Figure out what the oldest bad state you know about is (that's usually the +head of "master", since that's what you just tried to boot and failed at). +Also, figure out the most recent known-good commit (usually the _previous_ +kernel you ran: and if you've only done a single "pull" in between, it +will be ORIG_HEAD). + +Then do + + git bisect start + git bisect bad master <- mark "master" as the bad state + git bisect good ORIG_HEAD <- mark ORIG_HEAD as good (or + whatever other known-good + thing you booted last) + +and at this point "git bisect" will churn for a while, and tell you what +the mid-point between those two commits are, and check that state out as +the head of the new "bisect" branch. + +Compile and reboot. + +If it's good, just do + + git bisect good <- mark current head as good + +otherwise, reboot into a good kernel instead, and do (surprise surprise, +git really is very intuitive): + + git bisect bad <- mark current head as bad + +and whatever you do, git will select a new half-way point. Do this for a +while, until git tells you exactly which commit was the first bad commit. +That's your culprit. + +It really works wonderfully well, except for the case where there was +_another_ commit that broke something in between, like introduced some +stupid compile error. In that case you should not mark that commit good or +bad: you should try to find another commit close-by, and do a "git reset +--hard <newcommit>" to try out _that_ commit instead, and then test that +instead (and mark it good or bad). + +You can do "git bisect visualize" while you do all this to see what's +going on by starting up gitk on the bisection range. + +Finally, once you've figured out exactly which commit was bad, you can +then go back to the master branch, and try reverting just that commit: + + git checkout master + git revert <bad-commit-id> + +to verify that the top-of-kernel works with that single commit reverted. + diff --git a/Documentation/howto/make-dist.txt b/Documentation/howto/make-dist.txt new file mode 100644 index 0000000000..00e330b293 --- /dev/null +++ b/Documentation/howto/make-dist.txt @@ -0,0 +1,52 @@ +Date: Fri, 12 Aug 2005 22:39:48 -0700 (PDT) +From: Linus Torvalds <torvalds@osdl.org> +To: Dave Jones <davej@redhat.com> +cc: git@vger.kernel.org +Subject: Re: Fwd: Re: git checkout -f branch doesn't remove extra files +Abstract: In this article, Linus talks about building a tarball, + incremental patch, and ChangeLog, given a base release and two + rc releases, following the convention of giving the patch from + the base release and the latest rc, with ChangeLog between the + last rc and the latest rc. + +On Sat, 13 Aug 2005, Dave Jones wrote: +> +> > Git actually has a _lot_ of nifty tools. I didn't realize that people +> > didn't know about such basic stuff as "git-tar-tree" and "git-ls-files". +> +> Maybe its because things are moving so fast :) Or maybe I just wasn't +> paying attention on that day. (I even read the git changes via RSS, +> so I should have no excuse). + +Well, git-tar-tree has been there since late April - it's actually one of +those really early commands. I'm pretty sure the RSS feed came later ;) + +I use it all the time in doing releases, it's a lot faster than creating a +tar tree by reading the filesystem (even if you don't have to check things +out). A hidden pearl. + +This is my crappy "release-script": + + [torvalds@g5 ~]$ cat bin/release-script + #!/bin/sh + stable="$1" + last="$2" + new="$3" + echo "# git-tag v$new" + echo "git-tar-tree v$new linux-$new | gzip -9 > ../linux-$new.tar.gz" + echo "git-diff-tree -p v$stable v$new | gzip -9 > ../patch-$new.gz" + echo "git-rev-list --pretty v$new ^v$last > ../ChangeLog-$new" + echo "git-rev-list --pretty=short v$new ^v$last | git-shortlog > ../ShortLog" + echo "git-diff-tree -p v$last v$new | git-apply --stat > ../diffstat-$new" + +and when I want to do a new kernel release I literally first tag it, and +then do + + release-script 2.6.12 2.6.13-rc6 2.6.13-rc7 + +and check that things look sane, and then just cut-and-paste the commands. + +Yeah, it's stupid. + + Linus + diff --git a/Documentation/howto/rebase-and-edit.txt b/Documentation/howto/rebase-and-edit.txt new file mode 100644 index 0000000000..646c55cc69 --- /dev/null +++ b/Documentation/howto/rebase-and-edit.txt @@ -0,0 +1,81 @@ +Date: Sat, 13 Aug 2005 22:16:02 -0700 (PDT) +From: Linus Torvalds <torvalds@osdl.org> +To: Steve French <smfrench@austin.rr.com> +cc: git@vger.kernel.org +Subject: Re: sending changesets from the middle of a git tree +Abstract: In this article, Linus demonstrates how a broken commit + in a sequence of commits can be removed by rewinding the head and + reapplying selected changes. + +On Sat, 13 Aug 2005, Linus Torvalds wrote: + +> That's correct. Same things apply: you can move a patch over, and create a +> new one with a modified comment, but basically the _old_ commit will be +> immutable. + +Let me clarify. + +You can entirely _drop_ old branches, so commits may be immutable, but +nothing forces you to keep them. Of course, when you drop a commit, you'll +always end up dropping all the commits that depended on it, and if you +actually got somebody else to pull that commit you can't drop it from +_their_ repository, but undoing things is not impossible. + +For example, let's say that you've made a mess of things: you've committed +three commits "old->a->b->c", and you notice that "a" was broken, but you +want to save "b" and "c". What you can do is + + # Create a branch "broken" that is the current code + # for reference + git branch broken + + # Reset the main branch to three parents back: this + # effectively undoes the three top commits + git reset HEAD^^^ + git checkout -f + + # Check the result visually to make sure you know what's + # going on + gitk --all + + # Re-apply the two top ones from "broken" + # + # First "parent of broken" (aka b): + git-diff-tree -p broken^ | git-apply --index + git commit --reedit=broken^ + + # Then "top of broken" (aka c): + git-diff-tree -p broken | git-apply --index + git commit --reedit=broken + +and you've now re-applied (and possibly edited the comments) the two +commits b/c, and commit "a" is basically gone (it still exists in the +"broken" branch, of course). + +Finally, check out the end result again: + + # Look at the new commit history + gitk --all + +to see that everything looks sensible. + +And then, you can just remove the broken branch if you decide you really +don't want it: + + # remove 'broken' branch + git branch -d broken + + # Prune old objects if you're really really sure + git prune + +And yeah, I'm sure there are other ways of doing this. And as usual, the +above is totally untested, and I just wrote it down in this email, so if +I've done something wrong, you'll have to figure it out on your own ;) + + Linus +- +To unsubscribe from this list: send the line "unsubscribe git" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html + + diff --git a/Documentation/howto/rebase-from-internal-branch.txt b/Documentation/howto/rebase-from-internal-branch.txt new file mode 100644 index 0000000000..3b3a5c2e69 --- /dev/null +++ b/Documentation/howto/rebase-from-internal-branch.txt @@ -0,0 +1,165 @@ +From: Junio C Hamano <junkio@cox.net> +To: git@vger.kernel.org +Cc: Petr Baudis <pasky@suse.cz>, Linus Torvalds <torvalds@osdl.org> +Subject: Re: sending changesets from the middle of a git tree +Date: Sun, 14 Aug 2005 18:37:39 -0700 +Abstract: In this article, JC talks about how he rebases the + public "pu" branch using the core GIT tools when he updates + the "master" branch, and how "rebase" works. Also discussed + is how this applies to individual developers who sends patches + upstream. + +Petr Baudis <pasky@suse.cz> writes: + +> Dear diary, on Sun, Aug 14, 2005 at 09:57:13AM CEST, I got a letter +> where Junio C Hamano <junkio@cox.net> told me that... +>> Linus Torvalds <torvalds@osdl.org> writes: +>> +>> > Junio, maybe you want to talk about how you move patches from your "pu" +>> > branch to the real branches. +>> +> Actually, wouldn't this be also precisely for what StGIT is intended to? + +Exactly my feeling. I was sort of waiting for Catalin to speak +up. With its basing philosophical ancestry on quilt, this is +the kind of task StGIT is designed to do. + +I just have done a simpler one, this time using only the core +GIT tools. + +I had a handful commits that were ahead of master in pu, and I +wanted to add some documentation bypassing my usual habit of +placing new things in pu first. At the beginning, the commit +ancestry graph looked like this: + + *"pu" head + master --> #1 --> #2 --> #3 + +So I started from master, made a bunch of edits, and committed: + + $ git checkout master + $ cd Documentation; ed git.txt ... + $ cd ..; git add Documentation/*.txt + $ git commit -s + +After the commit, the ancestry graph would look like this: + + *"pu" head + master^ --> #1 --> #2 --> #3 + \ + \---> master + +The old master is now master^ (the first parent of the master). +The new master commit holds my documentation updates. + +Now I have to deal with "pu" branch. + +This is the kind of situation I used to have all the time when +Linus was the maintainer and I was a contributor, when you look +at "master" branch being the "maintainer" branch, and "pu" +branch being the "contributor" branch. Your work started at the +tip of the "maintainer" branch some time ago, you made a lot of +progress in the meantime, and now the maintainer branch has some +other commits you do not have yet. And "git rebase" was written +with the explicit purpose of helping to maintain branches like +"pu". You _could_ merge master to pu and keep going, but if you +eventually want to cherrypick and merge some but not necessarily +all changes back to the master branch, it often makes later +operations for _you_ easier if you rebase (i.e. carry forward +your changes) "pu" rather than merge. So I ran "git rebase": + + $ git checkout pu + $ git rebase master pu + +What this does is to pick all the commits since the current +branch (note that I now am on "pu" branch) forked from the +master branch, and forward port these changes. + + master^ --> #1 --> #2 --> #3 + \ *"pu" head + \---> master --> #1' --> #2' --> #3' + +The diff between master^ and #1 is applied to master and +committed to create #1' commit with the commit information (log, +author and date) taken from commit #1. On top of that #2' and #3' +commits are made similarly out of #2 and #3 commits. + +Old #3 is not recorded in any of the .git/refs/heads/ file +anymore, so after doing this you will have dangling commit if +you ran fsck-cache, which is normal. After testing "pu", you +can run "git prune" to get rid of those original three commits. + +While I am talking about "git rebase", I should talk about how +to do cherrypicking using only the core GIT tools. + +Let's go back to the earlier picture, with different labels. + +You, as an individual developer, cloned upstream repository and +made a couple of commits on top of it. + + *your "master" head + upstream --> #1 --> #2 --> #3 + +You would want changes #2 and #3 incorporated in the upstream, +while you feel that #1 may need further improvements. So you +prepare #2 and #3 for e-mail submission. + + $ git format-patch master^^ master + +This creates two files, 0001-XXXX.patch and 0002-XXXX.patch. Send +them out "To: " your project maintainer and "Cc: " your mailing +list. You could use contributed script git-send-email if +your host has necessary perl modules for this, but your usual +MUA would do as long as it does not corrupt whitespaces in the +patch. + +Then you would wait, and you find out that the upstream picked +up your changes, along with other changes. + + where *your "master" head + upstream --> #1 --> #2 --> #3 + used \ + to be \--> #A --> #2' --> #3' --> #B --> #C + *upstream head + +The two commits #2' and #3' in the above picture record the same +changes your e-mail submission for #2 and #3 contained, but +probably with the new sign-off line added by the upstream +maintainer and definitely with different committer and ancestry +information, they are different objects from #2 and #3 commits. + +You fetch from upstream, but not merge. + + $ git fetch upstream + +This leaves the updated upstream head in .git/FETCH_HEAD but +does not touch your .git/HEAD nor .git/refs/heads/master. +You run "git rebase" now. + + $ git rebase FETCH_HEAD master + +Earlier, I said that rebase applies all the commits from your +branch on top of the upstream head. Well, I lied. "git rebase" +is a bit smarter than that and notices that #2 and #3 need not +be applied, so it only applies #1. The commit ancestry graph +becomes something like this: + + where *your old "master" head + upstream --> #1 --> #2 --> #3 + used \ your new "master" head* + to be \--> #A --> #2' --> #3' --> #B --> #C --> #1' + *upstream + head + +Again, "git prune" would discard the disused commits #1-#3 and +you continue on starting from the new "master" head, which is +the #1' commit. + +-jc + +- +To unsubscribe from this list: send the line "unsubscribe git" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html + + diff --git a/Documentation/howto/rebuild-from-update-hook.txt b/Documentation/howto/rebuild-from-update-hook.txt new file mode 100644 index 0000000000..02621b54a0 --- /dev/null +++ b/Documentation/howto/rebuild-from-update-hook.txt @@ -0,0 +1,87 @@ +Subject: [HOWTO] Using post-update hook +Message-ID: <7vy86o6usx.fsf@assigned-by-dhcp.cox.net> +From: Junio C Hamano <junkio@cox.net> +Date: Fri, 26 Aug 2005 18:19:10 -0700 +Abstract: In this how-to article, JC talks about how he + uses the post-update hook to automate git documentation page + shown at http://www.kernel.org/pub/software/scm/git/docs/. + +The pages under http://www.kernel.org/pub/software/scm/git/docs/ +are built from Documentation/ directory of the git.git project +and needed to be kept up-to-date. The www.kernel.org/ servers +are mirrored and I was told that the origin of the mirror is on +the machine $some.kernel.org, on which I was given an account +when I took over git maintainership from Linus. + +The directories relevant to this how-to are these two: + + /pub/scm/git/git.git/ The public git repository. + /pub/software/scm/git/docs/ The HTML documentation page. + +So I made a repository to generate the documentation under my +home directory over there. + + $ cd + $ mkdir doc-git && cd doc-git + $ git clone /pub/scm/git/git.git/ docgen + +What needs to happen is to update the $HOME/doc-git/docgen/ +working tree, build HTML docs there and install the result in +/pub/software/scm/git/docs/ directory. So I wrote a little +script: + + $ cat >dododoc.sh <<\EOF + #!/bin/sh + cd $HOME/doc-git/docgen || exit + + unset GIT_DIR + + git pull /pub/scm/git/git.git/ master && + cd Documentation && + make install-webdoc + EOF + +Initially I used to run this by hand whenever I push into the +public git repository. Then I did a cron job that ran twice a +day. The current round uses the post-update hook mechanism, +like this: + + $ cat >/pub/scm/git/git.git/hooks/post-update <<\EOF + #!/bin/sh + # + # An example hook script to prepare a packed repository for use over + # dumb transports. + # + # To enable this hook, make this file executable by "chmod +x post-update". + + case " $* " in + *' refs/heads/master '*) + echo $HOME/doc-git/dododoc.sh | at now + ;; + esac + exec git-update-server-info + EOF + $ chmod +x /pub/scm/git/git.git/hooks/post-update + +There are four things worth mentioning: + + - The update-hook is run after the repository accepts a "git + push", under my user privilege. It is given the full names + of refs that have been updated as arguments. My post-update + runs the dododoc.sh script only when the master head is + updated. + + - When update-hook is run, GIT_DIR is set to '.' by the calling + receive-pack. This is inherited by the dododoc.sh run via + the "at" command, and needs to be unset; otherwise, "git + pull" it does into $HOME/doc-git/docgen/ repository would not + work correctly. + + - The stdout of update hook script is not connected to git + push; I run the heavy part of the command inside "at", to + receive the execution report via e-mail. + + - This is still crude and does not protect against simultaneous + make invocations stomping on each other. I would need to add + some locking mechanism for this. + diff --git a/Documentation/howto/revert-branch-rebase.txt b/Documentation/howto/revert-branch-rebase.txt new file mode 100644 index 0000000000..d88ec23a97 --- /dev/null +++ b/Documentation/howto/revert-branch-rebase.txt @@ -0,0 +1,193 @@ +From: Junio C Hamano <junkio@cox.net> +To: git@vger.kernel.org +Subject: [HOWTO] Reverting an existing commit +Abstract: In this article, JC gives a small real-life example of using + 'git revert' command, and using a temporary branch and tag for safety + and easier sanity checking. +Date: Mon, 29 Aug 2005 21:39:02 -0700 +Content-type: text/asciidoc +Message-ID: <7voe7g3uop.fsf@assigned-by-dhcp.cox.net> + +Reverting an existing commit +============================ + +One of the changes I pulled into the 'master' branch turns out to +break building GIT with GCC 2.95. While they were well intentioned +portability fixes, keeping things working with gcc-2.95 was also +important. Here is what I did to revert the change in the 'master' +branch and to adjust the 'pu' branch, using core GIT tools and +barebone Porcelain. + +First, prepare a throw-away branch in case I screw things up. + +------------------------------------------------ +$ git checkout -b revert-c99 master +------------------------------------------------ + +Now I am on the 'revert-c99' branch. Let's figure out which commit to +revert. I happen to know that the top of the 'master' branch is a +merge, and its second parent (i.e. foreign commit I merged from) has +the change I would want to undo. Further I happen to know that that +merge introduced 5 commits or so: + +------------------------------------------------ +$ git show-branch --more=4 master master^2 | head +* [master] Merge refs/heads/portable from http://www.cs.berkeley.... + ! [master^2] Replace C99 array initializers with code. +-- +- [master] Merge refs/heads/portable from http://www.cs.berkeley.... +*+ [master^2] Replace C99 array initializers with code. +*+ [master^2~1] Replace unsetenv() and setenv() with older putenv(). +*+ [master^2~2] Include sys/time.h in daemon.c. +*+ [master^2~3] Fix ?: statements. +*+ [master^2~4] Replace zero-length array decls with []. +* [master~1] tutorial note about git branch +------------------------------------------------ + +The '--more=4' above means "after we reach the merge base of refs, +show until we display four more common commits". That last commit +would have been where the "portable" branch was forked from the main +git.git repository, so this would show everything on both branches +since then. I just limited the output to the first handful using +'head'. + +Now I know 'master^2~4' (pronounce it as "find the second parent of +the 'master', and then go four generations back following the first +parent") is the one I would want to revert. Since I also want to say +why I am reverting it, the '-n' flag is given to 'git revert'. This +prevents it from actually making a commit, and instead 'git revert' +leaves the commit log message it wanted to use in '.msg' file: + +------------------------------------------------ +$ git revert -n master^2~4 +$ cat .msg +Revert "Replace zero-length array decls with []." + +This reverts 6c5f9baa3bc0d63e141e0afc23110205379905a4 commit. +$ git diff HEAD ;# to make sure what we are reverting makes sense. +$ make CC=gcc-2.95 clean test ;# make sure it fixed the breakage. +$ make clean test ;# make sure it did not cause other breakage. +------------------------------------------------ + +The reverted change makes sense (from reading the 'diff' output), does +fix the problem (from 'make CC=gcc-2.95' test), and does not cause new +breakage (from the last 'make test'). I'm ready to commit: + +------------------------------------------------ +$ git commit -a -s ;# read .msg into the log, + # and explain why I am reverting. +------------------------------------------------ + +I could have screwed up in any of the above steps, but in the worst +case I could just have done 'git checkout master' to start over. +Fortunately I did not have to; what I have in the current branch +'revert-c99' is what I want. So merge that back into 'master': + +------------------------------------------------ +$ git checkout master +$ git merge revert-c99 ;# this should be a fast forward +Updating from 10d781b9caa4f71495c7b34963bef137216f86a8 to e3a693c... + cache.h | 8 ++++---- + commit.c | 2 +- + ls-files.c | 2 +- + receive-pack.c | 2 +- + server-info.c | 2 +- + 5 files changed, 8 insertions(+), 8 deletions(-) +------------------------------------------------ + +There is no need to redo the test at this point. We fast forwarded +and we know 'master' matches 'revert-c99' exactly. In fact: + +------------------------------------------------ +$ git diff master..revert-c99 +------------------------------------------------ + +says nothing. + +Then we rebase the 'pu' branch as usual. + +------------------------------------------------ +$ git checkout pu +$ git tag pu-anchor pu +$ git rebase master +* Applying: Redo "revert" using three-way merge machinery. +First trying simple merge strategy to cherry-pick. +Finished one cherry-pick. +* Applying: Remove git-apply-patch-script. +First trying simple merge strategy to cherry-pick. +Simple cherry-pick fails; trying Automatic cherry-pick. +Removing Documentation/git-apply-patch-script.txt +Removing git-apply-patch-script +Finished one cherry-pick. +* Applying: Document "git cherry-pick" and "git revert" +First trying simple merge strategy to cherry-pick. +Finished one cherry-pick. +* Applying: mailinfo and applymbox updates +First trying simple merge strategy to cherry-pick. +Finished one cherry-pick. +* Applying: Show commits in topo order and name all commits. +First trying simple merge strategy to cherry-pick. +Finished one cherry-pick. +* Applying: More documentation updates. +First trying simple merge strategy to cherry-pick. +Finished one cherry-pick. +------------------------------------------------ + +The temporary tag 'pu-anchor' is me just being careful, in case 'git +rebase' screws up. After this, I can do these for sanity check: + +------------------------------------------------ +$ git diff pu-anchor..pu ;# make sure we got the master fix. +$ make CC=gcc-2.95 clean test ;# make sure it fixed the breakage. +$ make clean test ;# make sure it did not cause other breakage. +------------------------------------------------ + +Everything is in the good order. I do not need the temporary branch +nor tag anymore, so remove them: + +------------------------------------------------ +$ rm -f .git/refs/tags/pu-anchor +$ git branch -d revert-c99 +------------------------------------------------ + +It was an emergency fix, so we might as well merge it into the +'release candidate' branch, although I expect the next release would +be some days off: + +------------------------------------------------ +$ git checkout rc +$ git pull . master +Packing 0 objects +Unpacking 0 objects + +* committish: e3a693c... refs/heads/master from . +Trying to merge e3a693c... into 8c1f5f0... using 10d781b... +Committed merge 7fb9b7262a1d1e0a47bbfdcbbcf50ce0635d3f8f + cache.h | 8 ++++---- + commit.c | 2 +- + ls-files.c | 2 +- + receive-pack.c | 2 +- + server-info.c | 2 +- + 5 files changed, 8 insertions(+), 8 deletions(-) +------------------------------------------------ + +And the final repository status looks like this: + +------------------------------------------------ +$ git show-branch --more=1 master pu rc +! [master] Revert "Replace zero-length array decls with []." + ! [pu] git-repack: Add option to repack all objects. + * [rc] Merge refs/heads/master from . +--- + + [pu] git-repack: Add option to repack all objects. + + [pu~1] More documentation updates. + + [pu~2] Show commits in topo order and name all commits. + + [pu~3] mailinfo and applymbox updates + + [pu~4] Document "git cherry-pick" and "git revert" + + [pu~5] Remove git-apply-patch-script. + + [pu~6] Redo "revert" using three-way merge machinery. + - [rc] Merge refs/heads/master from . +++* [master] Revert "Replace zero-length array decls with []." + - [rc~1] Merge refs/heads/master from . +... [master~1] Merge refs/heads/portable from http://www.cs.berkeley.... +------------------------------------------------ diff --git a/Documentation/howto/separating-topic-branches.txt b/Documentation/howto/separating-topic-branches.txt new file mode 100644 index 0000000000..090e2c9b01 --- /dev/null +++ b/Documentation/howto/separating-topic-branches.txt @@ -0,0 +1,91 @@ +From: Junio C Hamano <junkio@cox.net> +Subject: Separating topic branches +Abstract: In this article, JC describes how to separate topic branches. + +This text was originally a footnote to a discussion about the +behaviour of the git diff commands. + +Often I find myself doing that [running diff against something other +than HEAD] while rewriting messy development history. For example, I +start doing some work without knowing exactly where it leads, and end +up with a history like this: + + "master" + o---o + \ "topic" + o---o---o---o---o---o + +At this point, "topic" contains something I know I want, but it +contains two concepts that turned out to be completely independent. +And often, one topic component is larger than the other. It may +contain more than two topics. + +In order to rewrite this mess to be more manageable, I would first do +"diff master..topic", to extract the changes into a single patch, start +picking pieces from it to get logically self-contained units, and +start building on top of "master": + + $ git diff master..topic >P.diff + $ git checkout -b topicA master + ... pick and apply pieces from P.diff to build + ... commits on topicA branch. + + o---o---o + / "topicA" + o---o"master" + \ "topic" + o---o---o---o---o---o + +Before doing each commit on "topicA" HEAD, I run "diff HEAD" +before update-index the affected paths, or "diff --cached HEAD" +after. Also I would run "diff --cached master" to make sure +that the changes are only the ones related to "topicA". Usually +I do this for smaller topics first. + +After that, I'd do the remainder of the original "topic", but +for that, I do not start from the patchfile I extracted by +comparing "master" and "topic" I used initially. Still on +"topicA", I extract "diff topic", and use it to rebuild the +other topic: + + $ git diff -R topic >P.diff ;# --cached also would work fine + $ git checkout -b topicB master + ... pick and apply pieces from P.diff to build + ... commits on topicB branch. + + "topicB" + o---o---o---o---o + / + /o---o---o + |/ "topicA" + o---o"master" + \ "topic" + o---o---o---o---o---o + +After I am done, I'd try a pretend-merge between "topicA" and +"topicB" in order to make sure I have not missed anything: + + $ git pull . topicA ;# merge it into current "topicB" + $ git diff topic + "topicB" + o---o---o---o---o---* (pretend merge) + / / + /o---o---o----------' + |/ "topicA" + o---o"master" + \ "topic" + o---o---o---o---o---o + +The last diff better not to show anything other than cleanups +for crufts. Then I can finally clean things up: + + $ git branch -D topic + $ git reset --hard HEAD^ ;# nuke pretend merge + + "topicB" + o---o---o---o---o + / + /o---o---o + |/ "topicA" + o---o"master" + diff --git a/Documentation/howto/setup-git-server-over-http.txt b/Documentation/howto/setup-git-server-over-http.txt new file mode 100644 index 0000000000..8eadc20494 --- /dev/null +++ b/Documentation/howto/setup-git-server-over-http.txt @@ -0,0 +1,256 @@ +From: Rutger Nijlunsing <rutger@nospam.com> +Subject: Setting up a git repository which can be pushed into and pulled from over HTTP. +Date: Thu, 10 Aug 2006 22:00:26 +0200 + +Since Apache is one of those packages people like to compile +themselves while others prefer the bureaucrat's dream Debian, it is +impossible to give guidelines which will work for everyone. Just send +some feedback to the mailing list at git@vger.kernel.org to get this +document tailored to your favorite distro. + + +What's needed: + +- Have an Apache web-server + + On Debian: + $ apt-get install apache2 + To get apache2 by default started, + edit /etc/default/apache2 and set NO_START=0 + +- can edit the configuration of it. + + This could be found under /etc/httpd, or refer to your Apache documentation. + + On Debian: this means being able to edit files under /etc/apache2 + +- can restart it. + + 'apachectl --graceful' might do. If it doesn't, just stop and + restart apache. Be warning that active connections to your server + might be aborted by this. + + On Debian: + $ /etc/init.d/apache2 restart + or + $ /etc/init.d/apache2 force-reload + (which seems to do the same) + This adds symlinks from the /etc/apache2/mods-enabled to + /etc/apache2/mods-available. + +- have permissions to chown a directory + +- have git installed at the server _and_ client + +In effect, this probably means you're going to be root. + + +Step 1: setup a bare GIT repository +----------------------------------- + +At the time of writing, git-http-push cannot remotely create a GIT +repository. So we have to do that at the server side with git. Another +option would be to generate an empty repository at the client and copy +it to the server with WebDAV. But then you're probably the first to +try that out :) + +Create the directory under the DocumentRoot of the directories served +by Apache. As an example we take /usr/local/apache2, but try "grep +DocumentRoot /where/ever/httpd.conf" to find your root: + + $ cd /usr/local/apache/htdocs + $ mkdir my-new-repo.git + + On Debian: + + $ cd /var/www + $ mkdir my-new-repo.git + + +Initialize a bare repository + + $ cd my-new-repo.git + $ git --bare init + + +Change the ownership to your web-server's credentials. Use "grep ^User +httpd.conf" and "grep ^Group httpd.conf" to find out: + + $ chown -R www.www . + + On Debian: + + $ chown -R www-data.www-data . + + +If you do not know which user Apache runs as, you can alternatively do +a "chmod -R a+w .", inspect the files which are created later on, and +set the permissions appropriately. + +Restart apache2, and check whether http://server/my-new-repo.git gives +a directory listing. If not, check whether apache started up +successfully. + + +Step 2: enable DAV on this repository +------------------------------------- + +First make sure the dav_module is loaded. For this, insert in httpd.conf: + + LoadModule dav_module libexec/httpd/libdav.so + AddModule mod_dav.c + +Also make sure that this line exists which is the file used for +locking DAV operations: + + DAVLockDB "/usr/local/apache2/temp/DAV.lock" + + On Debian these steps can be performed with: + + Enable the dav and dav_fs modules of apache: + $ a2enmod dav_fs + (just to be sure. dav_fs might be unneeded, I don't know) + $ a2enmod dav + The DAV lock is located in /etc/apache2/mods-available/dav_fs.conf: + DAVLockDB /var/lock/apache2/DAVLock + +Of course, it can point somewhere else, but the string is actually just a +prefix in some Apache configurations, and therefore the _directory_ has to +be writable by the user Apache runs as. + +Then, add something like this to your httpd.conf + + <Location /my-new-repo.git> + DAV on + AuthType Basic + AuthName "Git" + AuthUserFile /usr/local/apache2/conf/passwd.git + Require valid-user + </Location> + + On Debian: + Create (or add to) /etc/apache2/conf.d/git.conf : + + <Location /my-new-repo.git> + DAV on + AuthType Basic + AuthName "Git" + AuthUserFile /etc/apache2/passwd.git + Require valid-user + </Location> + + Debian automatically reads all files under /etc/apach2/conf.d. + +The password file can be somewhere else, but it has to be readable by +Apache and preferably not readable by the world. + +Create this file by + $ htpasswd -c /usr/local/apache2/conf/passwd.git <user> + + On Debian: + $ htpasswd -c /etc/apache2/passwd.git <user> + +You will be asked a password, and the file is created. Subsequent calls +to htpasswd should omit the '-c' option, since you want to append to the +existing file. + +You need to restart Apache. + +Now go to http://<username>@<servername>/my-new-repo.git in your +browser to check whether it asks for a password and accepts the right +password. + +On Debian: + + To test the WebDAV part, do: + + $ apt-get install litmus + $ litmus http://<servername>/my-new-repo.git <username> <password> + + Most tests should pass. + +A command line tool to test WebDAV is cadaver. + +If you're into Windows, from XP onwards Internet Explorer supports +WebDAV. For this, do Internet Explorer -> Open Location -> +http://<servername>/my-new-repo.git [x] Open as webfolder -> login . + + +Step 3: setup the client +------------------------ + +Make sure that you have HTTP support, i.e. your git was built with curl. +The easiest way to check is to look for the executable 'git-http-push'. + +Then, add the following to your $HOME/.netrc (you can do without, but will be +asked to input your password a _lot_ of times): + + machine <servername> + login <username> + password <password> + +...and set permissions: + chmod 600 ~/.netrc + +If you want to access the web-server by its IP, you have to type that in, +instead of the server name. + +To check whether all is OK, do: + + curl --netrc --location -v http://<username>@<servername>/my-new-repo.git/ + +...this should give a directory listing in HTML of /var/www/my-new-repo.git . + + +Now, add the remote in your existing repository which contains the project +you want to export: + + $ git-config remote.upload.url \ + http://<username>@<servername>/my-new-repo.git/ + +It is important to put the last '/'; Without it, the server will send +a redirect which git-http-push does not (yet) understand, and git-http-push +will repeat the request infinitely. + + +Step 4: make the initial push +----------------------------- + +From your client repository, do + + $ git push upload master + +This pushes branch 'master' (which is assumed to be the branch you +want to export) to repository called 'upload', which we previously +defined with git-config. + + +Troubleshooting: +---------------- + +If git-http-push says + + Error: no DAV locking support on remote repo http://... + +then it means the web-server did not accept your authentication. Make sure +that the user name and password matches in httpd.conf, .netrc and the URL +you are uploading to. + +If git-http-push shows you an error (22/502) when trying to MOVE a blob, +it means that your web-server somehow does not recognize its name in the +request; This can happen when you start Apache, but then disable the +network interface. A simple restart of Apache helps. + +Errors like (22/502) are of format (curl error code/http error +code). So (22/404) means something like 'not found' at the server. + +Reading /usr/local/apache2/logs/error_log is often helpful. + + On Debian: Read /var/log/apache2/error.log instead. + + +Debian References: http://www.debian-administration.org/articles/285 + +Authors + Johannes Schindelin <Johannes.Schindelin@gmx.de> + Rutger Nijlunsing <git@wingding.demon.nl> diff --git a/Documentation/howto/update-hook-example.txt b/Documentation/howto/update-hook-example.txt new file mode 100644 index 0000000000..3a33696f00 --- /dev/null +++ b/Documentation/howto/update-hook-example.txt @@ -0,0 +1,172 @@ +From: Junio C Hamano <junkio@cox.net> and Carl Baldwin <cnb@fc.hp.com> +Subject: control access to branches. +Date: Thu, 17 Nov 2005 23:55:32 -0800 +Message-ID: <7vfypumlu3.fsf@assigned-by-dhcp.cox.net> +Abstract: An example hooks/update script is presented to + implement repository maintenance policies, such as who can push + into which branch and who can make a tag. + +When your developer runs git-push into the repository, +git-receive-pack is run (either locally or over ssh) as that +developer, so is hooks/update script. Quoting from the relevant +section of the documentation: + + Before each ref is updated, if $GIT_DIR/hooks/update file exists + and executable, it is called with three parameters: + + $GIT_DIR/hooks/update refname sha1-old sha1-new + + The refname parameter is relative to $GIT_DIR; e.g. for the + master head this is "refs/heads/master". Two sha1 are the + object names for the refname before and after the update. Note + that the hook is called before the refname is updated, so either + sha1-old is 0{40} (meaning there is no such ref yet), or it + should match what is recorded in refname. + +So if your policy is (1) always require fast-forward push +(i.e. never allow "git-push repo +branch:branch"), (2) you +have a list of users allowed to update each branch, and (3) you +do not let tags to be overwritten, then you can use something +like this as your hooks/update script. + +[jc: editorial note. This is a much improved version by Carl +since I posted the original outline] + +-- >8 -- beginning of script -- >8 -- + +#!/bin/bash + +umask 002 + +# If you are having trouble with this access control hook script +# you can try setting this to true. It will tell you exactly +# why a user is being allowed/denied access. + +verbose=false + +# Default shell globbing messes things up downstream +GLOBIGNORE=* + +function grant { + $verbose && echo >&2 "-Grant- $1" + echo grant + exit 0 +} + +function deny { + $verbose && echo >&2 "-Deny- $1" + echo deny + exit 1 +} + +function info { + $verbose && echo >&2 "-Info- $1" +} + +# Implement generic branch and tag policies. +# - Tags should not be updated once created. +# - Branches should only be fast-forwarded. +case "$1" in + refs/tags/*) + [ -f "$GIT_DIR/$1" ] && + deny >/dev/null "You can't overwrite an existing tag" + ;; + refs/heads/*) + # No rebasing or rewinding + if expr "$2" : '0*$' >/dev/null; then + info "The branch '$1' is new..." + else + # updating -- make sure it is a fast forward + mb=$(git-merge-base "$2" "$3") + case "$mb,$2" in + "$2,$mb") info "Update is fast-forward" ;; + *) deny >/dev/null "This is not a fast-forward update." ;; + esac + fi + ;; + *) + deny >/dev/null \ + "Branch is not under refs/heads or refs/tags. What are you trying to do?" + ;; +esac + +# Implement per-branch controls based on username +allowed_users_file=$GIT_DIR/info/allowed-users +username=$(id -u -n) +info "The user is: '$username'" + +if [ -f "$allowed_users_file" ]; then + rc=$(cat $allowed_users_file | grep -v '^#' | grep -v '^$' | + while read head_pattern user_patterns; do + matchlen=$(expr "$1" : "$head_pattern") + if [ "$matchlen" == "${#1}" ]; then + info "Found matching head pattern: '$head_pattern'" + for user_pattern in $user_patterns; do + info "Checking user: '$username' against pattern: '$user_pattern'" + matchlen=$(expr "$username" : "$user_pattern") + if [ "$matchlen" == "${#username}" ]; then + grant "Allowing user: '$username' with pattern: '$user_pattern'" + fi + done + deny "The user is not in the access list for this branch" + fi + done + ) + case "$rc" in + grant) grant >/dev/null "Granting access based on $allowed_users_file" ;; + deny) deny >/dev/null "Denying access based on $allowed_users_file" ;; + *) ;; + esac +fi + +allowed_groups_file=$GIT_DIR/info/allowed-groups +groups=$(id -G -n) +info "The user belongs to the following groups:" +info "'$groups'" + +if [ -f "$allowed_groups_file" ]; then + rc=$(cat $allowed_groups_file | grep -v '^#' | grep -v '^$' | + while read head_pattern group_patterns; do + matchlen=$(expr "$1" : "$head_pattern") + if [ "$matchlen" == "${#1}" ]; then + info "Found matching head pattern: '$head_pattern'" + for group_pattern in $group_patterns; do + for groupname in $groups; do + info "Checking group: '$groupname' against pattern: '$group_pattern'" + matchlen=$(expr "$groupname" : "$group_pattern") + if [ "$matchlen" == "${#groupname}" ]; then + grant "Allowing group: '$groupname' with pattern: '$group_pattern'" + fi + done + done + deny "None of the user's groups are in the access list for this branch" + fi + done + ) + case "$rc" in + grant) grant >/dev/null "Granting access based on $allowed_groups_file" ;; + deny) deny >/dev/null "Denying access based on $allowed_groups_file" ;; + *) ;; + esac +fi + +deny >/dev/null "There are no more rules to check. Denying access" + +-- >8 -- end of script -- >8 -- + +This uses two files, $GIT_DIR/info/allowed-users and +allowed-groups, to describe which heads can be pushed into by +whom. The format of each file would look like this: + + refs/heads/master junio + refs/heads/cogito$ pasky + refs/heads/bw/ linus + refs/heads/tmp/ * + refs/tags/v[0-9]* junio + +With this, Linus can push or create "bw/penguin" or "bw/zebra" +or "bw/panda" branches, Pasky can do only "cogito", and JC can +do master branch and make versioned tags. And anybody can do +tmp/blah branches. + +------------ diff --git a/Documentation/howto/using-topic-branches.txt b/Documentation/howto/using-topic-branches.txt new file mode 100644 index 0000000000..2c98194cb8 --- /dev/null +++ b/Documentation/howto/using-topic-branches.txt @@ -0,0 +1,296 @@ +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?) +Abstract: In this article, Tony Luck discusses how he uses GIT + as a Linux subsystem maintainer. + +Here's something that I've been putting together on how I'm using +GIT as a Linux subsystem maintainer. + +-Tony + +Last updated w.r.t. GIT 1.1 + +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 by 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 git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git work + +Change directory into the cloned tree you just created + + $ cd work + +Set up a remotes file so that you can fetch the latest from Linus' master +branch into a local branch named "linus": + + $ cat > .git/remotes/linus + URL: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git + Pull: master:linus + ^D + +and create the linus branch: + + $ git branch linus + +The "linus" branch will be used to track the upstream kernel. To update it, +you simply run: + + $ git fetch linus + +you can do this frequently (and it should be safe to do so with pending +work in your tree, but perhaps not if you are in mid-merge). + +If you need to keep track of other public trees, you can add remote branches +for them too: + + $ git branch another + $ cat > .git/remotes/another + URL: ... insert URL here ... + Pull: name-of-branch-in-this-remote-tree:another + ^D + +and run: + + $ git fetch 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 merge "Auto-update from upstream" test linus + $ git checkout release && git merge "Auto-update from upstream" release linus + +Important note! If you have any local changes in these branches, then +this merge will create a commit object in the history (with no local +changes git will simply do a "Fast forward" merge). Many people dislike +the "noise" that this creates in the Linux history, so you should avoid +doing this capriciously in the "release" branch, as these noisy commits +will become part of the permanent history when you ask Linus to pull +from the release branch. + +Set up so that you can push upstream to your public tree (you need to +log-in to the remote system and create an empty tree there before the +first push). + + $ cat > .git/remotes/mytree + URL: master.kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git + Push: release + Push: test + ^D + +and the push both the test and release trees using: + + $ git push mytree + +or push just one of the test and release branches using: + + $ git push mytree test +or + $ git push mytree 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 merge "Pull speed-up-spinlock changes" test speed-up-spinlocks + +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 merge "Pull speed-up-spinlock changes" release speed-up-spinlocks + +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: + + $ git branch -d 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 merge "Auto-update from upstream" $1 linus + ;; +linus) + before=$(cat .git/refs/heads/linus) + git fetch linus + after=$(cat .git/refs/heads/linus) + 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 merge "Pull $1 into $2 branch" $2 $1 + ;; +*) + 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-list 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-list $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 |