Merge branch 'rs/pretty'
authorJunio C Hamano <gitster@pobox.com>
Wed, 14 Nov 2007 22:03:50 +0000 (14:03 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 14 Nov 2007 22:03:50 +0000 (14:03 -0800)
* rs/pretty:
Fix preprocessor logic that determines the availablity of strchrnul().
Simplify strchrnul() compat code
--format=pretty: avoid calculating expensive expansions twice
add strbuf_adddup()
--pretty=format: parse commit message only once
--pretty=format: on-demand format expansion
Add strchrnul()

51 files changed:
Documentation/Makefile
Documentation/asciidoc.conf
Documentation/cmd-list.perl
Documentation/core-tutorial.txt
Documentation/git-add.txt
Documentation/git-branch.txt
Documentation/git-commit.txt
Documentation/git-cvsexportcommit.txt
Documentation/git-get-tar-commit-id.txt
Documentation/git-local-fetch.txt [deleted file]
Documentation/git-push.txt
Documentation/git-remote.txt
Documentation/git-ssh-fetch.txt [deleted file]
Documentation/git-ssh-upload.txt [deleted file]
Documentation/gitattributes.txt
Documentation/howto/recover-corrupted-blob-object.txt [new file with mode: 0644]
Documentation/user-manual.txt
Makefile
builtin-blame.c
builtin-for-each-ref.c
builtin-push.c
builtin-reset.c
builtin-revert.c
fast-import.c
git-clean.sh
git-cvsexportcommit.perl
git-cvsimport.perl
git-svn.perl
gitweb/gitweb.perl
hash-object.c
index-pack.c
list-objects.c
parse-options.c
setup.c
strbuf.c
t/t0040-parse-options.sh
t/t3404-rebase-interactive.sh
t/t5530-upload-pack-error.sh [new file with mode: 0755]
t/t6300-for-each-ref.sh
t/t7102-reset.sh
t/t7300-clean.sh
t/t7501-commit.sh
t/t9106-git-svn-dcommit-clobber-series.sh
t/t9118-git-svn-funky-branch-names.sh [new file with mode: 0755]
t/test-lib.sh
test-parse-options.c
trace.c
transport.c
transport.h
upload-pack.c
usage.c
index 39ec0ede0249da79be574d85e731f8a7b239d9db..d88664177da52ef92c25959ba396b4b823859225 100644 (file)
@@ -37,9 +37,6 @@ man7dir=$(mandir)/man7
 
 ASCIIDOC=asciidoc
 ASCIIDOC_EXTRA =
-ifdef ASCIIDOC8
-ASCIIDOC_EXTRA += -a asciidoc7compatible
-endif
 INSTALL?=install
 RM ?= rm -f
 DOC_REF = origin/man
@@ -52,6 +49,13 @@ DOCBOOK2X_TEXI=docbook2x-texi
 -include ../config.mak.autogen
 -include ../config.mak
 
+ifdef ASCIIDOC8
+ASCIIDOC_EXTRA += -a asciidoc7compatible
+endif
+ifdef DOCBOOK_XSL_172
+ASCIIDOC_EXTRA += -a docbook-xsl-172
+endif
+
 #
 # Please note that there is a minor bug in asciidoc.
 # The version after 6.0.3 _will_ include the patch found here:
index af5b1558a63219a3eac2570e1cecc97e3008f96f..99d8874aa0a97597507cbd6864df4113c00d4cf7 100644 (file)
@@ -23,7 +23,9 @@ ifdef::backend-docbook[]
 endif::backend-docbook[]
 
 ifdef::backend-docbook[]
+ifndef::docbook-xsl-172[]
 # "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this.
+# v1.72 breaks with this because it replaces dots not in roff requests.
 [listingblock]
 <example><title>{title}</title>
 <literallayout>
@@ -36,6 +38,7 @@ ifdef::doctype-manpage[]
 endif::doctype-manpage[]
 </literallayout>
 {title#}</example>
+endif::docbook-xsl-172[]
 endif::backend-docbook[]
 
 ifdef::doctype-manpage[]
index 8d21d423e5ef777d19369d6d1988f10cb8922fb8..57a790df63b884b5ece790422bedacaab0a4ba3b 100755 (executable)
@@ -3,7 +3,8 @@
 use File::Compare qw(compare);
 
 sub format_one {
-       my ($out, $name) = @_;
+       my ($out, $nameattr) = @_;
+       my ($name, $attr) = @$nameattr;
        my ($state, $description);
        $state = 0;
        open I, '<', "$name.txt" or die "No such file $name.txt";
@@ -26,8 +27,11 @@ sub format_one {
                die "No description found in $name.txt";
        }
        if (my ($verify_name, $text) = ($description =~ /^($name) - (.*)/)) {
-               print $out "gitlink:$name\[1\]::\n";
-               print $out "\t$text.\n\n";
+               print $out "gitlink:$name\[1\]::\n\t";
+               if ($attr) {
+                       print $out "($attr) ";
+               }
+               print $out "$text.\n\n";
        }
        else {
                die "Description does not match $name: $description";
@@ -39,8 +43,8 @@ sub format_one {
        next if /^#/;
 
        chomp;
-       my ($name, $cat) = /^(\S+)\s+(.*)$/;
-       push @{$cmds{$cat}}, $name;
+       my ($name, $cat, $attr) = /^(\S+)\s+(.*?)(?:\s+(.*))?$/;
+       push @{$cmds{$cat}}, [$name, $attr];
 }
 
 for my $cat (qw(ancillaryinterrogators
@@ -124,9 +128,8 @@ sub format_one {
 git-init                                mainporcelain
 git-instaweb                            ancillaryinterrogators
 gitk                                    mainporcelain
-git-local-fetch                         synchingrepositories
 git-log                                 mainporcelain
-git-lost-found                          ancillarymanipulators
+git-lost-found                          ancillarymanipulators  deprecated
 git-ls-files                            plumbinginterrogators
 git-ls-remote                           plumbinginterrogators
 git-ls-tree                             plumbinginterrogators
@@ -178,8 +181,6 @@ sub format_one {
 git-show-index                          plumbinginterrogators
 git-show-ref                            plumbinginterrogators
 git-sh-setup                            purehelpers
-git-ssh-fetch                           synchingrepositories
-git-ssh-upload                          synchingrepositories
 git-stash                               mainporcelain
 git-status                              mainporcelain
 git-stripspace                          purehelpers
@@ -187,7 +188,7 @@ sub format_one {
 git-svn                                 foreignscminterface
 git-symbolic-ref                        plumbingmanipulators
 git-tag                                 mainporcelain
-git-tar-tree                            plumbinginterrogators
+git-tar-tree                            plumbinginterrogators  deprecated
 git-unpack-file                         plumbinginterrogators
 git-unpack-objects                      plumbingmanipulators
 git-update-index                        plumbingmanipulators
index 99817c53375e6f58b7a3e089cd81e3af5aaffc79..bd6cd4124546a867c029a0c14b16f1944f9eca88 100644 (file)
@@ -931,12 +931,13 @@ Another useful tool, especially if you do not always work in X-Window
 environment, is `git show-branch`.
 
 ------------------------------------------------
-$ git show-branch --topo-order master mybranch
+$ git-show-branch --topo-order --more=1 master mybranch
 * [master] Merge work in mybranch
  ! [mybranch] Some work.
 --
 -  [master] Merge work in mybranch
 *+ [mybranch] Some work.
+*  [master^] Some fun.
 ------------------------------------------------
 
 The first two lines indicate that it is showing the two branches
@@ -954,10 +955,22 @@ because `mybranch` has not been merged to incorporate these
 commits from the master branch.  The string inside brackets
 before the commit log message is a short name you can use to
 name the commit.  In the above example, 'master' and 'mybranch'
-are branch heads.  'master~1' is the first parent of 'master'
+are branch heads.  'master^' is the first parent of 'master'
 branch head.  Please see 'git-rev-parse' documentation if you
 see more complex cases.
 
+[NOTE]
+Without the '--more=1' option, 'git-show-branch' would not output the
+'[master^]' commit, as '[mybranch]' commit is a common ancestor of
+both 'master' and 'mybranch' tips.  Please see 'git-show-branch'
+documentation for details.
+
+[NOTE]
+If there were more commits on the 'master' branch after the merge, the
+merge commit itself would not be shown by 'git-show-branch' by
+default.  You would need to provide '--sparse' option to make the
+merge commit visible in this case.
+
 Now, let's pretend you are the one who did all the work in
 `mybranch`, and the fruit of your hard work has finally been merged
 to the `master` branch. Let's go back to `mybranch`, and run
@@ -1077,11 +1090,6 @@ server like git Native transport does.  Any stock HTTP server
 that does not even support directory index would suffice.  But
 you must prepare your repository with `git-update-server-info`
 to help dumb transport downloaders.
-+
-There are (confusingly enough) `git-ssh-fetch` and `git-ssh-upload`
-programs, which are 'commit walkers'; they outlived their
-usefulness when git Native and SSH transports were introduced,
-and are not used by `git pull` or `git push` scripts.
 
 Once you fetch from the remote repository, you `merge` that
 with your current branch.
@@ -1144,7 +1152,7 @@ back to the earlier repository with "hello" and "example" file,
 and bring ourselves back to the pre-merge state:
 
 ------------
-$ git show-branch --more=3 master mybranch
+$ git show-branch --more=2 master mybranch
 ! [master] Merge work in mybranch
  * [mybranch] Merge work in mybranch
 --
@@ -1207,7 +1215,7 @@ $ git-read-tree -m -u $mb HEAD mybranch
 This is the same `git-read-tree` command we have already seen,
 but it takes three trees, unlike previous examples.  This reads
 the contents of each tree into different 'stage' in the index
-file (the first tree goes to stage 1, the second stage 2,
+file (the first tree goes to stage 1, the second to stage 2,
 etc.).  After reading three trees into three stages, the paths
 that are the same in all three stages are 'collapsed' into stage
 0.  Also paths that are the same in two of three stages are
index 963e1ab1e2b7437a32f0aff97dda8dae3c4f47a0..63829d93cc827255355aa07a7db061b1a3a9e4d9 100644 (file)
@@ -224,6 +224,7 @@ See Also
 --------
 gitlink:git-status[1]
 gitlink:git-rm[1]
+gitlink:git-reset[1]
 gitlink:git-mv[1]
 gitlink:git-commit[1]
 gitlink:git-update-index[1]
index 5e81aa4ee15af50bd47aa9b26ffd566328f3c35e..5ce905de862253aa2bd2ed619819306165e978f0 100644 (file)
@@ -105,7 +105,7 @@ OPTIONS
        '--track' were given.
 
 --no-track::
-       When -b is given and a branch is created off a remote branch,
+       When a branch is created off a remote branch,
        set up configuration so that git-pull will not retrieve data
        from the remote branch, ignoring the branch.autosetupmerge
        configuration variable.
index e54fb12103d4e4955f41532566cb4558432a97bb..d4bfd49ce12ebe8f7b172d6f682d64ccbce66087 100644 (file)
@@ -154,10 +154,13 @@ EXAMPLES
 --------
 When recording your own work, the contents of modified files in
 your working tree are temporarily stored to a staging area
-called the "index" with gitlink:git-add[1].  Removal
-of a file is staged with gitlink:git-rm[1].  After building the
-state to be committed incrementally with these commands, `git
-commit` (without any pathname parameter) is used to record what
+called the "index" with gitlink:git-add[1].  A file can be
+reverted back, only in the index but not in the working tree,
+to that of the last commit with `git-reset HEAD -- <file>`,
+which effectively reverts `git-add` and prevents the changes to
+this file from participating in the next commit.  After building
+the state to be committed incrementally with these commands,
+`git commit` (without any pathname parameter) is used to record what
 has been staged so far.  This is the most basic form of the
 command.  An example:
 
index c3922f9238cf9f33d404665714fb0458122b6e43..3f9d2295d38b4728929764b0adcbdf5785167f75 100644 (file)
@@ -8,7 +8,7 @@ git-cvsexportcommit - Export a single commit to a CVS checkout
 
 SYNOPSIS
 --------
-'git-cvsexportcommit' [-h] [-u] [-v] [-c] [-P] [-p] [-a] [-d cvsroot] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
+'git-cvsexportcommit' [-h] [-u] [-v] [-c] [-P] [-p] [-a] [-d cvsroot] [-w cvsworkdir] [-f] [-m msgprefix] [PARENTCOMMIT] COMMITID
 
 
 DESCRIPTION
@@ -16,8 +16,9 @@ DESCRIPTION
 Exports a commit from GIT to a CVS checkout, making it easier
 to merge patches from a git repository into a CVS repository.
 
-Execute it from the root of the CVS working copy. GIT_DIR must be defined.
-See examples below.
+Specify the name of a CVS checkout using the -w switch or execute it
+from the root of the CVS working copy. In the latter case GIT_DIR must
+be defined. See examples below.
 
 It does its best to do the safe thing, it will check that the files are
 unchanged and up to date in the CVS checkout, and it will not autocommit
@@ -61,6 +62,11 @@ OPTIONS
 -u::
        Update affected files from CVS repository before attempting export.
 
+-w::
+       Specify the location of the CVS checkout to use for the export. This
+       option does not require GIT_DIR to be set before execution if the
+       current directory is within a git repository.
+
 -v::
        Verbose.
 
@@ -76,6 +82,12 @@ $ git-cvsexportcommit -v <commit-sha1>
 $ cvs commit -F .msg <files>
 ------------
 
+Merge one patch into CVS (-c and -w options). The working directory is within the Git Repo::
++
+------------
+       $ git-cvsexportcommit -v -c -w ~/project_cvs_checkout <commit-sha1>
+------------
+
 Merge pending patches into CVS automatically -- only if you really know what you are doing::
 +
 ------------
@@ -86,11 +98,11 @@ $ git-cherry cvshead myhead | sed -n 's/^+ //p' | xargs -l1 git-cvsexportcommit
 
 Author
 ------
-Written by Martin Langhoff <martin@catalyst.net.nz>
+Written by Martin Langhoff <martin@catalyst.net.nz> and others.
 
 Documentation
 --------------
-Documentation by Martin Langhoff <martin@catalyst.net.nz>
+Documentation by Martin Langhoff <martin@catalyst.net.nz> and others.
 
 GIT
 ---
index 9b5f86fc30aecc5e1183e514d5d0f81d14a751c3..76316bbc9e3265dc9e5dca7562b7c79357c77931 100644 (file)
@@ -14,12 +14,12 @@ SYNOPSIS
 DESCRIPTION
 -----------
 Acts as a filter, extracting the commit ID stored in archives created by
-git-tar-tree.  It reads only the first 1024 bytes of input, thus its
+gitlink:git-archive[1].  It reads only the first 1024 bytes of input, thus its
 runtime is not influenced by the size of <tarfile> very much.
 
 If no commit ID is found, git-get-tar-commit-id quietly exists with a
 return code of 1.  This can happen if <tarfile> had not been created
-using git-tar-tree or if the first parameter of git-tar-tree had been
+using git-archive or if the <treeish> parameter of git-archive had been
 a tree ID instead of a commit ID or tag.
 
 
diff --git a/Documentation/git-local-fetch.txt b/Documentation/git-local-fetch.txt
deleted file mode 100644 (file)
index e830dee..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-git-local-fetch(1)
-==================
-
-NAME
-----
-git-local-fetch - Duplicate another git repository on a local system
-
-
-SYNOPSIS
---------
-[verse]
-'git-local-fetch' [-c] [-t] [-a] [-d] [-v] [-w filename] [--recover] [-l] [-s] [-n]
-                  commit-id path
-
-DESCRIPTION
------------
-THIS COMMAND IS DEPRECATED.
-
-Duplicates another git repository on a local system.
-
-OPTIONS
--------
--c::
-       Get the commit objects.
--t::
-       Get trees associated with the commit objects.
--a::
-       Get all the objects.
--v::
-       Report what is downloaded.
--s::
-       Instead of regular file-to-file copying use symbolic links to the objects
-       in the remote repository.
--l::
-       Before attempting symlinks (if -s is specified) or file-to-file copying the
-       remote objects, try to hardlink the remote objects into the local
-       repository.
--n::
-       Never attempt to file-to-file copy remote objects.  Only useful with
-       -s or -l command-line options.
-
--w <filename>::
-        Writes the commit-id into the filename under $GIT_DIR/refs/<filename> on
-        the local end after the transfer is complete.
-
---stdin::
-       Instead of a commit id on the command line (which is not expected in this
-       case), 'git-local-fetch' expects lines on stdin in the format
-
-               <commit-id>['\t'<filename-as-in--w>]
-
---recover::
-       Verify that everything reachable from target is fetched.  Used after
-       an earlier fetch is interrupted.
-
-Author
-------
-Written by Junio C Hamano <junkio@cox.net>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
-GIT
----
-Part of the gitlink:git[7] suite
index e5dd4c10662230622299d0a4b2bb2850071be7d8..4a68aaba342bd1155beb2ae72fd81c701e6c80eb 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 --------
 [verse]
 'git-push' [--all] [--dry-run] [--tags] [--receive-pack=<git-receive-pack>]
-           [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]
+           [--repo=all] [-f | --force] [-v | --verbose] [<repository> <refspec>...]
 
 DESCRIPTION
 -----------
@@ -95,7 +95,7 @@ the remote repository.
        transfer spends extra cycles to minimize the number of
        objects to be sent and meant to be used on slower connection.
 
--v::
+-v, \--verbose::
        Run verbosely.
 
 include::urls-remotes.txt[]
index 027ba11bdb67ba540b63ec12e5a6b920cd2e5f7e..0da8704a25f7010d84008396ab1bb0be5b4a4da1 100644 (file)
@@ -79,7 +79,7 @@ caution.
 Fetch updates for a named set of remotes in the repository as defined by
 remotes.<group>.  If a named group is not specified on the command line,
 the configuration parameter remotes.default will get used; if
-remotes.default is not defined, all remotes which do not the
+remotes.default is not defined, all remotes which do not have the
 configuration parameter remote.<name>.skipDefaultUpdate set to true will
 be updated.  (See gitlink:git-config[1]).
 
diff --git a/Documentation/git-ssh-fetch.txt b/Documentation/git-ssh-fetch.txt
deleted file mode 100644 (file)
index 8d3e2ff..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-git-ssh-fetch(1)
-================
-
-NAME
-----
-git-ssh-fetch - Fetch from a remote repository over ssh connection
-
-
-
-SYNOPSIS
---------
-'git-ssh-fetch' [-c] [-t] [-a] [-d] [-v] [-w filename] [--recover] commit-id url
-
-DESCRIPTION
------------
-THIS COMMAND IS DEPRECATED.
-
-Pulls from a remote repository over ssh connection, invoking
-git-ssh-upload on the other end. It functions identically to
-git-ssh-upload, aside from which end you run it on.
-
-
-OPTIONS
--------
-commit-id::
-        Either the hash or the filename under [URL]/refs/ to
-        pull.
-
--c::
-       Get the commit objects.
--t::
-       Get trees associated with the commit objects.
--a::
-       Get all the objects.
--v::
-       Report what is downloaded.
--w::
-        Writes the commit-id into the filename under $GIT_DIR/refs/ on
-        the local end after the transfer is complete.
-
-
-Author
-------
-Written by Daniel Barkalow <barkalow@iabervon.org>
-
-Documentation
---------------
-Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
-
-GIT
----
-Part of the gitlink:git[7] suite
diff --git a/Documentation/git-ssh-upload.txt b/Documentation/git-ssh-upload.txt
deleted file mode 100644 (file)
index 5e2ca8d..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-git-ssh-upload(1)
-=================
-
-NAME
-----
-git-ssh-upload - Push to a remote repository over ssh connection
-
-
-SYNOPSIS
---------
-'git-ssh-upload' [-c] [-t] [-a] [-d] [-v] [-w filename] [--recover] commit-id url
-
-DESCRIPTION
------------
-THIS COMMAND IS DEPRECATED.
-
-Pushes from a remote repository over ssh connection, invoking
-git-ssh-fetch on the other end. It functions identically to
-git-ssh-fetch, aside from which end you run it on.
-
-OPTIONS
--------
-commit-id::
-        Id of commit to push.
-
--c::
-        Get the commit objects.
--t::
-        Get tree associated with the requested commit object.
--a::
-        Get all the objects.
--v::
-        Report what is uploaded.
--w::
-        Writes the commit-id into the filename under [URL]/refs/ on
-        the remote end after the transfer is complete.
-
-Author
-------
-Written by Daniel Barkalow <barkalow@iabervon.org>
-
-Documentation
---------------
-Documentation by Daniel Barkalow
-
-GIT
----
-Part of the gitlink:git[7] suite
index 20cf8ff81673265629028b49c34e0393063fd6b1..19bd25f29900c99d78592fe290772856092e2dc5 100644 (file)
@@ -148,22 +148,23 @@ with `$Id$` upon check-in.
 `filter`
 ^^^^^^^^
 
-A `filter` attribute can be set to a string value.  This names
+A `filter` attribute can be set to a string value that names a
 filter driver specified in the configuration.
 
-A filter driver consists of `clean` command and `smudge`
+A filter driver consists of a `clean` command and a `smudge`
 command, either of which can be left unspecified.  Upon
-checkout, when `smudge` command is specified, the command is fed
-the blob object from its standard input, and its standard output
-is used to update the worktree file.  Similarly, `clean` command
-is used to convert the contents of worktree file upon checkin.
+checkout, when the `smudge` command is specified, the command is
+fed the blob object from its standard input, and its standard
+output is used to update the worktree file.  Similarly, the
+`clean` command is used to convert the contents of worktree file
+upon checkin.
 
-Missing filter driver definition in the config is not an error
+A missing filter driver definition in the config is not an error
 but makes the filter a no-op passthru.
 
 The content filtering is done to massage the content into a
 shape that is more convenient for the platform, filesystem, and
-the user to use.  The keyword here is "more convenient" and not
+the user to use.  The key phrase here is "more convenient" and not
 "turning something unusable into usable".  In other words, the
 intent is that if someone unsets the filter driver definition,
 or does not have the appropriate filter program, the project
diff --git a/Documentation/howto/recover-corrupted-blob-object.txt b/Documentation/howto/recover-corrupted-blob-object.txt
new file mode 100644 (file)
index 0000000..323b513
--- /dev/null
@@ -0,0 +1,134 @@
+Date: Fri, 9 Nov 2007 08:28:38 -0800 (PST)
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Subject: corrupt object on git-gc
+Abstract: Some tricks to reconstruct blob objects in order to fix
+ a corrupted repository.
+
+On Fri, 9 Nov 2007, Yossi Leybovich wrote:
+>
+> Did not help still the repository look for this object?
+> Any one know how can I track this object and understand which file is it
+
+So exactly *because* the SHA1 hash is cryptographically secure, the hash
+itself doesn't actually tell you anything, in order to fix a corrupt
+object you basically have to find the "original source" for it.
+
+The easiest way to do that is almost always to have backups, and find the
+same object somewhere else. Backups really are a good idea, and git makes
+it pretty easy (if nothing else, just clone the repository somewhere else,
+and make sure that you do *not* use a hard-linked clone, and preferably
+not the same disk/machine).
+
+But since you don't seem to have backups right now, the good news is that
+especially with a single blob being corrupt, these things *are* somewhat
+debuggable.
+
+First off, move the corrupt object away, and *save* it. The most common
+cause of corruption so far has been memory corruption, but even so, there
+are people who would be interested in seeing the corruption - but it's
+basically impossible to judge the corruption until we can also see the
+original object, so right now the corrupt object is useless, but it's very
+interesting for the future, in the hope that you can re-create a
+non-corrupt version.
+
+So:
+
+> ib]$ mv .git/objects/4b/9458b3786228369c63936db65827de3cc06200 ../
+
+This is the right thing to do, although it's usually best to save it under
+it's full SHA1 name (you just dropped the "4b" from the result ;).
+
+Let's see what that tells us:
+
+> ib]$ git-fsck --full
+> broken link from    tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8
+>              to    blob 4b9458b3786228369c63936db65827de3cc06200
+> missing blob 4b9458b3786228369c63936db65827de3cc06200
+
+Ok, I removed the "dangling commit" messages, because they are just
+messages about the fact that you probably have rebased etc, so they're not
+at all interesting. But what remains is still very useful. In particular,
+we now know which tree points to it!
+
+Now you can do
+
+       git ls-tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8
+
+which will show something like
+
+       100644 blob 8d14531846b95bfa3564b58ccfb7913a034323b8    .gitignore
+       100644 blob ebf9bf84da0aab5ed944264a5db2a65fe3a3e883    .mailmap
+       100644 blob ca442d313d86dc67e0a2e5d584b465bd382cbf5c    COPYING
+       100644 blob ee909f2cc49e54f0799a4739d24c4cb9151ae453    CREDITS
+       040000 tree 0f5f709c17ad89e72bdbbef6ea221c69807009f6    Documentation
+       100644 blob 1570d248ad9237e4fa6e4d079336b9da62d9ba32    Kbuild
+       100644 blob 1c7c229a092665b11cd46a25dbd40feeb31661d9    MAINTAINERS
+       ...
+
+and you should now have a line that looks like
+
+       10064 blob 4b9458b3786228369c63936db65827de3cc06200     my-magic-file
+
+in the output. This already tells you a *lot* it tells you what file the
+corrupt blob came from!
+
+Now, it doesn't tell you quite enough, though: it doesn't tell what
+*version* of the file didn't get correctly written! You might be really
+lucky, and it may be the version that you already have checked out in your
+working tree, in which case fixing this problem is really simple, just do
+
+       git hash-object -w my-magic-file
+
+again, and if it outputs the missing SHA1 (4b945..) you're now all done!
+
+But that's the really lucky case, so let's assume that it was some older
+version that was broken. How do you tell which version it was?
+
+The easiest way to do it is to do
+
+       git log --raw --all --full-history -- subdirectory/my-magic-file
+
+and that will show you the whole log for that file (please realize that
+the tree you had may not be the top-level tree, so you need to figure out
+which subdirectory it was in on your own), and because you're asking for
+raw output, you'll now get something like
+
+       commit abc
+       Author:
+       Date:
+         ..
+       :100644 100644 4b9458b... newsha... M  somedirectory/my-magic-file
+
+
+       commit xyz
+       Author:
+       Date:
+
+         ..
+       :100644 100644 oldsha... 4b9458b... M   somedirectory/my-magic-file
+
+and this actually tells you what the *previous* and *subsequent* versions
+of that file were! So now you can look at those ("oldsha" and "newsha"
+respectively), and hopefully you have done commits often, and can
+re-create the missing my-magic-file version by looking at those older and
+newer versions!
+
+If you can do that, you can now recreate the missing object with
+
+       git hash-object -w <recreated-file>
+
+and your repository is good again!
+
+(Btw, you could have ignored the fsck, and started with doing a
+
+       git log --raw --all
+
+and just looked for the sha of the missing object (4b9458b..) in that
+whole thing. It's up to you - git does *have* a lot of information, it is
+just missing one particular blob version.
+
+Trying to recreate trees and especially commits is *much* harder. So you
+were lucky that it's a blob. It's quite possible that you can recreate the
+thing.
+
+                       Linus
index d99adc6f728aebfa0b7e4b956c4f784e3d2f7bd4..c7cfbbccfc941db891ce855c30a55e0f28de87c0 100644 (file)
@@ -475,7 +475,7 @@ Bisecting: 3537 revisions left to test after this
 If you run "git branch" at this point, you'll see that git has
 temporarily moved you to a new branch named "bisect".  This branch
 points to a commit (with commit id 65934...) that is reachable from
-v2.6.19 but not from v2.6.18.  Compile and test it, and see whether
+"master" but not from v2.6.18.  Compile and test it, and see whether
 it crashes.  Assume it does crash.  Then:
 
 -------------------------------------------------
@@ -1367,7 +1367,7 @@ If you make a commit that you later wish you hadn't, there are two
 fundamentally different ways to fix the problem:
 
        1. You can create a new commit that undoes whatever was done
-       by the previous commit.  This is the correct thing if your
+       by the old commit.  This is the correct thing if your
        mistake has already been made public.
 
        2. You can go back and modify the old commit.  You should
@@ -1568,7 +1568,7 @@ $ git log master@{1}
 -------------------------------------------------
 
 This lists the commits reachable from the previous version of the head.
-This syntax can be used to with any git command that accepts a commit,
+This syntax can be used with any git command that accepts a commit,
 not just with git log.  Some other examples:
 
 -------------------------------------------------
index 621270f6235306dcdd9c55ac371c90cb5b5effc3..e830bc7445c5753b29b6bb329ec8d977557df97b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -115,6 +115,8 @@ all::
 #
 # Define ASCIIDOC8 if you want to format documentation with AsciiDoc 8
 #
+# Define DOCBOOK_XSL_172 if you want to format man pages with DocBook XSL v1.72.
+#
 # Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's
 # MakeMaker (e.g. using ActiveState under Cygwin).
 #
@@ -998,6 +1000,8 @@ test-date$X: date.o ctype.o
 
 test-delta$X: diff-delta.o patch-delta.o
 
+test-parse-options$X: parse-options.o
+
 .PRECIOUS: $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
 
 test-%$X: test-%.o $(GITLIBS)
@@ -1126,12 +1130,13 @@ endif
 ### Check documentation
 #
 check-docs::
-       @for v in $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk; \
+       @(for v in $(ALL_PROGRAMS) $(BUILT_INS) git gitk; \
        do \
                case "$$v" in \
                git-merge-octopus | git-merge-ours | git-merge-recursive | \
-               git-merge-resolve | git-merge-stupid | \
+               git-merge-resolve | git-merge-stupid | git-merge-subtree | \
                git-add--interactive | git-fsck-objects | git-init-db | \
+               git-rebase--interactive | \
                git-repo-config | git-fetch--tool ) continue ;; \
                esac ; \
                test -f "Documentation/$$v.txt" || \
@@ -1142,7 +1147,30 @@ check-docs::
                git) ;; \
                *) echo "no link: $$v";; \
                esac ; \
-       done | sort
+       done; \
+       ( \
+               sed -e '1,/^__DATA__/d' \
+                   -e 's/[     ].*//' \
+                   -e 's/^/listed /' Documentation/cmd-list.perl; \
+               ls -1 Documentation/git*txt | \
+               sed -e 's|Documentation/|documented |' \
+                   -e 's/\.txt//'; \
+       ) | while read how cmd; \
+       do \
+               case "$$how,$$cmd" in \
+               *,git-citool | \
+               *,git-gui | \
+               documented,gitattributes | \
+               documented,gitignore | \
+               documented,gitmodules | \
+               documented,git-tools | \
+               sentinel,not,matching,is,ok ) continue ;; \
+               esac; \
+               case " $(ALL_PROGRAMS) $(BUILT_INS) git gitk " in \
+               *" $$cmd "*)    ;; \
+               *) echo "removed but $$how: $$cmd" ;; \
+               esac; \
+       done ) | sort
 
 ### Make sure built-ins do not have dups and listed in git.c
 #
index 55a3c0bc5e3aa9c893468f5f97eab17681ddc673..ba80bf8942f1db42b8a132471ddbfc38e565f115 100644 (file)
@@ -2295,6 +2295,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                        else if (i != argc - 1)
                                usage(blame_usage); /* garbage at end */
 
+                       setup_work_tree();
                        if (!has_path_in_work_tree(path))
                                die("cannot stat path %s: %s",
                                    path, strerror(errno));
index da8c7948e63609aeeae20cde87b519933a5a4207..bfde2e2bbeffaed68b369b25cfe1b5ef4b108e12 100644 (file)
@@ -304,7 +304,7 @@ static const char *find_wholine(const char *who, int wholen, const char *buf, un
                if (!eol)
                        return "";
                eol++;
-               if (eol[1] == '\n')
+               if (*eol == '\n')
                        return ""; /* end of header */
                buf = eol;
        }
@@ -847,7 +847,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
                OPT_GROUP(""),
                OPT_INTEGER( 0 , "count", &maxcount, "show only <n> matched refs"),
                OPT_STRING(  0 , "format", &format, "format", "format to use for the output"),
-               OPT_CALLBACK(0 , "sort", &sort_tail, "key",
+               OPT_CALLBACK(0 , "sort", sort_tail, "key",
                            "field name to sort on", &opt_parse_sort),
                OPT_END(),
        };
index 2c561953fc2d8cd8b02ab2a4c6fc470349c89bbb..6d1da07c46704f3de837044652f0a1fd149327ad 100644 (file)
@@ -115,6 +115,8 @@ int cmd_push(int argc, const char **argv, const char *prefix)
                flags |= TRANSPORT_PUSH_FORCE;
        if (dry_run)
                flags |= TRANSPORT_PUSH_DRY_RUN;
+       if (verbose)
+               flags |= TRANSPORT_PUSH_VERBOSE;
        if (tags)
                add_refspec("refs/tags/*");
        if (all)
index 9626d4c54a812e0ad94204cfb434309da33b6a57..4c61025aaef96ae9f8bcabe3fd4ad6c0fc2beba3 100644 (file)
@@ -46,26 +46,14 @@ static inline int is_merge(void)
 
 static int unmerged_files(void)
 {
-       char b;
-       ssize_t len;
-       struct child_process cmd;
-       const char *argv_ls_files[] = {"ls-files", "--unmerged", NULL};
-
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.argv = argv_ls_files;
-       cmd.git_cmd = 1;
-       cmd.out = -1;
-
-       if (start_command(&cmd))
-               die("Could not run sub-command: git ls-files");
-
-       len = xread(cmd.out, &b, 1);
-       if (len < 0)
-               die("Could not read output from git ls-files: %s",
-                                               strerror(errno));
-       finish_command(&cmd);
-
-       return len;
+       int i;
+       read_cache();
+       for (i = 0; i < active_nr; i++) {
+               struct cache_entry *ce = active_cache[i];
+               if (ce_stage(ce))
+                       return 1;
+       }
+       return 0;
 }
 
 static int reset_index_file(const unsigned char *sha1, int is_hard_reset)
@@ -107,26 +95,34 @@ static void print_new_head_line(struct commit *commit)
                printf("\n");
 }
 
-static int update_index_refresh(void)
+static int update_index_refresh(int fd, struct lock_file *index_lock)
 {
-       const char *argv_update_index[] = {"update-index", "--refresh", NULL};
-       return run_command_v_opt(argv_update_index, RUN_GIT_CMD);
-}
+       int result;
 
-struct update_cb_data {
-       int index_fd;
-       struct lock_file *lock;
-       int exit_code;
-};
+       if (!index_lock) {
+               index_lock = xcalloc(1, sizeof(struct lock_file));
+               fd = hold_locked_index(index_lock, 1);
+       }
+
+       if (read_cache() < 0)
+               return error("Could not read index");
+       result = refresh_cache(0) ? 1 : 0;
+       if (write_cache(fd, active_cache, active_nr) ||
+                       close(fd) ||
+                       commit_locked_index(index_lock))
+               return error ("Could not refresh index");
+       return result;
+}
 
 static void update_index_from_diff(struct diff_queue_struct *q,
                struct diff_options *opt, void *data)
 {
        int i;
-       struct update_cb_data *cb = data;
+       int *discard_flag = data;
 
        /* do_diff_cache() mangled the index */
        discard_cache();
+       *discard_flag = 1;
        read_cache();
 
        for (i = 0; i < q->nr; i++) {
@@ -140,34 +136,33 @@ static void update_index_from_diff(struct diff_queue_struct *q,
                } else
                        remove_file_from_cache(one->path);
        }
-
-       cb->exit_code = write_cache(cb->index_fd, active_cache, active_nr) ||
-               close(cb->index_fd) ||
-               commit_locked_index(cb->lock);
 }
 
 static int read_from_tree(const char *prefix, const char **argv,
                unsigned char *tree_sha1)
 {
+       struct lock_file *lock = xcalloc(1, sizeof(struct lock_file));
+       int index_fd, index_was_discarded = 0;
        struct diff_options opt;
-       struct update_cb_data cb;
 
        memset(&opt, 0, sizeof(opt));
        diff_tree_setup_paths(get_pathspec(prefix, (const char **)argv), &opt);
        opt.output_format = DIFF_FORMAT_CALLBACK;
        opt.format_callback = update_index_from_diff;
-       opt.format_callback_data = &cb;
+       opt.format_callback_data = &index_was_discarded;
 
-       cb.lock = xcalloc(1, sizeof(struct lock_file));
-       cb.index_fd = hold_locked_index(cb.lock, 1);
-       cb.exit_code = 0;
+       index_fd = hold_locked_index(lock, 1);
+       index_was_discarded = 0;
        read_cache();
        if (do_diff_cache(tree_sha1, &opt))
                return 1;
        diffcore_std(&opt);
        diff_flush(&opt);
 
-       return cb.exit_code;
+       if (!index_was_discarded)
+               /* The index is still clobbered from do_diff_cache() */
+               discard_cache();
+       return update_index_refresh(index_fd, lock);
 }
 
 static void prepend_reflog_action(const char *action, char *buf, size_t size)
@@ -243,9 +238,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
                else if (reset_type != NONE)
                        die("Cannot do %s reset with paths.",
                                        reset_type_names[reset_type]);
-               if (read_from_tree(prefix, argv + i, sha1))
-                       return 1;
-               return update_index_refresh() ? 1 : 0;
+               return read_from_tree(prefix, argv + i, sha1);
        }
        if (reset_type == NONE)
                reset_type = MIXED; /* by default */
