diff options
Diffstat (limited to 'Documentation/howto')
-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 | 83 | ||||
-rw-r--r-- | Documentation/howto/revert-branch-rebase.txt | 200 | ||||
-rw-r--r-- | Documentation/howto/update-hook-example.txt | 105 | ||||
-rw-r--r-- | Documentation/howto/using-topic-branches.txt | 288 |
8 files changed, 1039 insertions, 0 deletions
diff --git a/Documentation/howto/isolate-bugs-with-bisect.txt b/Documentation/howto/isolate-bugs-with-bisect.txt new file mode 100644 index 0000000000..400949564d --- /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 laste) + +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 bew "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..c2d4a91c7c --- /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.txt and 0002-XXXX.txt. 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 upsteam +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..ebd025db85 --- /dev/null +++ b/Documentation/howto/rebuild-from-update-hook.txt @@ -0,0 +1,83 @@ +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 master.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 three 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. + + - 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..5a7e0cfe05 --- /dev/null +++ b/Documentation/howto/revert-branch-rebase.txt @@ -0,0 +1,200 @@ +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 resolve master revert-c99 fast ;# 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(-) +------------------------------------------------ + +The 'fast' in the above 'git resolve' is not a magic. I knew this +'resolve' would result in a fast forward merge, and if not, there is +something very wrong (so I would do 'git reset' on the 'master' branch +and examine the situation). When a fast forward merge is done, the +message parameter to 'git resolve' is discarded, because no new commit +is created. You could have said 'junk' or 'nothing' there as well. + +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/update-hook-example.txt b/Documentation/howto/update-hook-example.txt new file mode 100644 index 0000000000..dacaf17c2e --- /dev/null +++ b/Documentation/howto/update-hook-example.txt @@ -0,0 +1,105 @@ +From: Junio C Hamano <junkio@cox.net> +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: + + #!/bin/sh + # This is a sample hooks/update script, written by JC + # in his e-mail buffer, so naturally it is not tested + # but hopefully would convey the idea. + + umask 002 + case "$1" in + refs/tags/*) + # No overwriting an existing tag + if test -f "$GIT_DIR/$1" + then + exit 1 + fi + ;; + refs/heads/*) + # No rebasing or rewinding + if expr "$2" : '0*$' >/dev/null + then + # creating a new branch + ; + else + # updating -- make sure it is a fast forward + mb=`git-merge-base "$2" "$3"` + case "$mb,$2" in + "$2,$mb") + ;; # fast forward -- happy + *) + exit 1 ;; # unhappy + esac + fi + ;; + *) + # No funny refs allowed + exit 1 + ;; + esac + + # Is the user allowed to update it? + me=`id -u -n` ;# e.g. "junio" + while read head_pattern users + do + if expr "$1" : "$head_pattern" >/dev/null + then + case " $users " in + *" $me "*) + exit 0 ;; # happy + ' * ') + exit 0 ;; # anybody + esac + fi + done + exit 1 + +For the sake of simplicity, I assumed that you keep something +like this in $GIT_DIR/info/allowed-pushers file: + + 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 I can do +master branch and make versioned tags. And anybody can do +tmp/blah branches. This assumes all the users are in a single +group that can write into $GIT_DIR/ and underneath. + + + + + + + + diff --git a/Documentation/howto/using-topic-branches.txt b/Documentation/howto/using-topic-branches.txt new file mode 100644 index 0000000000..4698abe46b --- /dev/null +++ b/Documentation/howto/using-topic-branches.txt @@ -0,0 +1,288 @@ +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 0.99.9f + +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 + +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: rsync://rsync.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 + +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 |