diff options
Diffstat (limited to 'Documentation/howto')
-rw-r--r-- | Documentation/howto/rebase-and-edit.txt | 79 | ||||
-rw-r--r-- | Documentation/howto/rebase-from-internal-branch.txt | 163 | ||||
-rw-r--r-- | Documentation/howto/rebuild-from-update-hook.txt | 86 | ||||
-rw-r--r-- | Documentation/howto/revert-branch-rebase.txt | 193 | ||||
-rw-r--r-- | Documentation/howto/separating-topic-branches.txt | 90 | ||||
-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/use-git-daemon.txt | 51 |
8 files changed, 1090 insertions, 0 deletions
diff --git a/Documentation/howto/rebase-and-edit.txt b/Documentation/howto/rebase-and-edit.txt new file mode 100644 index 0000000000..554909fe08 --- /dev/null +++ b/Documentation/howto/rebase-and-edit.txt @@ -0,0 +1,79 @@ +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..7a76045eb7 --- /dev/null +++ b/Documentation/howto/rebase-from-internal-branch.txt @@ -0,0 +1,163 @@ +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..8d55dfbfae --- /dev/null +++ b/Documentation/howto/rebuild-from-update-hook.txt @@ -0,0 +1,86 @@ +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..865a666324 --- /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..0d73b31224 --- /dev/null +++ b/Documentation/howto/separating-topic-branches.txt @@ -0,0 +1,90 @@ +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/use-git-daemon.txt b/Documentation/howto/use-git-daemon.txt new file mode 100644 index 0000000000..4e2f75cb61 --- /dev/null +++ b/Documentation/howto/use-git-daemon.txt @@ -0,0 +1,51 @@ +How to use git-daemon + +Git can be run in inetd mode and in stand alone mode. But all you want is +let a coworker pull from you, and therefore need to set up a git server +real quick, right? + +Note that git-daemon is not really chatty at the moment, especially when +things do not go according to plan (e.g. a socket could not be bound). + +Another word of warning: if you run + + $ git ls-remote git://127.0.0.1/rule-the-world.git + +and you see a message like + + fatal: The remote end hung up unexpectedly + +it only means that _something_ went wrong. To find out _what_ went wrong, +you have to ask the server. (Git refuses to be more precise for your +security only. Take off your shoes now. You have any coins in your pockets? +Sorry, not allowed -- who knows what you planned to do with them?) + +With these two caveats, let's see an example: + + $ git daemon --reuseaddr --verbose --base-path=/home/gitte/git \ + --export-all -- /home/gitte/git/rule-the-world.git + +(Of course, unless your user name is `gitte` _and_ your repository is in +~/rule-the-world.git, you have to adjust the paths. If your repository is +not bare, be aware that you have to type the path to the .git directory!) + +This invocation tries to reuse the address if it is already taken +(this can save you some debugging, because otherwise killing and restarting +git-daemon could just silently fail to bind to a socket). + +Also, it is (relatively) verbose when somebody actually connects to it. +It also sets the base path, which means that all the projects which can be +accessed using this daemon have to reside in or under that path. + +The option `--export-all` just means that you _don't_ have to create a +file named `git-daemon-export-ok` in each exported repository. (Otherwise, +git-daemon would complain loudly, and refuse to cooperate.) + +Last of all, the repository which should be exported is specified. It is +a good practice to put the paths after a "--" separator. + +Now, test your daemon with + + $ git ls-remote git://127.0.0.1/rule-the-world.git + +If this does not work, find out why, and submit a patch to this document. |