@@ -282,7 +275,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
        case SOFT: /* Nothing else to do. */
                break;
        case MIXED: /* Report what has not been updated. */
-               update_index_refresh();
+               update_index_refresh(0, NULL);
                break;
        }
 
index 62ab1fa1f484a113f45da96de8cd209a0c5c522e..365b330f9e1f2989683611077d260fa49abcb889 100644 (file)
@@ -246,7 +246,9 @@ static int revert_or_cherry_pick(int argc, const char **argv)
        if (no_commit) {
                /*
                 * We do not intend to commit immediately.  We just want to
-                * merge the differences in.
+                * merge the differences in, so let's compute the tree
+                * that represents the "current" state for merge-recursive
+                * to work on.
                 */
                if (write_tree(head, 0, NULL))
                        die ("Your index file is unmerged.");
@@ -256,7 +258,7 @@ static int revert_or_cherry_pick(int argc, const char **argv)
                if (get_sha1("HEAD", head))
                        die ("You do not have a valid HEAD");
                wt_status_prepare(&s);
-               if (s.commitable || s.workdir_dirty)
+               if (s.commitable)
                        die ("Dirty index: cannot %s", me);
                discard_cache();
        }
index f93d7d6c9bf2db021ceb65766da87af32aecc1d1..98c2bd535957a45e5ef189875859d4788d937e7e 100644 (file)
@@ -153,13 +153,16 @@ Format of STDIN stream:
 
 #define PACK_ID_BITS 16
 #define MAX_PACK_ID ((1<<PACK_ID_BITS)-1)
+#define DEPTH_BITS 13
+#define MAX_DEPTH ((1<<DEPTH_BITS)-1)
 
 struct object_entry
 {
        struct object_entry *next;
        uint32_t offset;
-       unsigned type : TYPE_BITS;
-       unsigned pack_id : PACK_ID_BITS;
+       uint32_t type : TYPE_BITS,
+               pack_id : PACK_ID_BITS,
+               depth : DEPTH_BITS;
        unsigned char sha1[20];
 };
 
@@ -1083,7 +1086,7 @@ static int store_object(
                unsigned pos = sizeof(hdr) - 1;
 
                delta_count_by_type[type]++;
-               last->depth++;
+               e->depth = last->depth + 1;
 
                hdrlen = encode_header(OBJ_OFS_DELTA, deltalen, hdr);
                write_or_die(pack_data->pack_fd, hdr, hdrlen);
@@ -1095,8 +1098,7 @@ static int store_object(
                write_or_die(pack_data->pack_fd, hdr + pos, sizeof(hdr) - pos);
                pack_size += sizeof(hdr) - pos;
        } else {
-               if (last)
-                       last->depth = 0;
+               e->depth = 0;
                hdrlen = encode_header(type, dat->len, hdr);
                write_or_die(pack_data->pack_fd, hdr, hdrlen);
                pack_size += hdrlen;
@@ -1114,6 +1116,7 @@ static int store_object(
                        strbuf_swap(&last->data, dat);
                }
                last->offset = e->offset;
+               last->depth = e->depth;
        }
        return 0;
 }
@@ -1160,7 +1163,7 @@ static void load_tree(struct tree_entry *root)
        if (myoe && myoe->pack_id != MAX_PACK_ID) {
                if (myoe->type != OBJ_TREE)
                        die("Not a tree: %s", sha1_to_hex(sha1));
-               t->delta_depth = 0;
+               t->delta_depth = myoe->depth;
                buf = gfi_unpack_entry(myoe, &size);
        } else {
                enum object_type type;
@@ -2289,8 +2292,11 @@ int main(int argc, const char **argv)
                }
                else if (!prefixcmp(a, "--max-pack-size="))
                        max_packsize = strtoumax(a + 16, NULL, 0) * 1024 * 1024;
-               else if (!prefixcmp(a, "--depth="))
+               else if (!prefixcmp(a, "--depth=")) {
                        max_depth = strtoul(a + 8, NULL, 0);
+                       if (max_depth > MAX_DEPTH)
+                               die("--depth cannot exceed %u", MAX_DEPTH);
+               }
                else if (!prefixcmp(a, "--active-branches="))
                        max_active_branches = strtoul(a + 18, NULL, 0);
                else if (!prefixcmp(a, "--import-marks="))
index f4965b8391436384bf795c1e39b7f9158e624e51..ad68595fbf313c1cab7de565e6d44f2c87aff384 100755 (executable)
@@ -25,10 +25,7 @@ rmrf="rm -rf --"
 rm_refuse="echo Not removing"
 echo1="echo"
 
-# requireForce used to default to false but now it defaults to true.
-# IOW, lack of explicit "clean.requireForce = false" is taken as
-# "clean.requireForce = true".
-disabled=$(git config --bool clean.requireForce || echo true)
+disabled=$(git config --bool clean.requireForce)
 
 while test $# != 0
 do
@@ -37,10 +34,10 @@ do
                cleandir=1
                ;;
        -f)
-               disabled=
+               disabled=false
                ;;
        -n)
-               disabled=
+               disabled=false
                rmf="echo Would remove"
                rmrf="echo Would remove"
                rm_refuse="echo Would not remove"
@@ -68,10 +65,17 @@ do
        shift
 done
 
-if [ "$disabled" = true ]; then
-       echo "clean.requireForce set and -n or -f not given; refusing to clean"
-       exit 1
-fi
+# requireForce used to default to false but now it defaults to true.
+# IOW, lack of explicit "clean.requireForce = false" is taken as
+# "clean.requireForce = true".
+case "$disabled" in
+"")
+       die "clean.requireForce not set and -n or -f not given; refusing to clean"
+       ;;
+"true")
+       die "clean.requireForce set and -n or -f not given; refusing to clean"
+       ;;
+esac
 
 case "$ignored,$ignoredonly" in
        1,1) usage;;
@@ -79,15 +83,22 @@ esac
 
 if [ -z "$ignored" ]; then
        excl="--exclude-per-directory=.gitignore"
+       excl_info= excludes_file=
        if [ -f "$GIT_DIR/info/exclude" ]; then
                excl_info="--exclude-from=$GIT_DIR/info/exclude"
        fi
+       if cfg_excl=$(git config core.excludesfile) && test -f "$cfg_excl"
+       then
+               excludes_file="--exclude-from=$cfg_excl"
+       fi
        if [ "$ignoredonly" ]; then
                excl="$excl --ignored"
        fi
 fi
 
-git ls-files --others --directory $excl ${excl_info:+"$excl_info"} -- "$@" |
+git ls-files --others --directory \
+       $excl ${excl_info:+"$excl_info"} ${excludes_file:+"$excludes_file"} \
+       -- "$@" |
 while read -r file; do
        if [ -d "$file" -a ! -L "$file" ]; then
                if [ -z "$cleandir" ]; then
index 26844af4390b8b0902ad853f40e4d9f60b75fd23..92e41620fd2a998e765a47c2c2ca7085834b14cc 100755 (executable)
@@ -1,28 +1,42 @@
 #!/usr/bin/perl -w
 
-# Known limitations:
-# - does not propagate permissions
-# - error handling has not been extensively tested
-#
-
 use strict;
 use Getopt::Std;
 use File::Temp qw(tempdir);
 use Data::Dumper;
 use File::Basename qw(basename dirname);
 
-unless ($ENV{GIT_DIR} && -r $ENV{GIT_DIR}){
-    die "GIT_DIR is not defined or is unreadable";
-}
-
-our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d, $opt_u);
+our ($opt_h, $opt_P, $opt_p, $opt_v, $opt_c, $opt_f, $opt_a, $opt_m, $opt_d, $opt_u, $opt_w);
 
-getopts('uhPpvcfam:d:');
+getopts('uhPpvcfam:d:w:');
 
 $opt_h && usage();
 
 die "Need at least one commit identifier!" unless @ARGV;
 
+if ($opt_w) {
+       unless ($ENV{GIT_DIR}) {
+               # Remember where our GIT_DIR is before changing to CVS checkout
+               my $gd =`git-rev-parse --git-dir`;
+               chomp($gd);
+               if ($gd eq '.git') {
+                       my $wd = `pwd`;
+                       chomp($wd);
+                       $gd = $wd."/.git"       ;
+               }
+               $ENV{GIT_DIR} = $gd;
+       }
+
+       if (! -d $opt_w."/CVS" ) {
+               die "$opt_w is not a CVS checkout";
+       }
+       chdir $opt_w or die "Cannot change to CVS checkout at $opt_w";
+}
+unless ($ENV{GIT_DIR} && -r $ENV{GIT_DIR}){
+    die "GIT_DIR is not defined or is unreadable";
+}
+
+
 my @cvs;
 if ($opt_d) {
        @cvs = ('cvs', '-d', $opt_d);
     print "You'll need to apply the patch in .cvsexportcommit.diff manually\n";
     print "using a patch program. After applying the patch and resolving the\n";
     print "problems you may commit using:";
+    print "\n    cd \"$opt_w\"" if $opt_w;
     print "\n    $cmd\n\n";
     exit(1);
 }
 
 sub usage {
        print STDERR <<END;
-Usage: GIT_DIR=/path/to/.git ${\basename $0} [-h] [-p] [-v] [-c] [-f] [-m msgprefix] [ parent ] commit
+Usage: GIT_DIR=/path/to/.git ${\basename $0} [-h] [-p] [-v] [-c] [-f] [-u] [-w cvsworkdir] [-m msgprefix] [ parent ] commit
 END
        exit(1);
 }
index e4bc2b54f68930df217751975e32b4224f8d765c..efa6a0c41ad5a253047789e8ac2a30bf57f8646d 100755 (executable)
@@ -223,7 +223,8 @@ sub conn {
                        }
                }
 
-               $user="anonymous" unless defined $user;
+               # if username is not explicit in CVSROOT, then use current user, as cvs would
+               $user=(getlogin() || $ENV{'LOGNAME'} || $ENV{'USER'} || "anonymous") unless $user;
                my $rr2 = "-";
                unless ($port) {
                        $rr2 = ":pserver:$user\@$serv:$repo";
index dd93e320a7c0d20e8eec1c171c9c96a32ced406b..e3e00fdcc5f4b0ad1d06cc026a5efe62ff0be0fe 100755 (executable)
@@ -390,6 +390,9 @@ sub cmd_set_tree {
 
 sub cmd_dcommit {
        my $head = shift;
+       git_cmd_try { command_oneline(qw/diff-index --quiet HEAD/) }
+               'Cannot dcommit with a dirty index.  Commit your changes first'
+               . "or stash them with `git stash'.\n";
        $head ||= 'HEAD';
        my @refs;
        my ($url, $rev, $uuid, $gs) = working_head_info($head, \@refs);
@@ -3220,6 +3223,25 @@ ()
        ]
 }
 
+sub escape_uri_only {
+       my ($uri) = @_;
+       my @tmp;
+       foreach (split m{/}, $uri) {
+               s/([^\w.-])/sprintf("%%%02X",ord($1))/eg;
+               push @tmp, $_;
+       }
+       join('/', @tmp);
+}
+
+sub escape_url {
+       my ($url) = @_;
+       if ($url =~ m#^(https?)://([^/]+)(.*)$#) {
+               my ($scheme, $domain, $uri) = ($1, $2, escape_uri_only($3));
+               $url = "$scheme://$domain$uri";
+       }
+       $url;
+}
+
 sub new {
        my ($class, $url) = @_;
        $url =~ s!/+$!!;
@@ -3252,10 +3274,11 @@ sub new {
                        $Git::SVN::Prompt::_no_auth_cache = 1;
                }
        } # no warnings 'once'
-       my $self = SVN::Ra->new(url => $url, auth => $baton,
+       my $self = SVN::Ra->new(url => escape_url($url), auth => $baton,
                              config => $config,
                              pool => SVN::Pool->new,
                              auth_provider_callbacks => $callbacks);
+       $self->{url} = $url;
        $self->{svn_path} = $url;
        $self->{repos_root} = $self->get_repos_root;
        $self->{svn_path} =~ s#^\Q$self->{repos_root}\E(/|$)##;
@@ -3381,7 +3404,7 @@ sub gs_do_switch {
 
        my $full_url = $self->{url};
        my $old_url = $full_url;
-       $full_url .= "/$path" if length $path;
+       $full_url .= '/' . escape_uri_only($path) if length $path;
        my ($ra, $reparented);
        if ($old_url ne $full_url) {
                if ($old_url !~ m#^svn(\+ssh)?://#) {
index 759dff1cceafb3d67f662d3876405ffcf9ebf96c..e788ef90c981e93f59400332da8bb7de1c2b3952 100755 (executable)
@@ -1856,7 +1856,7 @@ sub parse_date {
        $date{'mday-time'} = sprintf "%d %s %02d:%02d",
                             $mday, $months[$mon], $hour ,$min;
        $date{'iso-8601'}  = sprintf "%04d-%02d-%02dT%02d:%02d:%02dZ",
-                            1900+$year, $mon, $mday, $hour ,$min, $sec;
+                            1900+$year, 1+$mon, $mday, $hour ,$min, $sec;
 
        $tz =~ m/^([+\-][0-9][0-9])([0-9][0-9])$/;
        my $local = $epoch + ((int $1 + ($2/60)) * 3600);
index 18f5017f51bcac5798e959991be37c7cd6d70528..0a58f3f1267dcb4dbd67c89fc165367c6840f1da 100644 (file)
@@ -42,6 +42,8 @@ int main(int argc, char **argv)
        int prefix_length = -1;
        int no_more_flags = 0;
 
+       git_config(git_default_config);
+
        for (i = 1 ; i < argc; i++) {
                if (!no_more_flags && argv[i][0] == '-') {
                        if (!strcmp(argv[i], "-t")) {
index 715a5bb7a6e42694b3e35de703e44e792a5442fe..3c99a1fce97c387ec1dfc76649699a8095e76d81 100644 (file)
@@ -256,7 +256,7 @@ static void *unpack_raw_entry(struct object_entry *obj, union delta_base *delta_
 
 static void *get_data_from_pack(struct object_entry *obj)
 {
-       unsigned long from = obj[0].idx.offset + obj[0].hdr_size;
+       off_t from = obj[0].idx.offset + obj[0].hdr_size;
        unsigned long len = obj[1].idx.offset - from;
        unsigned long rdy = 0;
        unsigned char *src, *data;
index e5c88c278fe23eefbf4cb4dd0c66251b208e48bd..4ef58e7ec01ebdfc6f036ccafaf837b2b38ed7a5 100644 (file)
@@ -170,4 +170,11 @@ void traverse_commit_list(struct rev_info *revs,
        }
        for (i = 0; i < objects.nr; i++)
                show_object(&objects.objects[i]);
+       free(objects.objects);
+       if (revs->pending.nr) {
+               free(revs->pending.objects);
+               revs->pending.nr = 0;
+               revs->pending.alloc = 0;
+               revs->pending.objects = NULL;
+       }
 }
index cc09c98ec3fe19d6f9f5f7a58a3c5956bd7c0578..15b32f741b6b8bf47321b9ce78da43e9378f22b3 100644 (file)
@@ -119,8 +119,8 @@ static int parse_long_opt(struct optparse_t *p, const char *arg,
                           const struct option *options)
 {
        const char *arg_end = strchr(arg, '=');
-       const struct option *abbrev_option = NULL;
-       int abbrev_flags = 0;
+       const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
+       int abbrev_flags = 0, ambiguous_flags = 0;
 
        if (!arg_end)
                arg_end = arg + strlen(arg);
@@ -137,16 +137,16 @@ static int parse_long_opt(struct optparse_t *p, const char *arg,
                        /* abbreviated? */
                        if (!strncmp(options->long_name, arg, arg_end - arg)) {
 is_abbreviated:
-                               if (abbrev_option)
-                                       return error("Ambiguous option: %s "
-                                               "(could be --%s%s or --%s%s)",
-                                               arg,
-                                               (flags & OPT_UNSET) ?
-                                                       "no-" : "",
-                                               options->long_name,
-                                               (abbrev_flags & OPT_UNSET) ?
-                                                       "no-" : "",
-                                               abbrev_option->long_name);
+                               if (abbrev_option) {
+                                       /*
+                                        * If this is abbreviated, it is
+                                        * ambiguous. So when there is no
+                                        * exact match later, we need to
+                                        * error out.
+                                        */
+                                       ambiguous_option = abbrev_option;
+                                       ambiguous_flags = abbrev_flags;
+                               }
                                if (!(flags & OPT_UNSET) && *arg_end)
                                        p->opt = arg_end + 1;
                                abbrev_option = options;
@@ -176,6 +176,15 @@ static int parse_long_opt(struct optparse_t *p, const char *arg,
                }
                return get_value(p, options, flags);
        }
+
+       if (ambiguous_option)
+               return error("Ambiguous option: %s "
+                       "(could be --%s%s or --%s%s)",
+                       arg,
+                       (ambiguous_flags & OPT_UNSET) ?  "no-" : "",
+                       ambiguous_option->long_name,
+                       (abbrev_flags & OPT_UNSET) ?  "no-" : "",
+                       abbrev_option->long_name);
        if (abbrev_option)
                return get_value(p, abbrev_option, abbrev_flags);
        return error("unknown option `%s'", arg);
diff --git a/setup.c b/setup.c
index 1e2c55d0767dfc1122e0c6716f9148bd10be22ab..43cd3f94ea31a7a2a8f8a07cbb67598bb1e52c39 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -208,12 +208,18 @@ static const char *set_work_tree(const char *dir)
 
 void setup_work_tree(void)
 {
-       const char *work_tree = get_git_work_tree();
-       const char *git_dir = get_git_dir();
+       const char *work_tree, *git_dir;
+       static int initialized = 0;
+
+       if (initialized)
+               return;
+       work_tree = get_git_work_tree();
+       git_dir = get_git_dir();
        if (!is_absolute_path(git_dir))
                set_git_dir(make_absolute_path(git_dir));
        if (!work_tree || chdir(work_tree))
                die("This operation must be run in a work tree");
+       initialized = 1;
 }
 
 /*
index dbd8c4bcfb2f8549b8713a8d9fbbfd8adcd0088c..b9b194b3200e950cfdb3c696d92ece0657e9d344 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -118,12 +118,13 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
        int len;
        va_list ap;
 
+       if (!strbuf_avail(sb))
+               strbuf_grow(sb, 64);
        va_start(ap, fmt);
        len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
        va_end(ap);
-       if (len < 0) {
-               len = 0;
-       }
+       if (len < 0)
+               die("your vsnprintf is broken");
        if (len > strbuf_avail(sb)) {
                strbuf_grow(sb, len);
                va_start(ap, fmt);
index ae49424aa02a37df1b00813aa1478d570020c66b..462fdf262fe451c14679753018a415e1cc778732 100755 (executable)
@@ -18,6 +18,7 @@ string options
     -s, --string <string>
                           get a string
     --string2 <str>       get another string
+    --st <st>             get another string (pervert ordering)
 
 EOF
 
@@ -90,4 +91,16 @@ test_expect_failure 'ambiguously abbreviated option' '
         test $? != 129
 '
 
+cat > expect << EOF
+boolean: 0
+integer: 0
+string: 123
+EOF
+
+test_expect_success 'non ambiguous option (after two options it abbreviates)' '
+       test-parse-options --st 123 > output 2> output.err &&
+       test ! -s output.err &&
+       git diff expect output
+'
+
 test_done
index 11139048fe2238a3e06972252d7410da4058dccb..f1039d1a2146ed68217d849d7588d9ca65af785b 100755 (executable)
@@ -149,7 +149,7 @@ test_expect_success 'stop on conflicting pick' '
        diff -u expect .git/.dotest-merge/patch &&
        diff -u expect2 file1 &&
        test 4 = $(grep -v "^#" < .git/.dotest-merge/done | wc -l) &&
-       test 0 = $(grep -v "^#" < .git/.dotest-merge/todo | wc -l)
+       test 0 = $(grep -v "^#" < .git/.dotest-merge/git-rebase-todo | wc -l)
 '
 
 test_expect_success 'abort' '
diff --git a/t/t5530-upload-pack-error.sh b/t/t5530-upload-pack-error.sh
new file mode 100755 (executable)
index 0000000..cc8949e
--- /dev/null
@@ -0,0 +1,75 @@
+#!/bin/sh
+
+test_description='errors in upload-pack'
+
+. ./test-lib.sh
+
+D=`pwd`
+
+corrupt_repo () {
+       object_sha1=$(git rev-parse "$1") &&
+       ob=$(expr "$object_sha1" : "\(..\)") &&
+       ject=$(expr "$object_sha1" : "..\(..*\)") &&
+       rm -f ".git/objects/$ob/$ject"
+}
+
+test_expect_success 'setup and corrupt repository' '
+
+       echo file >file &&
+       git add file &&
+       git rev-parse :file &&
+       git commit -a -m original &&
+       test_tick &&
+       echo changed >file &&
+       git commit -a -m changed &&
+       corrupt_repo HEAD:file
+
+'
+
+test_expect_failure 'fsck fails' '
+
+       git fsck
+'
+
+test_expect_success 'upload-pack fails due to error in pack-objects' '
+
+       ! echo "0032want $(git rev-parse HEAD)
+00000009done
+0000" | git-upload-pack . > /dev/null 2> output.err &&
+       grep "pack-objects died" output.err
+'
+
+test_expect_success 'corrupt repo differently' '
+
+       git hash-object -w file &&
+       corrupt_repo HEAD^^{tree}
+
+'
+
+test_expect_failure 'fsck fails' '
+
+       git fsck
+'
+test_expect_success 'upload-pack fails due to error in rev-list' '
+
+       ! echo "0032want $(git rev-parse HEAD)
+00000009done
+0000" | git-upload-pack . > /dev/null 2> output.err &&
+       grep "waitpid (async) failed" output.err
+'
+
+test_expect_success 'create empty repository' '
+
+       mkdir foo &&
+       cd foo &&
+       git init
+
+'
+
+test_expect_failure 'fetch fails' '
+
+       git fetch .. master
+
+'
+
+test_done
index d0809eb651d3fef4ff6cd342bfeabf62e9ef5d05..c722635050fed8011c04177dc5a8220cae12a843 100755 (executable)
@@ -148,4 +148,26 @@ test_expect_success 'Check format "rfc2822" date fields output' '
        git diff expected actual
 '
 
+cat >expected <<\EOF
+refs/heads/master
+refs/tags/testtag
+EOF
+
+test_expect_success 'Verify ascending sort' '
+       git-for-each-ref --format="%(refname)" --sort=refname >actual &&
+       git diff expected actual
+'
+
+
+cat >expected <<\EOF
+refs/tags/testtag
+refs/heads/master
+EOF
+
+test_expect_success 'Verify descending sort' '
+       git-for-each-ref --format="%(refname)" --sort=-refname >actual &&
+       git diff expected actual
+'
+
+
 test_done
index cea9afb764226d3086450cb7c53c881bb9803eec..e5c9f30c73d4dbfe1fff6022bddfe6a387441a9b 100755 (executable)
@@ -59,6 +59,15 @@ test_expect_success 'giving a non existing revision should fail' '
        check_changes 3ec39651e7f44ea531a5de18a9fa791c0fd370fc
 '
 
+test_expect_success 'reset --soft with unmerged index should fail' '
+       touch .git/MERGE_HEAD &&
+       echo "100644 44c5b5884550c17758737edcced463447b91d42b 1 un" |
+               git update-index --index-info &&
+       ! git reset --soft HEAD &&
+       rm .git/MERGE_HEAD &&
+       git rm --cached -- un
+'
+
 test_expect_success \
        'giving paths with options different than --mixed should fail' '
        ! git reset --soft -- first &&
@@ -409,4 +418,14 @@ test_expect_success 'resetting an unmodified path is a no-op' '
        git diff-index --cached --exit-code HEAD
 '
 
+cat > expect << EOF
+file2: needs update
+EOF
+
+test_expect_success '--mixed refreshes the index' '
+       echo 123 >> file2 &&
+       git reset --mixed HEAD > output &&
+       git diff --exit-code expect output
+'
+
 test_done
index 25d3102dedd31f43bfaabd1ae05fdebbc51863f8..f013c176ed910d278cbb886004429869f288ebc7 100755 (executable)
@@ -291,4 +291,15 @@ test_expect_success 'clean.requireForce and -f' '
 
 '
 
+test_expect_success 'core.excludesfile' '
+
+       echo excludes >excludes &&
+       echo included >included &&
+       git config core.excludesfile excludes &&
+       output=$(git clean -n excludes included 2>&1) &&
+       expr "$output" : ".*included" >/dev/null &&
+       ! expr "$output" : ".*excludes" >/dev/null
+
+'
+
 test_done
index b151b51a3420fdba921da16979ec4a480b61a973..4dc35bdf558750ef41f229fbbb5dbef0a05401c5 100644 (file)
@@ -163,4 +163,73 @@ test_expect_success 'partial commit that involves removal (3)' '
 
 '
 
+author="The Real Author <someguy@his.email.org>"
+test_expect_success 'amend commit to fix author' '
+
+       oldtick=$GIT_AUTHOR_DATE &&
+       test_tick &&
+       git reset --hard &&
+       git cat-file -p HEAD |
+       sed -e "s/author.*/author $author $oldtick/" \
+               -e "s/^\(committer.*> \).*$/\1$GIT_COMMITTER_DATE/" > \
+               expected &&
+       git commit --amend --author="$author" &&
+       git cat-file -p HEAD > current &&
+       diff expected current
+
+'
+
+test_expect_success 'sign off (1)' '
+
+       echo 1 >positive &&
+       git add positive &&
+       git commit -s -m "thank you" &&
+       git cat-file commit HEAD | sed -e "1,/^\$/d" >actual &&
+       (
+               echo thank you
+               echo
+               git var GIT_COMMITTER_IDENT |
+               sed -e "s/>.*/>/" -e "s/^/Signed-off-by: /"
+       ) >expected &&
+       diff -u expected actual
+
+'
+
+test_expect_success 'sign off (2)' '
+
+       echo 2 >positive &&
+       git add positive &&
+       existing="Signed-off-by: Watch This <watchthis@example.com>" &&
+       git commit -s -m "thank you
+
+$existing" &&
+       git cat-file commit HEAD | sed -e "1,/^\$/d" >actual &&
+       (
+               echo thank you
+               echo
+               echo $existing
+               git var GIT_COMMITTER_IDENT |
+               sed -e "s/>.*/>/" -e "s/^/Signed-off-by: /"
+       ) >expected &&
+       diff -u expected actual
+
+'
+
+test_expect_success 'multiple -m' '
+
+       >negative &&
+       git add negative &&
+       git commit -m "one" -m "two" -m "three" &&
+       git cat-file commit HEAD | sed -e "1,/^\$/d" >actual &&
+       (
+               echo one
+               echo
+               echo two
+               echo
+               echo three
+       ) >expected &&
+       diff -u expected actual
+
+'
+
 test_done
index 7eff4cdc05635c85c354c9b2a96fe4844c682621..d59acc8d1ade041d01d5a45aa993b26919a0170c 100755 (executable)
@@ -53,4 +53,10 @@ test_expect_success 'change file but in unrelated area' "
                test x\"\`sed -n -e 61p < file\`\" = x6611
        "
 
+test_expect_failure 'attempt to dcommit with a dirty index' '
+       echo foo >>file &&
+       git add file &&
+       git svn dcommit
+'
+
 test_done
diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh
new file mode 100755 (executable)
index 0000000..640bb06
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Eric Wong
+#
+
+test_description='git-svn funky branch names'
+. ./lib-git-svn.sh
+
+test_expect_success 'setup svnrepo' "
+       mkdir project project/trunk project/branches project/tags &&
+       echo foo > project/trunk/foo &&
+       svn import -m '$test_description' project \"$svnrepo/pr ject\" &&
+       rm -rf project &&
+       svn cp -m 'fun' \"$svnrepo/pr ject/trunk\" \
+                       \"$svnrepo/pr ject/branches/fun plugin\" &&
+       svn cp -m 'more fun!' \"$svnrepo/pr ject/branches/fun plugin\" \
+                             \"$svnrepo/pr ject/branches/more fun plugin!\" &&
+       start_httpd
+       "
+
+test_expect_success 'test clone with funky branch names' "
+       git svn clone -s \"$svnrepo/pr ject\" project &&
+       cd project &&
+               git rev-parse 'refs/remotes/fun%20plugin' &&
+               git rev-parse 'refs/remotes/more%20fun%20plugin!' &&
+       cd ..
+       "
+
+test_expect_success 'test dcommit to funky branch' "
+       cd project &&
+       git reset --hard 'refs/remotes/more%20fun%20plugin!' &&
+       echo hello >> foo &&
+       git commit -m 'hello' -- foo &&
+       git svn dcommit &&
+       cd ..
+       "
+
+stop_httpd
+
+test_done
index 603a8cd5e7c53569fea3dba66754b52ea1fad9ba..90b6844d00c3cb288c23488923b98a7276eb83e8 100644 (file)
@@ -66,9 +66,6 @@ esac
        tput sgr0 >/dev/null 2>&1 &&
        color=t
 
-test "${test_description}" != "" ||
-error "Test script did not set test_description."
-
 while test "$#" -ne 0
 do
        case "$1" in
@@ -77,8 +74,7 @@ do
        -i|--i|--im|--imm|--imme|--immed|--immedi|--immedia|--immediat|--immediate)
                immediate=t; shift ;;
        -h|--h|--he|--hel|--help)
-               echo "$test_description"
-               exit 0 ;;
+               help=t; shift ;;
        -v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
                verbose=t; shift ;;
        -q|--q|--qu|--qui|--quie|--quiet)
@@ -124,6 +120,15 @@ say () {
        say_color info "$*"
 }
 
+test "${test_description}" != "" ||
+error "Test script did not set test_description."
+
+if test "$help" = "t"
+then
+       echo "$test_description"
+       exit 0
+fi
+
 exec 5>&1
 if test "$verbose" = "t"
 then
index 277cfe4d6dceb5ebe2ce9f141b6eb21a4dc37912..4d3e2ec39e33f6301cc6df162dab7de9dbb2ea80 100644 (file)
@@ -18,6 +18,7 @@ int main(int argc, const char **argv)
                OPT_GROUP("string options"),
                OPT_STRING('s', "string", &string, "string", "get a string"),
                OPT_STRING(0, "string2", &string, "str", "get another string"),
+               OPT_STRING(0, "st", &string, "st", "get another string (pervert ordering)"),
                OPT_END(),
        };
        int i;
diff --git a/trace.c b/trace.c
index 69fa05e6446355ed8e5bb7f560c83f61b9bc3aff..0d89dbe7794dcdfb8519e6d083f74bf792976c6a 100644 (file)
--- a/trace.c
+++ b/trace.c
@@ -72,7 +72,7 @@ void trace_printf(const char *fmt, ...)
        if (!fd)
                return;
 
-       strbuf_init(&buf, 0);
+       strbuf_init(&buf, 64);
        va_start(ap, fmt);
        len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap);
        va_end(ap);
@@ -103,7 +103,7 @@ void trace_argv_printf(const char **argv, int count, const char *fmt, ...)
        if (!fd)
                return;
 
-       strbuf_init(&buf, 0);
+       strbuf_init(&buf, 64);
        va_start(ap, fmt);
        len = vsnprintf(buf.buf, strbuf_avail(&buf), fmt, ap);
        va_end(ap);
index fa5cfbb09d18d4546725e947933b22bb32c3ec2c..e8a2608372de06ef3f77d9a450776e3095057c9f 100644 (file)
@@ -386,7 +386,7 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons
        int argc;
        int err;
 
-       argv = xmalloc((refspec_nr + 11) * sizeof(char *));
+       argv = xmalloc((refspec_nr + 12) * sizeof(char *));
        argv[0] = "http-push";
        argc = 1;
        if (flags & TRANSPORT_PUSH_ALL)
@@ -395,6 +395,8 @@ static int curl_transport_push(struct transport *transport, int refspec_nr, cons
                argv[argc++] = "--force";
        if (flags & TRANSPORT_PUSH_DRY_RUN)
                argv[argc++] = "--dry-run";
+       if (flags & TRANSPORT_PUSH_VERBOSE)
+               argv[argc++] = "--verbose";
        argv[argc++] = transport->url;
        while (refspec_nr--)
                argv[argc++] = *refspec++;
@@ -655,7 +657,7 @@ static int git_transport_push(struct transport *transport, int refspec_nr, const
        int argc;
        int err;
 
-       argv = xmalloc((refspec_nr + 11) * sizeof(char *));
+       argv = xmalloc((refspec_nr + 12) * sizeof(char *));
        argv[0] = "send-pack";
        argc = 1;
        if (flags & TRANSPORT_PUSH_ALL)
@@ -664,6 +666,8 @@ static int git_transport_push(struct transport *transport, int refspec_nr, const
                argv[argc++] = "--force";
        if (flags & TRANSPORT_PUSH_DRY_RUN)
                argv[argc++] = "--dry-run";
+       if (flags & TRANSPORT_PUSH_VERBOSE)
+               argv[argc++] = "--verbose";
        if (data->receivepack) {
                char *rp = xmalloc(strlen(data->receivepack) + 16);
                sprintf(rp, "--receive-pack=%s", data->receivepack);
index df12ea74243cab68cc13eecf61106bba8ace1be4..2f80ab4b03df181dc8b041b1aace5832aa84deb1 100644 (file)
@@ -30,6 +30,7 @@ struct transport {
 #define TRANSPORT_PUSH_ALL 1
 #define TRANSPORT_PUSH_FORCE 2
 #define TRANSPORT_PUSH_DRY_RUN 4
+#define TRANSPORT_PUSH_VERBOSE 8
 
 /* Returns a transport suitable for the url */
 struct transport *transport_get(struct remote *, const char *);
index 67994680f2f48e573f78c592c853422e6d8995cf..7e04311027176fc87c1de7dd619000d2a75d4eb9 100644 (file)
@@ -144,6 +144,7 @@ static void create_pack_file(void)
        char abort_msg[] = "aborting due to possible repository "
                "corruption on the remote side.";
        int buffered = -1;
+       ssize_t sz;
        const char *argv[10];
        int arg = 0;
 
@@ -168,22 +169,15 @@ static void create_pack_file(void)
        pack_objects.git_cmd = 1;
        pack_objects.argv = argv;
 
-       if (start_command(&pack_objects)) {
-               /* daemon sets things up to ignore TERM */
-               kill(rev_list.pid, SIGKILL);
+       if (start_command(&pack_objects))
                die("git-upload-pack: unable to fork git-pack-objects");
-       }
 
        /* We read from pack_objects.err to capture stderr output for
         * progress bar, and pack_objects.out to capture the pack data.
         */
 
        while (1) {
-               const char *who;
                struct pollfd pfd[2];
-               pid_t pid;
-               int status;
-               ssize_t sz;
                int pe, pu, pollsize;
 
                reset_timeout();
@@ -204,123 +198,91 @@ static void create_pack_file(void)
                        pollsize++;
                }
 
-               if (pollsize) {
-                       if (poll(pfd, pollsize, -1) < 0) {
-                               if (errno != EINTR) {
-                                       error("poll failed, resuming: %s",
-                                             strerror(errno));
-                                       sleep(1);
-                               }
-                               continue;
-                       }
-                       if (0 <= pu && (pfd[pu].revents & (POLLIN|POLLHUP))) {
-                               /* Data ready; we keep the last byte
-                                * to ourselves in case we detect
-                                * broken rev-list, so that we can
-                                * leave the stream corrupted.  This
-                                * is unfortunate -- unpack-objects
-                                * would happily accept a valid pack
-                                * data with trailing garbage, so
-                                * appending garbage after we pass all
-                                * the pack data is not good enough to
-                                * signal breakage to downstream.
-                                */
-                               char *cp = data;
-                               ssize_t outsz = 0;
-                               if (0 <= buffered) {
-                                       *cp++ = buffered;
-                                       outsz++;
-                               }
-                               sz = xread(pack_objects.out, cp,
-                                         sizeof(data) - outsz);
-                               if (0 < sz)
-                                               ;
-                               else if (sz == 0) {
-                                       close(pack_objects.out);
-                                       pack_objects.out = -1;
-                               }
-                               else
-                                       goto fail;
-                               sz += outsz;
-                               if (1 < sz) {
-                                       buffered = data[sz-1] & 0xFF;
-                                       sz--;
-                               }
-                               else
-                                       buffered = -1;
-                               sz = send_client_data(1, data, sz);
-                               if (sz < 0)
-                                       goto fail;
-                       }
-                       if (0 <= pe && (pfd[pe].revents & (POLLIN|POLLHUP))) {
-                               /* Status ready; we ship that in the side-band
-                                * or dump to the standard error.
-                                */
-                               sz = xread(pack_objects.err, progress,
-                                         sizeof(progress));
-                               if (0 < sz)
-                                       send_client_data(2, progress, sz);
-                               else if (sz == 0) {
-                                       close(pack_objects.err);
-                                       pack_objects.err = -1;
-                               }
-                               else
-                                       goto fail;
+               if (!pollsize)
+                       break;
+
+               if (poll(pfd, pollsize, -1) < 0) {
+                       if (errno != EINTR) {
+                               error("poll failed, resuming: %s",
+                                     strerror(errno));
+                               sleep(1);
                        }
+                       continue;
                }
-
-               /* See if the children are still there */
-               if (rev_list.pid || pack_objects.pid) {
-                       pid = waitpid(-1, &status, WNOHANG);
-                       if (!pid)
-                               continue;
-                       who = ((pid == rev_list.pid) ? "git-rev-list" :
-                              (pid == pack_objects.pid) ? "git-pack-objects" :
-                              NULL);
-                       if (!who) {
-                               if (pid < 0) {
-                                       error("git-upload-pack: %s",
-                                             strerror(errno));
-                                       goto fail;
-                               }
-                               error("git-upload-pack: we weren't "
-                                     "waiting for %d", pid);
-                               continue;
+               if (0 <= pu && (pfd[pu].revents & (POLLIN|POLLHUP))) {
+                       /* Data ready; we keep the last byte to ourselves
+                        * in case we detect broken rev-list, so that we
+                        * can leave the stream corrupted.  This is
+                        * unfortunate -- unpack-objects would happily
+                        * accept a valid packdata with trailing garbage,
+                        * so appending garbage after we pass all the
+                        * pack data is not good enough to signal
+                        * breakage to downstream.
+                        */
+                       char *cp = data;
+                       ssize_t outsz = 0;
+                       if (0 <= buffered) {
+                               *cp++ = buffered;
+                               outsz++;
+                       }
+                       sz = xread(pack_objects.out, cp,
+                                 sizeof(data) - outsz);
+                       if (0 < sz)
+                                       ;
+                       else if (sz == 0) {
+                               close(pack_objects.out);
+                               pack_objects.out = -1;
                        }
-                       if (!WIFEXITED(status) || WEXITSTATUS(status) > 0) {
-                               error("git-upload-pack: %s died with error.",
-                                     who);
+                       else
                                goto fail;
+                       sz += outsz;
+                       if (1 < sz) {
+                               buffered = data[sz-1] & 0xFF;
+                               sz--;
                        }
-                       if (pid == rev_list.pid)
-                               rev_list.pid = 0;
-                       if (pid == pack_objects.pid)
-                               pack_objects.pid = 0;
-                       if (rev_list.pid || pack_objects.pid)
-                               continue;
-               }
-
-               /* both died happily */
-               if (pollsize)
-                       continue;
-
-               /* flush the data */
-               if (0 <= buffered) {
-                       data[0] = buffered;
-                       sz = send_client_data(1, data, 1);
+                       else
+                               buffered = -1;
+                       sz = send_client_data(1, data, sz);
                        if (sz < 0)
                                goto fail;
-                       fprintf(stderr, "flushed.\n");
                }
-               if (use_sideband)
-                       packet_flush(1);
-               return;
+               if (0 <= pe && (pfd[pe].revents & (POLLIN|POLLHUP))) {
+                       /* Status ready; we ship that in the side-band
+                        * or dump to the standard error.
+                        */
+                       sz = xread(pack_objects.err, progress,
+                                 sizeof(progress));
+                       if (0 < sz)
+                               send_client_data(2, progress, sz);
+                       else if (sz == 0) {
+                               close(pack_objects.err);
+                               pack_objects.err = -1;
+                       }
+                       else
+                               goto fail;
+               }
+       }
+
+       if (finish_command(&pack_objects)) {
+               error("git-upload-pack: git-pack-objects died with error.");
+               goto fail;
+       }
+       if (finish_async(&rev_list))
+               goto fail;      /* error was already reported */
+
+       /* flush the data */
+       if (0 <= buffered) {
+               data[0] = buffered;
+               sz = send_client_data(1, data, 1);
+               if (sz < 0)
+                       goto fail;
+               fprintf(stderr, "flushed.\n");
        }
+       if (use_sideband)
+               packet_flush(1);
+       return;
+
  fail:
-       if (pack_objects.pid)
-               kill(pack_objects.pid, SIGKILL);
-       if (rev_list.pid)
-               kill(rev_list.pid, SIGKILL);
        send_client_data(3, abort_msg, sizeof(abort_msg));
        die("git-upload-pack: %s", abort_msg);
 }
diff --git a/usage.c b/usage.c
index f5e652cc76d7587fd7b682eb865d3436c99b16fb..a5fc4ec5fae66823266862fa0254474696c220e6 100644 (file)
--- a/usage.c
+++ b/usage.c
@@ -7,9 +7,9 @@
 
 static void report(const char *prefix, const char *err, va_list params)
 {
-       fputs(prefix, stderr);
-       vfprintf(stderr, err, params);
-       fputs("\n", stderr);
+       char msg[256];
+       vsnprintf(msg, sizeof(msg), err, params);
+       fprintf(stderr, "%s%s\n", prefix, msg);
 }
 
 static NORETURN void usage_builtin(const char *err)