Merge branch 'ph/parseopt-sh'
authorJunio C Hamano <gitster@pobox.com>
Sun, 18 Nov 2007 05:39:37 +0000 (21:39 -0800)
committerJunio C Hamano <gitster@pobox.com>
Sun, 18 Nov 2007 05:39:37 +0000 (21:39 -0800)
* ph/parseopt-sh:
git-quiltimport.sh fix --patches handling
git-am: -i does not take a string parameter.
sh-setup: don't let eval output to be shell-expanded.
git-sh-setup: fix parseopt `eval` string underquoting
Give git-am back the ability to add Signed-off-by lines.
git-rev-parse --parseopt
scripts: Add placeholders for OPTIONS_SPEC
Migrate git-repack.sh to use git-rev-parse --parseopt
Migrate git-quiltimport.sh to use git-rev-parse --parseopt
Migrate git-checkout.sh to use git-rev-parse --parseopt --keep-dashdash
Migrate git-instaweb.sh to use git-rev-parse --parseopt
Migrate git-merge.sh to use git-rev-parse --parseopt
Migrate git-am.sh to use git-rev-parse --parseopt
Migrate git-clone to use git-rev-parse --parseopt
Migrate git-clean.sh to use git-rev-parse --parseopt.
Update git-sh-setup(1) to allow transparent use of git-rev-parse --parseopt
Add a parseopt mode to git-rev-parse to bring parse-options to shell scripts.

143 files changed:
Documentation/CodingGuidelines [new file with mode: 0644]
Documentation/Makefile
Documentation/RelNotes-1.5.3.5.txt
Documentation/RelNotes-1.5.3.6.txt [new file with mode: 0644]
Documentation/RelNotes-1.5.4.txt
Documentation/SubmittingPatches
Documentation/asciidoc.conf
Documentation/cmd-list.perl
Documentation/config.txt
Documentation/core-tutorial.txt
Documentation/diff-options.txt
Documentation/git-add.txt
Documentation/git-branch.txt
Documentation/git-clone.txt
Documentation/git-commit.txt
Documentation/git-cvsexportcommit.txt
Documentation/git-diff.txt
Documentation/git-format-patch.txt
Documentation/git-get-tar-commit-id.txt
Documentation/git-local-fetch.txt [deleted file]
Documentation/git-lost-found.txt
Documentation/git-ls-files.txt
Documentation/git-push.txt
Documentation/git-remote.txt
Documentation/git-reset.txt
Documentation/git-rev-list.txt
Documentation/git-send-email.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/urls.txt
Documentation/user-manual.txt
Makefile
builtin-add.c
builtin-apply.c
builtin-blame.c
builtin-diff.c
builtin-fetch--tool.c
builtin-fetch-pack.c
builtin-fetch.c
builtin-for-each-ref.c
builtin-log.c
builtin-ls-files.c
builtin-mailsplit.c
builtin-push.c
builtin-reset.c
builtin-rev-list.c
builtin-revert.c
builtin-rm.c
builtin-tag.c
bundle.c
cache.h
check-racy.c
config.c
config.mak.in
configure.ac
contrib/fast-import/git-p4
contrib/hooks/post-receive-email
csum-file.c
csum-file.h
daemon.c
diff-lib.c
diff.h
dir.c
dir.h
entry.c
environment.c
fast-import.c
git-add--interactive.perl
git-bisect.sh
git-clean.sh
git-commit.sh
git-compat-util.h
git-cvsexportcommit.perl
git-cvsimport.perl
git-instaweb.sh
git-lost-found.sh
git-merge.sh
git-rebase--interactive.sh
git-rebase.sh
git-request-pull.sh
git-send-email.perl
git-stash.sh
git-submodule.sh
git-svn.perl
git.c
gitweb/gitweb.perl
hash-object.c
help.c
index-pack.c
list-objects.c
parse-options.c
perl/Git.pm
pretty.c
progress.c
progress.h
quote.c
read-cache.c
refs.c
refs.h
run-command.c
run-command.h
setup.c
sideband.c
strbuf.c
strbuf.h
t/t0040-parse-options.sh
t/t1400-update-ref.sh
t/t2200-add-update.sh
t/t3402-rebase-merge.sh
t/t3403-rebase-skip.sh
t/t3404-rebase-interactive.sh
t/t3700-add.sh
t/t4021-format-patch-numbered.sh [new file with mode: 0755]
t/t5502-quickfetch.sh
t/t5530-upload-pack-error.sh [new file with mode: 0755]
t/t6300-for-each-ref.sh
t/t7004-tag.sh
t/t7005-editor.sh
t/t7102-reset.sh
t/t7201-co.sh
t/t7300-clean.sh
t/t7500-commit.sh
t/t7501-commit.sh
t/t9101-git-svn-props.sh
t/t9106-git-svn-dcommit-clobber-series.sh
t/t9116-git-svn-log.sh
t/t9117-git-svn-init-clone.sh [new file with mode: 0755]
t/t9118-git-svn-funky-branch-names.sh [new file with mode: 0755]
t/test-lib.sh
templates/hooks--update
test-parse-options.c
trace.c
transport.c
transport.h
unpack-trees.c
upload-pack.c
usage.c
utf8.c
wt-status.c
xdiff/xdiffi.c
xdiff/xutils.c
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
new file mode 100644 (file)
index 0000000..3b042db
--- /dev/null
@@ -0,0 +1,112 @@
+Like other projects, we also have some guidelines to keep to the
+code.  For git in general, three rough rules are:
+
+ - Most importantly, we never say "It's in POSIX; we'll happily
+   ignore your needs should your system not conform to it."
+   We live in the real world.
+
+ - However, we often say "Let's stay away from that construct,
+   it's not even in POSIX".
+
+ - In spite of the above two rules, we sometimes say "Although
+   this is not in POSIX, it (is so convenient | makes the code
+   much more readable | has other good characteristics) and
+   practically all the platforms we care about support it, so
+   let's use it".
+
+   Again, we live in the real world, and it is sometimes a
+   judgement call, the decision based more on real world
+   constraints people face than what the paper standard says.
+
+
+As for more concrete guidelines, just imitate the existing code
+(this is a good guideline, no matter which project you are
+contributing to).  But if you must have a list of rules,
+here they are.
+
+For shell scripts specifically (not exhaustive):
+
+ - We prefer $( ... ) for command substitution; unlike ``, it
+   properly nests.  It should have been the way Bourne spelled
+   it from day one, but unfortunately isn't.
+
+ - We use ${parameter-word} and its [-=?+] siblings, and their
+   colon'ed "unset or null" form.
+
+ - We use ${parameter#word} and its [#%] siblings, and their
+   doubled "longest matching" form.
+
+ - We use Arithmetic Expansion $(( ... )).
+
+ - No "Substring Expansion" ${parameter:offset:length}.
+
+ - No shell arrays.
+
+ - No strlen ${#parameter}.
+
+ - No regexp ${parameter/pattern/string}.
+
+ - We do not use Process Substitution <(list) or >(list).
+
+ - We prefer "test" over "[ ... ]".
+
+ - We do not write the noiseword "function" in front of shell
+   functions.
+
+For C programs:
+
+ - We use tabs to indent, and interpret tabs as taking up to
+   8 spaces.
+
+ - We try to keep to at most 80 characters per line.
+
+ - When declaring pointers, the star sides with the variable
+   name, i.e. "char *string", not "char* string" or
+   "char * string".  This makes it easier to understand code
+   like "char *string, c;".
+
+ - We avoid using braces unnecessarily.  I.e.
+
+       if (bla) {
+               x = 1;
+       }
+
+   is frowned upon.  A gray area is when the statement extends
+   over a few lines, and/or you have a lengthy comment atop of
+   it.  Also, like in the Linux kernel, if there is a long list
+   of "else if" statements, it can make sense to add braces to
+   single line blocks.
+
+ - Try to make your code understandable.  You may put comments
+   in, but comments invariably tend to stale out when the code
+   they were describing changes.  Often splitting a function
+   into two makes the intention of the code much clearer.
+
+ - Double negation is often harder to understand than no negation
+   at all.
+
+ - Some clever tricks, like using the !! operator with arithmetic
+   constructs, can be extremely confusing to others.  Avoid them,
+   unless there is a compelling reason to use them.
+
+ - Use the API.  No, really.  We have a strbuf (variable length
+   string), several arrays with the ALLOC_GROW() macro, a
+   path_list for sorted string lists, a hash map (mapping struct
+   objects) named "struct decorate", amongst other things.
+
+ - When you come up with an API, document it.
+
+ - The first #include in C files, except in platform specific
+   compat/ implementations, should be git-compat-util.h or another
+   header file that includes it, such as cache.h or builtin.h.
+
+ - If you are planning a new command, consider writing it in shell
+   or perl first, so that changes in semantics can be easily
+   changed and discussed.  Many git commands started out like
+   that, and a few are still scripts.
+
+ - Avoid introducing a new dependency into git. This means you
+   usually should stay away from scripting languages not already
+   used in the git core command set (unless your command is clearly
+   separate from it, such as an importer to convert random-scm-X
+   repositories to git).
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 f99a2cd65003c06ef5da26a4508b4ce74d6b267f..7ff1d5d0d100fc632208f4cbb67189ecbf58e9a4 100644 (file)
@@ -90,5 +90,5 @@ Fixes since v1.5.3.4
  * "git-send-pack $remote frotz" segfaulted when there is nothing
    named 'frotz' on the local end.
 
- * "git-rebase -interactive" did not handle its "--strategy" option
+ * "git-rebase --interactive" did not handle its "--strategy" option
    properly.
diff --git a/Documentation/RelNotes-1.5.3.6.txt b/Documentation/RelNotes-1.5.3.6.txt
new file mode 100644 (file)
index 0000000..c9f948e
--- /dev/null
@@ -0,0 +1,52 @@
+GIT v1.5.3.6 Release Notes
+==========================
+
+Fixes since v1.5.3.5
+--------------------
+
+ * git-cvsexportcommit handles root commits better;
+
+ * git-svn dcommit used to clobber when sending a series of
+   patches;
+
+ * git-svn dcommit failed after attempting to rebase when
+   started with a dirty index; now it stops upfront.
+
+ * git-grep sometimes refused to work when your index was
+   unmerged;
+
+ * git-hash-object did not honor configuration variables, such as
+   core.compression.
+
+ * git-index-pack choked on a huge pack on 32-bit machines, even when
+   large file offsets are supported.
+
+ * atom feeds from git-web said "10" for the month of November.
+
+ * a memory leak in commit walker was plugged.
+
+ * When git-send-email inserted the original author's From:
+   address in body, it did not mark the message with
+   Content-type: as needed.
+
+ * git-revert and git-cherry-pick incorrectly refused to start
+   when the work tree was dirty.
+
+ * git-clean did not honor core.excludesfile configuration.
+
+ * git-add mishandled ".gitignore" files when applying them to
+   subdirectories.
+
+ * While importing a too branchy history, git-fastimport did not
+   honor delta depth limit properly.
+
+ * Support for zlib implementations that lack ZLIB_VERNUM and definition
+   of deflateBound() has been added.
+
+ * Quite a lot of documentation clarifications.
+
+--
+exec >/var/tmp/1
+O=v1.5.3.5-57-gb574c8d
+echo O=`git describe refs/heads/maint`
+git shortlog --no-merges $O..refs/heads/maint
index 133fa64d226d3e1265144c3504c06d6e3f9e8c33..229d773423f9a88a9aefb6594e69b510d054d1bc 100644 (file)
@@ -6,7 +6,10 @@ Updates since v1.5.3
 
  * Comes with much improved gitk.
 
- * git-reset is now built-in.
+ * "progress display" from many commands are a lot nicer to the
+   eye.  Transfer commands show throughput data.
+
+ * git-reset is now built-in and its output can be squelched with -q.
 
  * git-send-email can optionally talk over ssmtp and use SMTP-AUTH.
 
@@ -29,6 +32,10 @@ Updates since v1.5.3
    (read: safer than the usual one) after the user accumulates
    too many loose objects.
 
+ * You need to explicitly set clean.requireForce to true to allow
+   git-clean to do any damage now (the configuration variable used
+   to default to false).
+
  * git-push has been rewritten in C.
 
  * git-push learned --dry-run option to show what would happen
@@ -46,14 +53,60 @@ Updates since v1.5.3
 
  * Various Perforce importer updates.
 
+ * git-lost-found was deprecated in favor of git-fsck's --lost-found
+   option.
+
+ * git-svnimport was removed in favor of git-svn.
+
+ * git-bisect learned "skip" action to mark untestable commits.
+
+ * git-format-patch learned "format.numbered" configuration variable
+   to automatically turn --numbered option on when more than one
+   commits are formatted.
+
+ * git-ls-files learned "--exclude-standard" to use the canned
+   set of exclude files.
+
+ * git-rebase now detaches head during its operation, so after a
+   successful "git rebase" operation, the reflog entry branch@{1}
+   for the current branch points at the commit before the rebase
+   was started.
+
+ * "git-tag -a -f existing" begins the editor session using the
+   existing annotation message.
+
+ * "git cvsexportcommit" learned -w option to specify and switch
+   to the CVS working directory.
+
+ * Output processing for '--pretty=format:<user format>' has
+   been optimized.
+
+ * Rename detection diff family, while detecting exact matches,
+   has been greatly optimized.
+
+ * Example update and post-receive hooks have been improved.
+
+ * In addition there are quite a few internal clean-ups. Notably
+
+   - many fork/exec have been replaced with run-command API,
+     brought from the msysgit effort.
+
+   - introduction and more use of the option parser API.
+
+   - enhancement and more use of the strbuf API.
+
+
 Fixes since v1.5.3
 ------------------
 
 All of the fixes in v1.5.3 maintenance series are included in
 this release, unless otherwise noted.
 
+ * git-svn talking with the SVN over http will correctly quote branch
+   and project names.
+
 --
 exec >/var/tmp/1
-O=v1.5.3.4-450-g952a9e5
+O=v1.5.3.5-736-geb9d2b9
 echo O=`git describe refs/heads/master`
 git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint
index 61635bf04dc8aac5ec491f16c9c9b796457679c0..83bf54c7ac153b7010dcecc34d28c05dc68c10b6 100644 (file)
@@ -20,9 +20,6 @@ Checklist (and a short version for the impatient):
        Patch:
 
        - use "git format-patch -M" to create the patch
-       - send your patch to <git@vger.kernel.org>. If you use
-         git-send-email(1), please test it first by sending
-         email to yourself.
        - do not PGP sign your patch
        - do not attach your patch, but read in the mail
          body, unless you cannot teach your mailer to
@@ -31,13 +28,15 @@ Checklist (and a short version for the impatient):
          corrupt whitespaces.
        - provide additional information (which is unsuitable for
          the commit message) between the "---" and the diffstat
-       - send the patch to the list (git@vger.kernel.org) and the
-         maintainer (gitster@pobox.com).
        - if you change, add, or remove a command line option or
          make some other user interface change, the associated
          documentation should be updated as well.
        - if your name is not writable in ASCII, make sure that
          you send off a message in the correct encoding.
+       - send the patch to the list (git@vger.kernel.org) and the
+         maintainer (gitster@pobox.com). If you use
+         git-send-email(1), please test it first by sending
+         email to yourself.
 
 Long version:
 
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 0df004ea261d6862db0a9b528ec7f2c11bdd5b65..6dc9f3ed02b2dd4a3fe439c28df7b2ba6778244d 100644 (file)
@@ -345,8 +345,8 @@ branch.<name>.mergeoptions::
        supported.
 
 clean.requireForce::
-       A boolean to make git-clean do nothing unless given -f or -n.  Defaults
-       to false.
+       A boolean to make git-clean do nothing unless given -f
+       or -n.   Defaults to true.
 
 color.branch::
        A boolean to enable/disable color in the output of
@@ -432,6 +432,12 @@ fetch.unpackLimit::
        pack from a push can make the push operation complete faster,
        especially on slow filesystems.
 
+format.numbered::
+       A boolean which can enable sequence numbers in patch subjects.
+       Seting this option to "auto" will enable it only if there is
+       more than one patch.  See --numbered option in
+       gitlink:git-format-patch[1].
+
 format.headers::
        Additional email headers to include in a patch to be submitted
        by mail.  See gitlink:git-format-patch[1].
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 b1f528ae8864e429a509365a79d16bb8341620e1..e4af393515c346528bccb7a4f2d3823aebddddfc 100644 (file)
@@ -1,5 +1,25 @@
+// Please don't remove this comment as asciidoc behaves badly when
+// the first non-empty line is ifdef/ifndef. The symptom is that
+// without this comment the <git-diff-core> attribute conditionally
+// defined below ends up being defined unconditionally.
+// Last checked with asciidoc 7.0.2.
+
+ifndef::git-format-patch[]
+ifndef::git-diff[]
+:git-diff-core: 1
+endif::git-diff[]
+endif::git-format-patch[]
+
+ifdef::git-format-patch[]
 -p::
-       Generate patch (see section on generating patches)
+       Generate patches without diffstat.
+endif::git-format-patch[]
+
+ifndef::git-format-patch[]
+-p::
+       Generate patch (see section on generating patches).
+       {git-diff? This is the default.}
+endif::git-format-patch[]
 
 -u::
        Synonym for "-p".
@@ -13,6 +33,7 @@
 
 --raw::
        Generate the raw format.
+       {git-diff-core? This is the default.}
 
 --patch-with-raw::
        Synonym for "-p --raw".
@@ -41,6 +62,7 @@
 
 --patch-with-stat::
        Synonym for "-p --stat".
+       {git-format-patch? This is the default.}
 
 -z::
        NUL-line termination on output.  This affects the --raw
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 14e58f3866e3a4e7d1da01753cb68082e88ae2f6..c90bcece24c0fcbf9513af7808f6d0d13846c528 100644 (file)
@@ -130,6 +130,7 @@ OPTIONS
        for "host.xz:foo/.git").  Cloning into an existing directory
        is not allowed.
 
+:git-clone: 1
 include::urls.txt[]
 
 Examples
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 11c4216c4a5c705c6af55b1367cae96b13c20251..2808a5ec44d8a9e911faf4c7d24eb844d69390f2 100644 (file)
@@ -75,6 +75,7 @@ and the range notations ("<commit>..<commit>" and
 
 OPTIONS
 -------
+:git-diff: 1
 include::diff-options.txt[]
 
 <path>...::
index f0617efa0ab5d6c046e2b880a710ab852f1afd6a..6fb94298516620e6991e82272a7e657a8296f7ca 100644 (file)
@@ -9,9 +9,10 @@ git-format-patch - Prepare patches for e-mail submission
 SYNOPSIS
 --------
 [verse]
-'git-format-patch' [-n | -k] [-o <dir> | --stdout] [--thread]
+'git-format-patch' [-k] [-o <dir> | --stdout] [--thread]
                    [--attach[=<boundary>] | --inline[=<boundary>]]
                    [-s | --signoff] [<common diff options>]
+                   [-n | --numbered | -N | --no-numbered]
                    [--start-number <n>] [--numbered-files]
                    [--in-reply-to=Message-Id] [--suffix=.<sfx>]
                    [--ignore-if-in-upstream]
@@ -65,6 +66,7 @@ reference.
 
 OPTIONS
 -------
+:git-format-patch: 1
 include::diff-options.txt[]
 
 -<n>::
@@ -77,6 +79,9 @@ include::diff-options.txt[]
 -n|--numbered::
        Name output in '[PATCH n/m]' format.
 
+-N|--no-numbered::
+       Name output in '[PATCH]' format.
+
 --start-number <n>::
        Start numbering the patches at <n> instead of 1.
 
@@ -142,15 +147,16 @@ not add any suffix.
 
 CONFIGURATION
 -------------
-You can specify extra mail header lines to be added to each
-message in the repository configuration.  You can also specify
-new defaults for the subject prefix and file suffix.
+You can specify extra mail header lines to be added to each message
+in the repository configuration, new defaults for the subject prefix
+and file suffix, and number patches when outputting more than one.
 
 ------------
 [format]
         headers = "Organization: git-foo\n"
         subjectprefix = CHANGE
         suffix = .txt
+        numbered = auto
 ------------
 
 
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 bc739117beaf0a3ca56c4158e40f8879d74018e3..7f808fcd767993a60fb96a2876475e696a0f5900 100644 (file)
@@ -11,6 +11,10 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
+
+*NOTE*: this command is deprecated.  Use gitlink:git-fsck[1] with
+the option '--lost-found' instead.
+
 Finds dangling commits and tags from the object database, and
 creates refs to them in the .git/lost-found/ directory.  Commits and
 tags that dereference to commits are stored in .git/lost-found/commit,
index 9e454f0a4da465606afbed1720b7bd10cca8b241..2ec0c0d270edde03adff3f56531e4cee5fe05a57 100644 (file)
@@ -15,6 +15,7 @@ SYNOPSIS
                [-x <pattern>|--exclude=<pattern>]
                [-X <file>|--exclude-from=<file>]
                [--exclude-per-directory=<file>]
+               [--exclude-standard]
                [--error-unmatch] [--with-tree=<tree-ish>]
                [--full-name] [--abbrev] [--] [<file>]\*
 
@@ -77,6 +78,10 @@ OPTIONS
        read additional exclude patterns that apply only to the
        directory and its subdirectories in <file>.
 
+--exclude-standard::
+       Add the standard git exclusions: .git/info/exclude, .gitignore
+       in each directory, and the user's global exclusion file.
+
 --error-unmatch::
        If any <file> does not appear in the index, treat this as an
        error (return 1).
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]).
 
index 87afa6f8da0c6421e909663fe79a6f8b0fc0a7d8..050e4eadbb3d5b8f60edc173f2f17fdc959dde5d 100644 (file)
@@ -8,8 +8,8 @@ git-reset - Reset current HEAD to the specified state
 SYNOPSIS
 --------
 [verse]
-'git-reset' [--mixed | --soft | --hard] [<commit>]
-'git-reset' [--mixed] <commit> [--] <paths>...
+'git-reset' [--mixed | --soft | --hard] [-q] [<commit>]
+'git-reset' [--mixed] [-q] <commit> [--] <paths>...
 
 DESCRIPTION
 -----------
@@ -45,6 +45,9 @@ OPTIONS
        switched to. Any changes to tracked files in the working tree
        since <commit> are lost.
 
+-q::
+       Be quiet, only report errors.
+
 <commit>::
        Commit to make the current HEAD.
 
index 485280423e90bac43b4c372bbc8d350c34cf4fa8..989fbf3562977866d7d2558022587847f538ae4b 100644 (file)
@@ -20,6 +20,7 @@ SYNOPSIS
             [ \--not ]
             [ \--all ]
             [ \--stdin ]
+            [ \--quiet ]
             [ \--topo-order ]
             [ \--parents ]
             [ \--timestamp ]
@@ -270,6 +271,14 @@ limiting may be applied.
        In addition to the '<commit>' listed on the command
        line, read them from the standard input.
 
+--quiet::
+
+       Don't print anything to standard output.  This form of
+       git-rev-list is primarly meant to allow the caller to
+       test the exit status to see if a range of objects is fully
+       connected (or not).  It is faster than redirecting stdout
+       to /dev/null as the output does not have to be formatted.
+
 --cherry-pick::
 
        Omit any commit that introduces the same change as
index e38b7021b4d38c07bd794e59be0a5e0747a8b775..659215ac7221d5c8b6aa78bef2fcadce24ada8c3 100644 (file)
@@ -113,8 +113,7 @@ The --cc option must be repeated for each user you want on the cc list.
        is not set, this will be prompted for.
 
 --suppress-from, --no-suppress-from::
-        If this is set, do not add the From: address to the cc: list, if it
-        shows up in a From: line.
+        If this is set, do not add the From: address to the cc: list.
         Default is the value of 'sendemail.suppressfrom' configuration value;
         if that is unspecified, default to --no-suppress-from.
 
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 e67f9140ab6be15499b60a8a87ec524a5357a284..4f667382ec1b3a93871c8b2beb31111278ec27b8 100644 (file)
@@ -36,5 +36,11 @@ To sync with a local directory, you can use:
 - file:///path/to/repo.git/
 ===============================================================
 
+ifndef::git-clone[]
 They are mostly equivalent, except when cloning.  See
 gitlink:git-clone[1] for details.
+endif::git-clone[]
+
+ifdef::git-clone[]
+They are equivalent, except the former implies --local option.
+endif::git-clone[]
index d99adc6f728aebfa0b7e4b956c4f784e3d2f7bd4..518b7b5c9e283eccd20ce2d84ea85f107c98ca39 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
@@ -1567,9 +1567,9 @@ old history using, for example,
 $ 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,
-not just with git log.  Some other examples:
+This lists the commits reachable from the previous version of the
+"master" branch head.  This syntax can be used with any git command
+that accepts a commit, not just with git log.  Some other examples:
 
 -------------------------------------------------
 $ git show master@{2}          # See where the branch pointed 2,
index cf8ec49d12d59bd0c00f55b4030ebdee146eefeb..e830bc7445c5753b29b6bb329ec8d977557df97b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -98,6 +98,8 @@ all::
 # Define OLD_ICONV if your library has an old iconv(), where the second
 # (input buffer pointer) parameter is declared with type (const char **).
 #
+# Define NO_DEFLATE_BOUND if your zlib does not have deflateBound.
+#
 # Define NO_R_TO_GCC_LINKER if your gcc does not like "-R/path/lib"
 # that tells runtime paths to dynamic libraries;
 # "-Wl,-rpath=/path/lib" is used instead.
@@ -113,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).
 #
@@ -661,6 +665,10 @@ ifdef OLD_ICONV
        BASIC_CFLAGS += -DOLD_ICONV
 endif
 
+ifdef NO_DEFLATE_BOUND
+       BASIC_CFLAGS += -DNO_DEFLATE_BOUND
+endif
+
 ifdef PPC_SHA1
        SHA1_HEADER = "ppc/sha1.h"
        LIB_OBJS += ppc/sha1.o ppc/sha1ppc.o
@@ -916,6 +924,7 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS)
 
 $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
 $(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
+builtin-revert.o builtin-runstatus.o wt-status.o: wt-status.h
 
 $(LIB_FILE): $(LIB_OBJS)
        $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(LIB_OBJS)
@@ -991,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)
@@ -1119,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" || \
@@ -1135,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 45b14e8a61764e18d8b89ebfef550a820ffbf831..cf815a0b8ef0e588cfaf25f71747ba7248d19d70 100644 (file)
@@ -21,7 +21,6 @@ static const char * const builtin_add_usage[] = {
 };
 
 static int take_worktree_changes;
-static const char *excludes_file;
 
 static void prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)
 {
@@ -61,12 +60,7 @@ static void fill_directory(struct dir_struct *dir, const char **pathspec,
        memset(dir, 0, sizeof(*dir));
        if (!ignored_too) {
                dir->collect_ignored = 1;
-               dir->exclude_per_dir = ".gitignore";
-               path = git_path("info/exclude");
-               if (!access(path, R_OK))
-                       add_excludes_from_file(dir, path);
-               if (excludes_file != NULL && !access(excludes_file, R_OK))
-                       add_excludes_from_file(dir, excludes_file);
+               setup_standard_excludes(dir);
        }
 
        /*
@@ -120,7 +114,7 @@ void add_files_to_cache(int verbose, const char *prefix, const char **files)
        rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
        rev.diffopt.format_callback = update_callback;
        rev.diffopt.format_callback_data = &verbose;
-       run_diff_files(&rev, 0);
+       run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
 }
 
 static void refresh(int verbose, const char **pathspec)
@@ -141,18 +135,6 @@ static void refresh(int verbose, const char **pathspec)
         free(seen);
 }
 
-static int git_add_config(const char *var, const char *value)
-{
-       if (!strcmp(var, "core.excludesfile")) {
-               if (!value)
-                       die("core.excludesfile without value");
-               excludes_file = xstrdup(value);
-               return 0;
-       }
-
-       return git_default_config(var, value);
-}
-
 int interactive_add(void)
 {
        const char *argv[2] = { "add--interactive", NULL };
@@ -193,7 +175,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
                exit(interactive_add());
        }
 
-       git_config(git_add_config);
+       git_config(git_default_config);
 
        newfd = hold_locked_index(&lock_file, 1);
 
index 8411b38c7963852bffeb6dea1494399e8c9daa02..91f8752ff7fdb588e64f594519a2e9503c516630 100644 (file)
@@ -683,7 +683,6 @@ static char *git_header_name(char *line, int llen)
                        }
                }
        }
-       return NULL;
 }
 
 /* Verify that we recognize the lines following a git header */
@@ -1993,7 +1992,7 @@ static int verify_index_match(struct cache_entry *ce, struct stat *st)
                        return -1;
                return 0;
        }
-       return ce_match_stat(ce, st, 1);
+       return ce_match_stat(ce, st, CE_MATCH_IGNORE_VALID);
 }
 
 static int check_patch(struct patch *patch, struct patch *prev_patch)
index aedc294eac276af8d1a3e8c39bf93fa8fda93f94..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));
@@ -2342,6 +2343,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                 * do not default to HEAD, but use the working tree
                 * or "--contents".
                 */
+               setup_work_tree();
                sb.final = fake_working_tree_commit(path, contents_from);
                add_pending_object(&revs, &(sb.final->object), ":");
        }
index f77352b40decdc4cf8d2db29102703cb1193b49c..f557d21929fe3df018f30e68c7943ead7f8eb4a1 100644 (file)
@@ -200,15 +200,11 @@ static void refresh_index_quietly(void)
        discard_cache();
        read_cache();
        refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED);
-       if (active_cache_changed) {
-               if (write_cache(fd, active_cache, active_nr) ||
-                   close(fd) ||
-                   commit_locked_index(lock_file))
-                       ; /*
-                          * silently ignore it -- we haven't mucked
-                          * with the real index.
-                          */
-       }
+
+       if (active_cache_changed &&
+           !write_cache(fd, active_cache, active_nr) && !close(fd))
+               commit_locked_index(lock_file);
+
        rollback_lock_file(lock_file);
 }
 
index 6a78517958567e9dee4bfb00236caf5c3d1c3d67..ed60847d9fcd0ad8803c432af8d0bc2dd3567768 100644 (file)
@@ -435,9 +435,7 @@ static int pick_rref(int sha1_only, const char *rref, const char *ls_remote_resu
                                cp++;
                        if (!*cp)
                                break;
-                       np = strchr(cp, '\n');
-                       if (!np)
-                               np = cp + strlen(cp);
+                       np = strchrnul(cp, '\n');
                        if (pass) {
                                lrr_list[i].line = cp;
                                lrr_list[i].name = cp + 41;
@@ -461,9 +459,7 @@ static int pick_rref(int sha1_only, const char *rref, const char *ls_remote_resu
                        rref++;
                if (!*rref)
                        break;
-               next = strchr(rref, '\n');
-               if (!next)
-                       next = rref + strlen(rref);
+               next = strchrnul(rref, '\n');
                rreflen = next - rref;
 
                for (i = 0; i < lrr_count; i++) {
index 862652be92f65c50aaa900fd9983f8c54840d672..bb1742f1a267042a00f0a81bca32a4eefe87fd5d 100644 (file)
@@ -32,7 +32,7 @@ static const char fetch_pack_usage[] =
 #define MAX_IN_VAIN 256
 
 static struct commit_list *rev_list;
-static int non_common_revs, multi_ack, use_thin_pack, use_sideband;
+static int non_common_revs, multi_ack, use_sideband;
 
 static void rev_list_push(struct commit *commit, int mark)
 {
@@ -178,7 +178,7 @@ static int find_common(int fd[2], unsigned char *result_sha1,
                                     (multi_ack ? " multi_ack" : ""),
                                     (use_sideband == 2 ? " side-band-64k" : ""),
                                     (use_sideband == 1 ? " side-band" : ""),
-                                    (use_thin_pack ? " thin-pack" : ""),
+                                    (args.use_thin_pack ? " thin-pack" : ""),
                                     (args.no_progress ? " no-progress" : ""),
                                     " ofs-delta");
                else
index 5f5b59bfdb5056dfedf692215db2f9e4207f8580..be9e3ea2bcea0d0ab88a51d396aff5714822b77a 100644 (file)
@@ -8,10 +8,12 @@
 #include "path-list.h"
 #include "remote.h"
 #include "transport.h"
+#include "run-command.h"
 
 static const char fetch_usage[] = "git-fetch [-a | --append] [--upload-pack <upload-pack>] [-f | --force] [--no-tags] [-t | --tags] [-k | --keep] [-u | --update-head-ok] [--depth <depth>] [-v | --verbose] [<repository> <refspec>...]";
 
 static int append, force, tags, no_tags, update_head_ok, verbose, quiet;
+static const char *depth;
 static char *default_rla = NULL;
 static struct transport *transport;
 
@@ -152,6 +154,7 @@ static int s_update_ref(const char *action,
 }
 
 #define SUMMARY_WIDTH (2 * DEFAULT_ABBREV + 3)
+#define REFCOL_WIDTH  10
 
 static int update_local_ref(struct ref *ref,
                            const char *remote,
@@ -181,8 +184,9 @@ static int update_local_ref(struct ref *ref,
 
        if (!hashcmp(ref->old_sha1, ref->new_sha1)) {
                if (verbose)
-                       sprintf(display, "= %-*s %s -> %s", SUMMARY_WIDTH,
-                               "[up to date]", remote, pretty_ref);
+                       sprintf(display, "= %-*s %-*s -> %s", SUMMARY_WIDTH,
+                               "[up to date]", REFCOL_WIDTH, remote,
+                               pretty_ref);
                return 0;
        }
 
@@ -194,15 +198,17 @@ static int update_local_ref(struct ref *ref,
                 * If this is the head, and it's not okay to update
                 * the head, and the old value of the head isn't empty...
                 */
-               sprintf(display, "! %-*s %s -> %s  (can't  fetch in current branch)",
-                       SUMMARY_WIDTH, "[rejected]", remote, pretty_ref);
+               sprintf(display, "! %-*s %-*s -> %s  (can't fetch in current branch)",
+                       SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote,
+                       pretty_ref);
                return 1;
        }
 
        if (!is_null_sha1(ref->old_sha1) &&
            !prefixcmp(ref->name, "refs/tags/")) {
-               sprintf(display, "- %-*s %s -> %s",
-                       SUMMARY_WIDTH, "[tag update]", remote, pretty_ref);
+               sprintf(display, "- %-*s %-*s -> %s",
+                       SUMMARY_WIDTH, "[tag update]", REFCOL_WIDTH, remote,
+                       pretty_ref);
                return s_update_ref("updating tag", ref, 0);
        }
 
@@ -220,8 +226,8 @@ static int update_local_ref(struct ref *ref,
                        what = "[new branch]";
                }
 
-               sprintf(display, "* %-*s %s -> %s",
-                       SUMMARY_WIDTH, what, remote, pretty_ref);
+               sprintf(display, "* %-*s %-*s -> %s", SUMMARY_WIDTH, what,
+                       REFCOL_WIDTH, remote, pretty_ref);
                return s_update_ref(msg, ref, 0);
        }
 
@@ -230,20 +236,21 @@ static int update_local_ref(struct ref *ref,
                strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
                strcat(quickref, "..");
                strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));
-               sprintf(display, "  %-*s %s -> %s  (fast forward)",
-                       SUMMARY_WIDTH, quickref, remote, pretty_ref);
+               sprintf(display, "  %-*s %-*s -> %s", SUMMARY_WIDTH, quickref,
+                       REFCOL_WIDTH, remote, pretty_ref);
                return s_update_ref("fast forward", ref, 1);
        } else if (force || ref->force) {
                char quickref[84];
                strcpy(quickref, find_unique_abbrev(current->object.sha1, DEFAULT_ABBREV));
                strcat(quickref, "...");
                strcat(quickref, find_unique_abbrev(ref->new_sha1, DEFAULT_ABBREV));
-               sprintf(display, "+ %-*s %s -> %s  (forced update)",
-                       SUMMARY_WIDTH, quickref, remote, pretty_ref);
+               sprintf(display, "+ %-*s %-*s -> %s  (forced update)",
+                       SUMMARY_WIDTH, quickref, REFCOL_WIDTH, remote, pretty_ref);
                return s_update_ref("forced-update", ref, 1);
        } else {
-               sprintf(display, "! %-*s %s -> %s  (non fast forward)",
-                       SUMMARY_WIDTH, "[rejected]", remote, pretty_ref);
+               sprintf(display, "! %-*s %-*s -> %s  (non fast forward)",
+                       SUMMARY_WIDTH, "[rejected]", REFCOL_WIDTH, remote,
+                       pretty_ref);
                return 1;
        }
 }
@@ -330,9 +337,72 @@ static void store_updated_refs(const char *url, struct ref *ref_map)
        fclose(fp);
 }
 
+/*
+ * We would want to bypass the object transfer altogether if
+ * everything we are going to fetch already exists and connected
+ * locally.
+ *
+ * The refs we are going to fetch are in to_fetch (nr_heads in
+ * total).  If running
+ *
+ *  $ git-rev-list --objects to_fetch[0] to_fetch[1] ... --not --all
+ *
+ * does not error out, that means everything reachable from the
+ * refs we are going to fetch exists and is connected to some of
+ * our existing refs.
+ */
+static int quickfetch(struct ref *ref_map)
+{
+       struct child_process revlist;
+       struct ref *ref;
+       char **argv;
+       int i, err;
+
+       /*
+        * If we are deepening a shallow clone we already have these
+        * objects reachable.  Running rev-list here will return with
+        * a good (0) exit status and we'll bypass the fetch that we
+        * really need to perform.  Claiming failure now will ensure
+        * we perform the network exchange to deepen our history.
+        */
+       if (depth)
+               return -1;
+
+       for (i = 0, ref = ref_map; ref; ref = ref->next)
+               i++;
+       if (!i)
+               return 0;
+
+       argv = xmalloc(sizeof(*argv) * (i + 6));
+       i = 0;
+       argv[i++] = xstrdup("rev-list");
+       argv[i++] = xstrdup("--quiet");
+       argv[i++] = xstrdup("--objects");
+       for (ref = ref_map; ref; ref = ref->next)
+               argv[i++] = xstrdup(sha1_to_hex(ref->old_sha1));
+       argv[i++] = xstrdup("--not");
+       argv[i++] = xstrdup("--all");
+       argv[i++] = NULL;
+
+       memset(&revlist, 0, sizeof(revlist));
+       revlist.argv = (const char**)argv;
+       revlist.git_cmd = 1;
+       revlist.no_stdin = 1;
+       revlist.no_stdout = 1;
+       revlist.no_stderr = 1;
+       err = run_command(&revlist);
+
+       for (i = 0; argv[i]; i++)
+               free(argv[i]);
+       free(argv);
+       return err;
+}
+
 static int fetch_refs(struct transport *transport, struct ref *ref_map)
 {
-       int ret = transport_fetch_refs(transport, ref_map);
+       int ret = quickfetch(ref_map);
+       if (ret)
+               ret = transport_fetch_refs(transport, ref_map);
        if (!ret)
                store_updated_refs(transport->url, ref_map);
        transport_unlock_pack(transport);
@@ -384,7 +454,7 @@ static struct ref *find_non_local_tags(struct transport *transport,
 
                if (!path_list_has_path(&existing_refs, ref_name) &&
                    !path_list_has_path(&new_refs, ref_name) &&
-                   lookup_object(ref->old_sha1)) {
+                   has_sha1_file(ref->old_sha1)) {
                        path_list_insert(ref_name, &new_refs);
 
                        rm = alloc_ref(strlen(ref_name) + 1);
@@ -468,7 +538,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
        static const char **refs = NULL;
        int ref_nr = 0;
        int cmd_len = 0;
-       const char *depth = NULL, *upload_pack = NULL;
+       const char *upload_pack = NULL;
        int keep = 0;
 
        for (i = 1; i < argc; i++) {
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 8b2bf632c534c5a9b5295884e517d70c7d2d9e86..c5230106a0e8dfe32fc5859f6207ae78a58e2111 100644 (file)
@@ -273,6 +273,8 @@ static int istitlechar(char c)
 static char *extra_headers = NULL;
 static int extra_headers_size = 0;
 static const char *fmt_patch_suffix = ".patch";
+static int numbered = 0;
+static int auto_number = 0;
 
 static int git_format_config(const char *var, const char *value)
 {
@@ -297,6 +299,15 @@ static int git_format_config(const char *var, const char *value)
        if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) {
                return 0;
        }
+       if (!strcmp(var, "format.numbered")) {
+               if (!strcasecmp(value, "auto")) {
+                       auto_number = 1;
+                       return 0;
+               }
+
+               numbered = git_config_bool(var, value);
+               return 0;
+       }
 
        return git_log_config(var, value);
 }
@@ -466,7 +477,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        struct rev_info rev;
        int nr = 0, total, i, j;
        int use_stdout = 0;
-       int numbered = 0;
        int start_number = -1;
        int keep_subject = 0;
        int numbered_files = 0;         /* _just_ numbers */
@@ -503,6 +513,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                else if (!strcmp(argv[i], "-n") ||
                                !strcmp(argv[i], "--numbered"))
                        numbered = 1;
+               else if (!strcmp(argv[i], "-N") ||
+                               !strcmp(argv[i], "--no-numbered")) {
+                       numbered = 0;
+                       auto_number = 0;
+               }
                else if (!prefixcmp(argv[i], "--start-number="))
                        start_number = strtol(argv[i] + 15, NULL, 10);
                else if (!strcmp(argv[i], "--numbered-files"))
@@ -642,6 +657,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                list[nr - 1] = commit;
        }
        total = nr;
+       if (!keep_subject && auto_number && total > 1)
+               numbered = 1;
        if (numbered)
                rev.total = total + start_number - 1;
        rev.add_signoff = add_signoff;
index b70da1863b221386a073ec8b7138cf0d91f52159..7f607098305fcf14c3e2a7634b6a5dc118445306 100644 (file)
@@ -387,8 +387,8 @@ static void overlay_tree(const char *tree_name, const char *prefix)
 static const char ls_files_usage[] =
        "git-ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified])* "
        "[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] "
-       "[ --exclude-per-directory=<filename> ] [--full-name] [--abbrev] "
-       "[--] [<file>]*";
+       "[ --exclude-per-directory=<filename> ] [--exclude-standard] "
+       "[--full-name] [--abbrev] [--] [<file>]*";
 
 int cmd_ls_files(int argc, const char **argv, const char *prefix)
 {
@@ -496,6 +496,11 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
                        dir.exclude_per_dir = arg + 24;
                        continue;
                }
+               if (!strcmp(arg, "--exclude-standard")) {
+                       exc_given = 1;
+                       setup_standard_excludes(&dir);
+                       continue;
+               }
                if (!strcmp(arg, "--full-name")) {
                        prefix_offset = 0;
                        continue;
@@ -525,11 +530,8 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
                break;
        }
 
-       if (require_work_tree && !is_inside_work_tree()) {
-               const char *work_tree = get_git_work_tree();
-               if (!work_tree || chdir(work_tree))
-                       die("This operation must be run in a work tree");
-       }
+       if (require_work_tree && !is_inside_work_tree())
+               setup_work_tree();
 
        pathspec = get_pathspec(prefix, argv + i);
 
index 74b04706f36128711719fff3e1423b3fb454af4c..46b27cdaea71cba92974480da74ec5922fcf3a7a 100644 (file)
@@ -101,20 +101,29 @@ static int populate_maildir_list(struct path_list *list, const char *path)
 {
        DIR *dir;
        struct dirent *dent;
+       char name[PATH_MAX];
+       char *subs[] = { "cur", "new", NULL };
+       char **sub;
+
+       for (sub = subs; *sub; ++sub) {
+               snprintf(name, sizeof(name), "%s/%s", path, *sub);
+               if ((dir = opendir(name)) == NULL) {
+                       if (errno == ENOENT)
+                               continue;
+                       error("cannot opendir %s (%s)", name, strerror(errno));
+                       return -1;
+               }
 
-       if ((dir = opendir(path)) == NULL) {
-               error("cannot opendir %s (%s)", path, strerror(errno));
-               return -1;
-       }
+               while ((dent = readdir(dir)) != NULL) {
+                       if (dent->d_name[0] == '.')
+                               continue;
+                       snprintf(name, sizeof(name), "%s/%s", *sub, dent->d_name);
+                       path_list_insert(name, list);
+               }
 
-       while ((dent = readdir(dir)) != NULL) {
-               if (dent->d_name[0] == '.')
-                       continue;
-               path_list_insert(dent->d_name, list);
+               closedir(dir);
        }
 
-       closedir(dir);
-
        return 0;
 }
 
@@ -122,19 +131,17 @@ static int split_maildir(const char *maildir, const char *dir,
        int nr_prec, int skip)
 {
        char file[PATH_MAX];
-       char curdir[PATH_MAX];
        char name[PATH_MAX];
        int ret = -1;
        int i;
        struct path_list list = {NULL, 0, 0, 1};
 
-       snprintf(curdir, sizeof(curdir), "%s/cur", maildir);
-       if (populate_maildir_list(&list, curdir) < 0)
+       if (populate_maildir_list(&list, maildir) < 0)
                goto out;
 
        for (i = 0; i < list.nr; i++) {
                FILE *f;
-               snprintf(file, sizeof(file), "%s/%s", curdir, list.items[i].path);
+               snprintf(file, sizeof(file), "%s/%s", maildir, list.items[i].path);
                f = fopen(file, "r");
                if (!f) {
                        error("cannot open mail %s (%s)", file, strerror(errno));
@@ -152,10 +159,9 @@ static int split_maildir(const char *maildir, const char *dir,
                fclose(f);
        }
 
-       path_list_clear(&list, 1);
-
        ret = skip;
 out:
+       path_list_clear(&list, 1);
        return ret;
 }
 
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 5467e36c73766494ba23d03fd23a9cbf03d05b95..4c61025aaef96ae9f8bcabe3fd4ad6c0fc2beba3 100644 (file)
@@ -18,7 +18,7 @@
 #include "tree.h"
 
 static const char builtin_reset_usage[] =
-"git-reset [--mixed | --soft | --hard]  [<commit-ish>] [ [--] <paths>...]";
+"git-reset [--mixed | --soft | --hard] [-q] [<commit-ish>] [ [--] <paths>...]";
 
 static char *args_to_str(const char **argv)
 {
@@ -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)
@@ -185,7 +180,7 @@ static const char *reset_type_names[] = { "mixed", "soft", "hard", NULL };
 
 int cmd_reset(int argc, const char **argv, const char *prefix)
 {
-       int i = 1, reset_type = NONE, update_ref_status = 0;
+       int i = 1, reset_type = NONE, update_ref_status = 0, quiet = 0;
        const char *rev = "HEAD";
        unsigned char sha1[20], *orig = NULL, sha1_orig[20],
                                *old_orig = NULL, sha1_old_orig[20];
@@ -197,7 +192,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
        reflog_action = args_to_str(argv);
        setenv("GIT_REFLOG_ACTION", reflog_action, 0);
 
-       if (i < argc) {
+       while (i < argc) {
                if (!strcmp(argv[i], "--mixed")) {
                        reset_type = MIXED;
                        i++;
@@ -210,6 +205,12 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
                        reset_type = HARD;
                        i++;
                }
+               else if (!strcmp(argv[i], "-q")) {
+                       quiet = 1;
+                       i++;
+               }
+               else
+                       break;
        }
 
        if (i < argc && argv[i][0] != '-')
@@ -237,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 */
@@ -270,13 +269,13 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
 
        switch (reset_type) {
        case HARD:
-               if (!update_ref_status)
+               if (!update_ref_status && !quiet)
                        print_new_head_line(commit);
                break;
        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 697046723fc64f38ab4fb589c84f1c5d5934894a..f5149e59b7c04d943f3b90f706a66d185f8a396c 100644 (file)
@@ -26,6 +26,7 @@ static const char rev_list_usage[] =
 "    --remove-empty\n"
 "    --all\n"
 "    --stdin\n"
+"    --quiet\n"
 "  ordering output:\n"
 "    --topo-order\n"
 "    --date-order\n"
@@ -50,6 +51,7 @@ static int show_timestamp;
 static int hdr_termination;
 static const char *header_prefix;
 
+static void finish_commit(struct commit *commit);
 static void show_commit(struct commit *commit)
 {
        if (show_timestamp)
@@ -93,6 +95,11 @@ static void show_commit(struct commit *commit)
                strbuf_release(&buf);
        }
        maybe_flush_or_die(stdout, "stdout");
+       finish_commit(commit);
+}
+
+static void finish_commit(struct commit *commit)
+{
        if (commit->parents) {
                free_commit_list(commit->parents);
                commit->parents = NULL;
@@ -101,6 +108,12 @@ static void show_commit(struct commit *commit)
        commit->buffer = NULL;
 }
 
+static void finish_object(struct object_array_entry *p)
+{
+       if (p->item->type == OBJ_BLOB && !has_sha1_file(p->item->sha1))
+               die("missing blob object '%s'", sha1_to_hex(p->item->sha1));
+}
+
 static void show_object(struct object_array_entry *p)
 {
        /* An object with name "foo\n0000000..." can be used to
@@ -108,9 +121,7 @@ static void show_object(struct object_array_entry *p)
         */
        const char *ep = strchr(p->name, '\n');
 
-       if (p->item->type == OBJ_BLOB && !has_sha1_file(p->item->sha1))
-               die("missing blob object '%s'", sha1_to_hex(p->item->sha1));
-
+       finish_object(p);
        if (ep) {
                printf("%s %.*s\n", sha1_to_hex(p->item->sha1),
                       (int) (ep - p->name),
@@ -527,6 +538,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
        int read_from_stdin = 0;
        int bisect_show_vars = 0;
        int bisect_find_all = 0;
+       int quiet = 0;
 
        git_config(git_default_config);
        init_revisions(&revs, prefix);
@@ -565,6 +577,10 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
                        read_revisions_from_stdin(&revs);
                        continue;
                }
+               if (!strcmp(arg, "--quiet")) {
+                       quiet = 1;
+                       continue;
+               }
                usage(rev_list_usage);
 
        }
@@ -640,7 +656,9 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
                }
        }
 
-       traverse_commit_list(&revs, show_commit, show_object);
+       traverse_commit_list(&revs,
+               quiet ? finish_commit : show_commit,
+               quiet ? finish_object : show_object);
 
        return 0;
 }
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 bca2bd97036fdaf2e2bf99e308ba62e1acf4d9e8..a3d25e6a571584c486d252c5a8e2b182f3da86e3 100644 (file)
@@ -155,6 +155,9 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
        if (!argc)
                usage_with_options(builtin_rm_usage, builtin_rm_options);
 
+       if (!index_only)
+               setup_work_tree();
+
        pathspec = get_pathspec(prefix, argv);
        seen = NULL;
        for (i = 0; pathspec[i] ; i++)
index 66e5a5830792471a44c9211d4eafcf2b1ff6f0dd..cbb0f04e85627a5509bb2ba8cbf04a54d4d20c41 100644 (file)
@@ -81,17 +81,16 @@ static int show_reference(const char *refname, const unsigned char *sha1,
                }
                printf("%-15s ", refname);
 
-               sp = buf = read_sha1_file(sha1, &type, &size);
-               if (!buf)
+               buf = read_sha1_file(sha1, &type, &size);
+               if (!buf || !size)
                        return 0;
-               if (!size) {
+
+               /* skip header */
+               sp = strstr(buf, "\n\n");
+               if (!sp) {
                        free(buf);
                        return 0;
                }
-               /* skip header */
-               while (sp + 1 < buf + size &&
-                               !(sp[0] == '\n' && sp[1] == '\n'))
-                       sp++;
                /* only take up to "lines" lines, and strip the signature */
                for (i = 0, sp += 2;
                                i < filter->lines && sp < buf + size &&
@@ -247,9 +246,37 @@ static int git_tag_config(const char *var, const char *value)
        return git_default_config(var, value);
 }
 
+static void write_tag_body(int fd, const unsigned char *sha1)
+{
+       unsigned long size;
+       enum object_type type;
+       char *buf, *sp, *eob;
+       size_t len;
+
+       buf = read_sha1_file(sha1, &type, &size);
+       if (!buf)
+               return;
+       /* skip header */
+       sp = strstr(buf, "\n\n");
+
+       if (!sp || !size || type != OBJ_TAG) {
+               free(buf);
+               return;
+       }
+       sp += 2; /* skip the 2 LFs */
+       eob = strstr(sp, "\n" PGP_SIGNATURE "\n");
+       if (eob)
+               len = eob - sp;
+       else
+               len = buf + size - sp;
+       write_or_die(fd, sp, len);
+
+       free(buf);
+}
+
 static void create_tag(const unsigned char *object, const char *tag,
                       struct strbuf *buf, int message, int sign,
-                          unsigned char *result)
+                          unsigned char *prev, unsigned char *result)
 {
        enum object_type type;
        char header_buf[1024];
@@ -282,7 +309,11 @@ static void create_tag(const unsigned char *object, const char *tag,
                if (fd < 0)
                        die("could not create file '%s': %s",
                                                path, strerror(errno));
-               write_or_die(fd, tag_template, strlen(tag_template));
+
+               if (!is_null_sha1(prev))
+                       write_tag_body(fd, prev);
+               else
+                       write_or_die(fd, tag_template, strlen(tag_template));
                close(fd);
 
                launch_editor(path, buf);
@@ -419,7 +450,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
                die("tag '%s' already exists", tag);
 
        if (annotate)
-               create_tag(object, tag, &buf, message, sign, object);
+               create_tag(object, tag, &buf, message, sign, prev, object);
 
        lock = lock_any_ref_for_update(ref, prev, 0);
        if (!lock)
index 0869fcf0261de7217cc0b1dadd30a5259468d4f8..e4d60cde6f1b9dd7a2aab36ebc4f2a97a9d61b22 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -23,7 +23,8 @@ static void add_to_ref_list(const unsigned char *sha1, const char *name,
 }
 
 /* returns an fd */
-int read_bundle_header(const char *path, struct bundle_header *header) {
+int read_bundle_header(const char *path, struct bundle_header *header)
+{
        char buffer[1024];
        int fd;
        long fpos;
diff --git a/cache.h b/cache.h
index bfffa05dff149a948e46b04f6b15589e6f4be07e..33ebccf48d0d8963ab5b262bfb87312e6542ed75 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -7,7 +7,7 @@
 #include SHA1_HEADER
 #include <zlib.h>
 
-#if ZLIB_VERNUM < 0x1200
+#if defined(NO_DEFLATE_BOUND) || ZLIB_VERNUM < 0x1200
 #define deflateBound(c,s)  ((s) + (((s) + 7) >> 3) + (((s) + 63) >> 6) + 11)
 #endif
 
@@ -175,8 +175,8 @@ extern struct index_state the_index;
 #define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))
 #define add_file_to_cache(path, verbose) add_file_to_index(&the_index, (path), (verbose))
 #define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL)
-#define ce_match_stat(ce, st, really) ie_match_stat(&the_index, (ce), (st), (really))
-#define ce_modified(ce, st, really) ie_modified(&the_index, (ce), (st), (really))
+#define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))
+#define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
 #endif
 
 enum object_type {
@@ -222,6 +222,7 @@ extern const char *get_git_work_tree(void);
 #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
 
 extern const char **get_pathspec(const char *prefix, const char **pathspec);
+extern void setup_work_tree(void);
 extern const char *setup_git_directory_gently(int *);
 extern const char *setup_git_directory(void);
 extern const char *prefix_path(const char *prefix, int len, const char *path);
@@ -267,8 +268,14 @@ extern int remove_file_from_index(struct index_state *, const char *path);
 extern int add_file_to_index(struct index_state *, const char *path, int verbose);
 extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
 extern int ce_same_name(struct cache_entry *a, struct cache_entry *b);
-extern int ie_match_stat(struct index_state *, struct cache_entry *, struct stat *, int);
-extern int ie_modified(struct index_state *, struct cache_entry *, struct stat *, int);
+
+/* do stat comparison even if CE_VALID is true */
+#define CE_MATCH_IGNORE_VALID          01
+/* do not check the contents but report dirty on racily-clean entries */
+#define CE_MATCH_RACY_IS_DIRTY 02
+extern int ie_match_stat(struct index_state *, struct cache_entry *, struct stat *, unsigned int);
+extern int ie_modified(struct index_state *, struct cache_entry *, struct stat *, unsigned int);
+
 extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
 extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
 extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object);
@@ -574,6 +581,7 @@ extern int pager_in_use;
 extern int pager_use_color;
 
 extern char *editor_program;
+extern char *excludes_file;
 
 /* base85 */
 int decode_85(char *dst, const char *line, int linelen);
index d6a08b4a55273af1a5f2933f3b5c6cb818ba74c6..00d92a16631a80ff8ec4e995dafcd3e55434fad5 100644 (file)
@@ -18,7 +18,7 @@ int main(int ac, char **av)
 
                if (ce_match_stat(ce, &st, 0))
                        dirty++;
-               else if (ce_match_stat(ce, &st, 2))
+               else if (ce_match_stat(ce, &st, CE_MATCH_RACY_IS_DIRTY))
                        racy++;
                else
                        clean++;
index dc3148d4566205858869973804de1c2ddb19e981..56e99fc0f4750174299303b27237737e09549933 100644 (file)
--- a/config.c
+++ b/config.c
@@ -431,6 +431,13 @@ int git_default_config(const char *var, const char *value)
                return 0;
        }
 
+       if (!strcmp(var, "core.excludesfile")) {
+               if (!value)
+                       die("core.excludesfile without value");
+               excludes_file = xstrdup(value);
+               return 0;
+       }
+
        /* Add other config variables here and to Documentation/config.txt. */
        return 0;
 }
index a3032e389f6bf63cd46a3aa23e59b6a6cd537132..776b80565902af3de1c2a33af062dd4de719a267 100644 (file)
@@ -38,3 +38,4 @@ NO_STRCASESTR=@NO_STRCASESTR@
 NO_STRLCPY=@NO_STRLCPY@
 NO_SETENV=@NO_SETENV@
 NO_ICONV=@NO_ICONV@
+NO_DEFLATE_BOUND=@NO_DEFLATE_BOUND@
index ed7cc895d276ac4d7548211a364a4e6952f9b7bd..53e9a17c737e10a51b8b33b9cf258744817e6e9a 100644 (file)
@@ -73,7 +73,7 @@ fi \
 AC_ARG_WITH([lib],
  [AS_HELP_STRING([--with-lib=ARG],
                  [ARG specifies alternative name for lib directory])],
- [if test "$withval" = "no" -o "$withval" = "yes"; then \
+ [if test "$withval" = "no" || test "$withval" = "yes"; then \
        AC_MSG_WARN([You should provide name for --with-lib=ARG]); \
 else \
        GIT_CONF_APPEND_LINE(lib=$withval); \
@@ -182,6 +182,26 @@ AC_SUBST(NEEDS_LIBICONV)
 AC_SUBST(NO_ICONV)
 test -n "$NEEDS_LIBICONV" && LIBS="$LIBS -liconv"
 #
+# Define NO_DEFLATE_BOUND if deflateBound is missing from zlib.
+AC_DEFUN([ZLIBTEST_SRC], [
+#include <zlib.h>
+
+int main(void)
+{
+       deflateBound(0, 0);
+       return 0;
+}
+])
+AC_MSG_CHECKING([for deflateBound in -lz])
+old_LIBS="$LIBS"
+LIBS="$LIBS -lz"
+AC_LINK_IFELSE(ZLIBTEST_SRC,
+       [AC_MSG_RESULT([yes])],
+       [AC_MSG_RESULT([no])
+       NO_DEFLATE_BOUND=yes])
+LIBS="$old_LIBS"
+AC_SUBST(NO_DEFLATE_BOUND)
+#
 # Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
 # Patrick Mauritz).
 AC_CHECK_LIB([c], [socket],
@@ -245,9 +265,9 @@ AC_RUN_IFELSE(
        [AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
                [[char buf[64];
                if (sprintf(buf, "%lld%hhd%jd%zd%td", (long long int)1, (char)2, (intmax_t)3, (size_t)4, (ptrdiff_t)5) != 5)
-                 exit(1);
+                 return 1;
                else if (strcmp(buf, "12345"))
-                 exit(2);]])],
+                 return 2;]])],
        [ac_cv_c_c99_format=yes],
        [ac_cv_c_c99_format=no])
 ])
index bf33f74b70a0514ebb3e3f3c31fbace65d26ff8a..c148b5ab7d139ea64fa7836f95be542dbbf69a45 100755 (executable)
@@ -71,6 +71,79 @@ def isP4Exec(kind):
     a plus sign, it is also executable"""
     return (re.search(r"(^[cku]?x)|\+.*x", kind) != None)
 
+def setP4ExecBit(file, mode):
+    # Reopens an already open file and changes the execute bit to match
+    # the execute bit setting in the passed in mode.
+
+    p4Type = "+x"
+
+    if not isModeExec(mode):
+        p4Type = getP4OpenedType(file)
+        p4Type = re.sub('^([cku]?)x(.*)', '\\1\\2', p4Type)
+        p4Type = re.sub('(.*?\+.*?)x(.*?)', '\\1\\2', p4Type)
+        if p4Type[-1] == "+":
+            p4Type = p4Type[0:-1]
+
+    system("p4 reopen -t %s %s" % (p4Type, file))
+
+def getP4OpenedType(file):
+    # Returns the perforce file type for the given file.
+
+    result = read_pipe("p4 opened %s" % file)
+    match = re.match(".*\((.+)\)$", result)
+    if match:
+        return match.group(1)
+    else:
+        die("Could not determine file type for %s" % file)
+
+def diffTreePattern():
+    # This is a simple generator for the diff tree regex pattern. This could be
+    # a class variable if this and parseDiffTreeEntry were a part of a class.
+    pattern = re.compile(':(\d+) (\d+) (\w+) (\w+) ([A-Z])(\d+)?\t(.*?)((\t(.*))|$)')
+    while True:
+        yield pattern
+
+def parseDiffTreeEntry(entry):
+    """Parses a single diff tree entry into its component elements.
+
+    See git-diff-tree(1) manpage for details about the format of the diff
+    output. This method returns a dictionary with the following elements:
+
+    src_mode - The mode of the source file
+    dst_mode - The mode of the destination file
+    src_sha1 - The sha1 for the source file
+    dst_sha1 - The sha1 fr the destination file
+    status - The one letter status of the diff (i.e. 'A', 'M', 'D', etc)
+    status_score - The score for the status (applicable for 'C' and 'R'
+                   statuses). This is None if there is no score.
+    src - The path for the source file.
+    dst - The path for the destination file. This is only present for
+          copy or renames. If it is not present, this is None.
+
+    If the pattern is not matched, None is returned."""
+
+    match = diffTreePattern().next().match(entry)
+    if match:
+        return {
+            'src_mode': match.group(1),
+            'dst_mode': match.group(2),
+            'src_sha1': match.group(3),
+            'dst_sha1': match.group(4),
+            'status': match.group(5),
+            'status_score': match.group(6),
+            'src': match.group(7),
+            'dst': match.group(10)
+        }
+    return None
+
+def isModeExec(mode):
+    # Returns True if the given git mode represents an executable file,
+    # otherwise False.
+    return mode[-3:] == "755"
+
+def isModeExecChanged(src_mode, dst_mode):
+    return isModeExec(src_mode) != isModeExec(dst_mode)
+
 def p4CmdList(cmd, stdin=None, stdin_mode='w+b'):
     cmd = "p4 -G %s" % cmd
     if verbose:
@@ -494,18 +567,23 @@ class P4Submit(Command):
         else:
             print "Applying %s" % (read_pipe("git log --max-count=1 --pretty=oneline %s" % id))
             diffOpts = ("", "-M")[self.detectRename]
-            diff = read_pipe_lines("git diff-tree -r --name-status %s \"%s^\" \"%s\"" % (diffOpts, id, id))
+            diff = read_pipe_lines("git diff-tree -r %s \"%s^\" \"%s\"" % (diffOpts, id, id))
         filesToAdd = set()
         filesToDelete = set()
         editedFiles = set()
+        filesToChangeExecBit = {}
         for line in diff:
-            modifier = line[0]
-            path = line[1:].strip()
+            diff = parseDiffTreeEntry(line)
+            modifier = diff['status']
+            path = diff['src']
             if modifier == "M":
                 system("p4 edit \"%s\"" % path)
+                if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
+                    filesToChangeExecBit[path] = diff['dst_mode']
                 editedFiles.add(path)
             elif modifier == "A":
                 filesToAdd.add(path)
+                filesToChangeExecBit[path] = diff['dst_mode']
                 if path in filesToDelete:
                     filesToDelete.remove(path)
             elif modifier == "D":
@@ -513,9 +591,11 @@ class P4Submit(Command):
                 if path in filesToAdd:
                     filesToAdd.remove(path)
             elif modifier == "R":
-                src, dest = line.strip().split("\t")[1:3]
+                src, dest = diff['src'], diff['dst']
                 system("p4 integrate -Dt \"%s\" \"%s\"" % (src, dest))
                 system("p4 edit \"%s\"" % (dest))
+                if isModeExecChanged(diff['src_mode'], diff['dst_mode']):
+                    filesToChangeExecBit[dest] = diff['dst_mode']
                 os.unlink(dest)
                 editedFiles.add(dest)
                 filesToDelete.add(src)
@@ -568,6 +648,11 @@ class P4Submit(Command):
             system("p4 revert \"%s\"" % f)
             system("p4 delete \"%s\"" % f)
 
+        # Set/clear executable bits
+        for f in filesToChangeExecBit.keys():
+            mode = filesToChangeExecBit[f]
+            setP4ExecBit(f, mode)
+
         logMessage = ""
         if not self.directSubmit:
             logMessage = extractLogMessageFromGitCommit(id)
index 2aa9bb501c2768770d8aed5de93dda8afc29b427..7511ea0797286453051c15765c4b795ac577cc0d 100644 (file)
@@ -2,24 +2,26 @@
 #
 # Copyright (c) 2007 Andy Parkins
 #
-# An example hook script to mail out commit update information.  This hook sends emails
-# listing new revisions to the repository introduced by the change being reported.  The
-# rule is that (for branch updates) each commit will appear on one email and one email
-# only.
+# An example hook script to mail out commit update information.  This hook
+# sends emails listing new revisions to the repository introduced by the
+# change being reported.  The rule is that (for branch updates) each commit
+# will appear on one email and one email only.
 #
-# This hook is stored in the contrib/hooks directory.  Your distribution will have put
-# this somewhere standard.  You should make this script executable then link to it in
-# the repository you would like to use it in.  For example, on debian the hook is stored
-# in /usr/share/doc/git-core/contrib/hooks/post-receive-email:
+# This hook is stored in the contrib/hooks directory.  Your distribution
+# will have put this somewhere standard.  You should make this script
+# executable then link to it in the repository you would like to use it in.
+# For example, on debian the hook is stored in
+# /usr/share/doc/git-core/contrib/hooks/post-receive-email:
 #
 #  chmod a+x post-receive-email
 #  cd /path/to/your/repository.git
 #  ln -sf /usr/share/doc/git-core/contrib/hooks/post-receive-email hooks/post-receive
 #
-# This hook script assumes it is enabled on the central repository of a project, with
-# all users pushing only to it and not between each other.  It will still work if you
-# don't operate in that style, but it would become possible for the email to be from
-# someone other than the person doing the push.
+# This hook script assumes it is enabled on the central repository of a
+# project, with all users pushing only to it and not between each other.  It
+# will still work if you don't operate in that style, but it would become
+# possible for the email to be from someone other than the person doing the
+# push.
 #
 # Config
 # ------
 #   emails for every ref update.
 # hooks.announcelist
 #   This is the list that all pushes of annotated tags will go to.  Leave it
-#   blank to default to the mailinglist field.  The announce emails lists the
-#   short log summary of the changes since the last annotated tag.
-# hook.envelopesender
-#   If set then the -f option is passed to sendmail to allow the envelope sender
-#   address to be set
+#   blank to default to the mailinglist field.  The announce emails lists
+#   the short log summary of the changes since the last annotated tag.
+# hooks.envelopesender
+#   If set then the -f option is passed to sendmail to allow the envelope
+#   sender address to be set
+# hooks.emailprefix
+#   All emails have their subjects prefixed with this prefix, or "[SCM]"
+#   if emailprefix is unset, to aid filtering
 #
 # Notes
 # -----
-# All emails have their subjects prefixed with "[SCM]" to aid filtering.
 # All emails include the headers "X-Git-Refname", "X-Git-Oldrev",
 # "X-Git-Newrev", and "X-Git-Reftype" to enable fine tuned filtering and
 # give information for debugging.
@@ -49,8 +53,8 @@
 # this is and calls the appropriate body-generation routine after outputting
 # the common header
 #
-# Note this function doesn't actually generate any email output, that is taken
-# care of by the functions it calls:
+# Note this function doesn't actually generate any email output, that is
+# taken care of by the functions it calls:
 #  - generate_email_header
 #  - generate_create_XXXX_email
 #  - generate_update_XXXX_email
@@ -152,10 +156,6 @@ generate_email()
        fi
 
        # Email parameters
-       # The committer will be obtained from the latest existing rev; so
-       # for a deletion it will be the oldrev, for the others, then newrev
-       committer=$(git show --pretty=full -s $rev | sed -ne "s/^Commit: //p" |
-               sed -ne 's/\(.*\) </"\1" </p')
        # The email subject will contain the best description of the ref
        # that we can build from the parameters
        describe=$(git describe $rev 2>/dev/null)
@@ -186,7 +186,7 @@ generate_email_header()
        # Generate header
        cat <<-EOF
        To: $recipients
-       Subject: ${EMAILPREFIX}$projectdesc $refname_type, $short_refname, ${change_type}d. $describe
+       Subject: ${emailprefix}$projectdesc $refname_type, $short_refname, ${change_type}d. $describe
        X-Git-Refname: $refname
        X-Git-Reftype: $refname_type
        X-Git-Oldrev: $oldrev
@@ -225,8 +225,9 @@ generate_create_branch_email()
        echo $LOGBEGIN
        # This shows all log entries that are not already covered by
        # another ref - i.e. commits that are now accessible from this
-       # ref that were previously not accessible (see generate_update_branch_email
-       # for the explanation of this command)
+       # ref that were previously not accessible
+       # (see generate_update_branch_email for the explanation of this
+       # command)
        git rev-parse --not --branches | grep -v $(git rev-parse $refname) |
        git rev-list --pretty --stdin $newrev
        echo $LOGEND
@@ -254,9 +255,10 @@ generate_update_branch_email()
        #
        #  git-rev-list N ^O ^X ^N
        #
-       # So, we need to build up the list more carefully.  git-rev-parse will
-       # generate a list of revs that may be fed into git-rev-list.  We can get
-       # it to make the "--not --all" part and then filter out the "^N" with:
+       # So, we need to build up the list more carefully.  git-rev-parse
+       # will generate a list of revs that may be fed into git-rev-list.
+       # We can get it to make the "--not --all" part and then filter out
+       # the "^N" with:
        #
        #  git-rev-parse --not --all | grep -v N
        #
@@ -266,16 +268,17 @@ generate_update_branch_email()
        #  git-rev-list N ^O ^X
        #
        # This leaves a problem when someone else updates the repository
-       # while this script is running.  Their new value of the ref we're working
-       # on would be included in the "--not --all" output; and as our $newrev
-       # would be an ancestor of that commit, it would exclude all of our
-       # commits.  What we really want is to exclude the current value of
-       # $refname from the --not list, rather than N itself.  So:
+       # while this script is running.  Their new value of the ref we're
+       # working on would be included in the "--not --all" output; and as
+       # our $newrev would be an ancestor of that commit, it would exclude
+       # all of our commits.  What we really want is to exclude the current
+       # value of $refname from the --not list, rather than N itself.  So:
        #
        #  git-rev-parse --not --all | grep -v $(git-rev-parse $refname)
        #
-       # Get's us to something pretty safe (apart from the small time between
-       # refname being read, and git-rev-parse running - for that, I give up)
+       # Get's us to something pretty safe (apart from the small time
+       # between refname being read, and git-rev-parse running - for that,
+       # I give up)
        #
        #
        # Next problem, consider this:
@@ -283,18 +286,18 @@ generate_update_branch_email()
        #          \
        #           * --- X --- * --- N ($newrev)
        #
-       # That is to say, there is no guarantee that oldrev is a strict subset of
-       # newrev (it would have required a --force, but that's allowed).  So, we
-       # can't simply say rev-list $oldrev..$newrev.  Instead we find the common
-       # base of the two revs and list from there.
+       # That is to say, there is no guarantee that oldrev is a strict
+       # subset of newrev (it would have required a --force, but that's
+       # allowed).  So, we can't simply say rev-list $oldrev..$newrev.
+       # Instead we find the common base of the two revs and list from
+       # there.
        #
-       # As above, we need to take into account the presence of X; if another
-       # branch is already in the repository and points at some of the revisions
-       # that we are about to output - we don't want them.  The solution is as
-       # before: git-rev-parse output filtered.
+       # As above, we need to take into account the presence of X; if
+       # another branch is already in the repository and points at some of
+       # the revisions that we are about to output - we don't want them.
+       # The solution is as before: git-rev-parse output filtered.
        #
-       # Finally, tags:
-       #   1 --- 2 --- O --- T --- 3 --- 4 --- N
+       # Finally, tags: 1 --- 2 --- O --- T --- 3 --- 4 --- N
        #
        # Tags pushed into the repository generate nice shortlog emails that
        # summarise the commits between them and the previous tag.  However,
@@ -302,13 +305,14 @@ generate_update_branch_email()
        # for a branch update.  Therefore we still want to output revisions
        # that have been output on a tag email.
        #
-       # Luckily, git-rev-parse includes just the tool.  Instead of using "--all"
-       # we use "--branches"; this has the added benefit that "remotes/" will
-       # be ignored as well.
-
-       # List all of the revisions that were removed by this update, in a fast forward
-       # update, this list will be empty, because rev-list O ^N is empty.  For a non
-       # fast forward, O ^N is the list of removed revisions
+       # Luckily, git-rev-parse includes just the tool.  Instead of using
+       # "--all" we use "--branches"; this has the added benefit that
+       # "remotes/" will be ignored as well.
+
+       # List all of the revisions that were removed by this update, in a
+       # fast forward update, this list will be empty, because rev-list O
+       # ^N is empty.  For a non fast forward, O ^N is the list of removed
+       # revisions
        fast_forward=""
        rev=""
        for rev in $(git rev-list $newrev..$oldrev)
@@ -321,10 +325,10 @@ generate_update_branch_email()
        fi
 
        # List all the revisions from baserev to newrev in a kind of
-       # "table-of-contents"; note this list can include revisions that have
-       # already had notification emails and is present to show the full detail
-       # of the change from rolling back the old revision to the base revision and
-       # then forward to the new revision
+       # "table-of-contents"; note this list can include revisions that
+       # have already had notification emails and is present to show the
+       # full detail of the change from rolling back the old revision to
+       # the base revision and then forward to the new revision
        for rev in $(git rev-list $oldrev..$newrev)
        do
                revtype=$(git cat-file -t "$rev")
@@ -334,19 +338,20 @@ generate_update_branch_email()
        if [ "$fast_forward" ]; then
                echo "      from  $oldrev ($oldrev_type)"
        else
-               #  1. Existing revisions were removed.  In this case newrev is a
-               #     subset of oldrev - this is the reverse of a fast-forward,
-               #     a rewind
-               #  2. New revisions were added on top of an old revision, this is
-               #     a rewind and addition.
+               #  1. Existing revisions were removed.  In this case newrev
+               #     is a subset of oldrev - this is the reverse of a
+               #     fast-forward, a rewind
+               #  2. New revisions were added on top of an old revision,
+               #     this is a rewind and addition.
 
-               # (1) certainly happened, (2) possibly.  When (2) hasn't happened,
-               # we set a flag to indicate that no log printout is required.
+               # (1) certainly happened, (2) possibly.  When (2) hasn't
+               # happened, we set a flag to indicate that no log printout
+               # is required.
 
                echo ""
 
-               # Find the common ancestor of the old and new revisions and compare
-               # it with newrev
+               # Find the common ancestor of the old and new revisions and
+               # compare it with newrev
                baserev=$(git merge-base $oldrev $newrev)
                rewind_only=""
                if [ "$baserev" = "$newrev" ]; then
@@ -387,21 +392,22 @@ generate_update_branch_email()
                git rev-parse --not --branches | grep -v $(git rev-parse $refname) |
                git rev-list --pretty --stdin $oldrev..$newrev
 
-               # XXX: Need a way of detecting whether git rev-list actually outputted
-               # anything, so that we can issue a "no new revisions added by this
-               # update" message
+               # XXX: Need a way of detecting whether git rev-list actually
+               # outputted anything, so that we can issue a "no new
+               # revisions added by this update" message
 
                echo $LOGEND
        else
                echo "No new revisions were added by this update."
        fi
 
-       # The diffstat is shown from the old revision to the new revision.  This
-       # is to show the truth of what happened in this change.  There's no point
-       # showing the stat from the base to the new revision because the base
-       # is effectively a random revision at this point - the user will be
-       # interested in what this revision changed - including the undoing of
-       # previous revisions in the case of non-fast forward updates.
+       # The diffstat is shown from the old revision to the new revision.
+       # This is to show the truth of what happened in this change.
+       # There's no point showing the stat from the base to the new
+       # revision because the base is effectively a random revision at this
+       # point - the user will be interested in what this revision changed
+       # - including the undoing of previous revisions in the case of
+       # non-fast forward updates.
        echo ""
        echo "Summary of changes:"
        git diff-tree --stat --summary --find-copies-harder $oldrev..$newrev
@@ -448,7 +454,8 @@ generate_update_atag_email()
 #
 generate_atag_email()
 {
-       # Use git-for-each-ref to pull out the individual fields from the tag
+       # Use git-for-each-ref to pull out the individual fields from the
+       # tag
        eval $(git for-each-ref --shell --format='
        tagobject=%(*objectname)
        tagtype=%(*objecttype)
@@ -459,8 +466,10 @@ generate_atag_email()
        echo "   tagging  $tagobject ($tagtype)"
        case "$tagtype" in
        commit)
+
                # If the tagged object is a commit, then we assume this is a
-               # release, and so we calculate which tag this tag is replacing
+               # release, and so we calculate which tag this tag is
+               # replacing
                prevtag=$(git describe --abbrev=0 $newrev^ 2>/dev/null)
 
                if [ -n "$prevtag" ]; then
@@ -477,25 +486,27 @@ generate_atag_email()
        echo ""
        echo $LOGBEGIN
 
-       # Show the content of the tag message; this might contain a change log
-       # or release notes so is worth displaying.
+       # Show the content of the tag message; this might contain a change
+       # log or release notes so is worth displaying.
        git cat-file tag $newrev | sed -e '1,/^$/d'
 
        echo ""
        case "$tagtype" in
        commit)
-               # Only commit tags make sense to have rev-list operations performed
-               # on them
+               # Only commit tags make sense to have rev-list operations
+               # performed on them
                if [ -n "$prevtag" ]; then
                        # Show changes since the previous release
                        git rev-list --pretty=short "$prevtag..$newrev" | git shortlog
                else
-                       # No previous tag, show all the changes since time began
+                       # No previous tag, show all the changes since time
+                       # began
                        git rev-list --pretty=short $newrev | git shortlog
                fi
                ;;
        *)
-               # XXX: Is there anything useful we can do for non-commit objects?
+               # XXX: Is there anything useful we can do for non-commit
+               # objects?
                ;;
        esac
 
@@ -544,13 +555,14 @@ generate_update_general_email()
 #
 generate_general_email()
 {
-       # Unannotated tags are more about marking a point than releasing a version;
-       # therefore we don't do the shortlog summary that we do for annotated tags
-       # above - we simply show that the point has been marked, and print the log
-       # message for the marked point for reference purposes
+       # Unannotated tags are more about marking a point than releasing a
+       # version; therefore we don't do the shortlog summary that we do for
+       # annotated tags above - we simply show that the point has been
+       # marked, and print the log message for the marked point for
+       # reference purposes
        #
-       # Note this section also catches any other reference type (although there
-       # aren't any) and deals with them in the same way.
+       # Note this section also catches any other reference type (although
+       # there aren't any) and deals with them in the same way.
 
        echo ""
        if [ "$newrev_type" = "commit" ]; then
@@ -558,10 +570,10 @@ generate_general_email()
                git show --no-color --root -s $newrev
                echo $LOGEND
        else
-               # What can we do here?  The tag marks an object that is not a commit,
-               # so there is no log for us to display.  It's probably not wise to
-               # output git-cat-file as it could be a binary blob.  We'll just say how
-               # big it is
+               # What can we do here?  The tag marks an object that is not
+               # a commit, so there is no log for us to display.  It's
+               # probably not wise to output git-cat-file as it could be a
+               # binary blob.  We'll just say how big it is
                echo "$newrev is a $newrev_type, and is $(git cat-file -s $newrev) bytes long."
        fi
 }
@@ -590,7 +602,6 @@ send_mail()
 # ---------------------------- main()
 
 # --- Constants
-EMAILPREFIX="[SCM] "
 LOGBEGIN="- Log -----------------------------------------------------------------"
 LOGEND="-----------------------------------------------------------------------"
 
@@ -604,8 +615,8 @@ if [ -z "$GIT_DIR" ]; then
 fi
 
 projectdesc=$(sed -ne '1p' "$GIT_DIR/description")
-# Check if the description is unchanged from it's default, and shorten it to a
-# more manageable length if it is
+# Check if the description is unchanged from it's default, and shorten it to
+# more manageable length if it is
 if expr "$projectdesc" : "Unnamed repository.*$" >/dev/null
 then
        projectdesc="UNNAMED PROJECT"
@@ -614,13 +625,15 @@ fi
 recipients=$(git repo-config hooks.mailinglist)
 announcerecipients=$(git repo-config hooks.announcelist)
 envelopesender=$(git-repo-config hooks.envelopesender)
+emailprefix=$(git-repo-config hooks.emailprefix || echo '[SCM] ')
 
 # --- Main loop
-# Allow dual mode: run from the command line just like the update hook, or if
-# no arguments are given then run as a hook script
+# Allow dual mode: run from the command line just like the update hook, or
+# if no arguments are given then run as a hook script
 if [ -n "$1" -a -n "$2" -a -n "$3" ]; then
        # Output to the terminal in command line mode - if someone wanted to
-       # resend an email; they could redirect the output to sendmail themselves
+       # resend an email; they could redirect the output to sendmail
+       # themselves
        PAGER= generate_email $2 $3 $1
 else
        while read oldrev newrev refname
index 3729e73e19e18a78c15fb90dfc28133f541176ef..9728a9954129246b96713d2f3b8dbd52541c416b 100644 (file)
@@ -18,7 +18,8 @@ static void sha1flush(struct sha1file *f, unsigned int count)
        for (;;) {
                int ret = xwrite(f->fd, buf, count);
                if (ret > 0) {
-                       display_throughput(f->tp, ret);
+                       f->total += ret;
+                       display_throughput(f->tp, f->total);
                        buf = (char *) buf + ret;
                        count -= ret;
                        if (count)
@@ -87,21 +88,12 @@ struct sha1file *sha1fd(int fd, const char *name)
 
 struct sha1file *sha1fd_throughput(int fd, const char *name, struct progress *tp)
 {
-       struct sha1file *f;
-       unsigned len;
-
-       f = xmalloc(sizeof(*f));
-
-       len = strlen(name);
-       if (len >= PATH_MAX)
-               die("you wascally wabbit, you");
-       f->namelen = len;
-       memcpy(f->name, name, len+1);
-
+       struct sha1file *f = xmalloc(sizeof(*f));
        f->fd = fd;
-       f->error = 0;
        f->offset = 0;
+       f->total = 0;
        f->tp = tp;
+       f->name = name;
        f->do_crc = 0;
        SHA1_Init(&f->ctx);
        return f;
index 4d1b231292ad4cfc7996b73ea31fa74a5eff2687..1af76562f31da89e4cd2592079edb9c6a45736e3 100644 (file)
@@ -5,11 +5,12 @@ struct progress;
 
 /* A SHA1-protected file */
 struct sha1file {
-       int fd, error;
-       unsigned int offset, namelen;
+       int fd;
+       unsigned int offset;
        SHA_CTX ctx;
+       off_t total;
        struct progress *tp;
-       char name[PATH_MAX];
+       const char *name;
        int do_crc;
        uint32_t crc32;
        unsigned char buffer[8192];
index b8df980dc57cc7b9f3710f4ee90b7aa3d18596ca..41a60af624ae661e9bd96a935ecdc855625b669e 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -406,7 +406,8 @@ static struct daemon_service daemon_service[] = {
        { "receive-pack", "receivepack", receive_pack, 0, 1 },
 };
 
-static void enable_service(const char *name, int ena) {
+static void enable_service(const char *name, int ena)
+{
        int i;
        for (i = 0; i < ARRAY_SIZE(daemon_service); i++) {
                if (!strcmp(daemon_service[i].name, name)) {
@@ -417,7 +418,8 @@ static void enable_service(const char *name, int ena) {
        die("No such service %s", name);
 }
 
-static void make_service_overridable(const char *name, int ena) {
+static void make_service_overridable(const char *name, int ena)
+{
        int i;
        for (i = 0; i < ARRAY_SIZE(daemon_service); i++) {
                if (!strcmp(daemon_service[i].name, name)) {
index da5571302df6ed418874fd4d7423853a7de5b52c..ec1b5e3d446c4e5a56fb5f3e4420499c4e8918eb 100644 (file)
@@ -173,9 +173,10 @@ static int is_in_index(const char *path)
 }
 
 static int handle_diff_files_args(struct rev_info *revs,
-               int argc, const char **argv, int *silent)
+                                 int argc, const char **argv,
+                                 unsigned int *options)
 {
-       *silent = 0;
+       *options = 0;
 
        /* revs->max_count == -2 means --no-index */
        while (1 < argc && argv[1][0] == '-') {
@@ -192,7 +193,7 @@ static int handle_diff_files_args(struct rev_info *revs,
                        revs->diffopt.no_index = 1;
                }
                else if (!strcmp(argv[1], "-q"))
-                       *silent = 1;
+                       *options |= DIFF_SILENT_ON_REMOVED;
                else
                        return error("invalid option: %s", argv[1]);
                argv++; argc--;
@@ -305,9 +306,9 @@ int setup_diff_no_index(struct rev_info *revs,
 
 int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv)
 {
-       int silent_on_removed;
+       unsigned int options;
 
-       if (handle_diff_files_args(revs, argc, argv, &silent_on_removed))
+       if (handle_diff_files_args(revs, argc, argv, &options))
                return -1;
 
        if (revs->diffopt.no_index) {
@@ -329,13 +330,16 @@ int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv)
                perror("read_cache");
                return -1;
        }
-       return run_diff_files(revs, silent_on_removed);
+       return run_diff_files(revs, options);
 }
 
-int run_diff_files(struct rev_info *revs, int silent_on_removed)
+int run_diff_files(struct rev_info *revs, unsigned int option)
 {
        int entries, i;
        int diff_unmerged_stage = revs->max_count;
+       int silent_on_removed = option & DIFF_SILENT_ON_REMOVED;
+       unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
+                             ? CE_MATCH_RACY_IS_DIRTY : 0);
 
        if (diff_unmerged_stage < 0)
                diff_unmerged_stage = 2;
@@ -441,7 +445,7 @@ int run_diff_files(struct rev_info *revs, int silent_on_removed)
                                       ce->sha1, ce->name, NULL);
                        continue;
                }
-               changed = ce_match_stat(ce, &st, 0);
+               changed = ce_match_stat(ce, &st, ce_option);
                if (!changed && !revs->diffopt.find_copies_harder)
                        continue;
                oldmode = ntohl(ce->ce_mode);
diff --git a/diff.h b/diff.h
index 4546aad219742e4ad878937dbd05436c93d298b9..efaa8f711a35c1339aba2bcaffeab6bf95343983 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -224,7 +224,11 @@ extern void diff_flush(struct diff_options*);
 
 extern const char *diff_unique_abbrev(const unsigned char *, int);
 
-extern int run_diff_files(struct rev_info *revs, int silent_on_removed);
+/* do not report anything on removed paths */
+#define DIFF_SILENT_ON_REMOVED 01
+/* report racily-clean paths as modified */
+#define DIFF_RACY_IS_MODIFIED 02
+extern int run_diff_files(struct rev_info *revs, unsigned int option);
 extern int setup_diff_no_index(struct rev_info *revs,
                int argc, const char ** argv, int nongit, const char *prefix);
 extern int run_diff_files_cmd(struct rev_info *revs, int argc, const char **argv);
diff --git a/dir.c b/dir.c
index 5bcc764c97dca5e584d0a4227bfb299efb5699ce..225fdfb52c432b7af1af1cdf9aa9a31f8022e3ec 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -298,7 +298,8 @@ int excluded(struct dir_struct *dir, const char *pathname)
        return 0;
 }
 
-static struct dir_entry *dir_entry_new(const char *pathname, int len) {
+static struct dir_entry *dir_entry_new(const char *pathname, int len)
+{
        struct dir_entry *ent;
 
        ent = xmalloc(sizeof(*ent) + len + 1);
@@ -653,6 +654,7 @@ static void free_simplify(struct path_simplify *simplify)
 int read_directory(struct dir_struct *dir, const char *path, const char *base, int baselen, const char **pathspec)
 {
        struct path_simplify *simplify = create_simplify(pathspec);
+       char *pp = NULL;
 
        /*
         * Make sure to do the per-directory exclude for all the
@@ -660,7 +662,8 @@ int read_directory(struct dir_struct *dir, const char *path, const char *base, i
         */
        if (baselen) {
                if (dir->exclude_per_dir) {
-                       char *p, *pp = xmalloc(baselen+1);
+                       char *p;
+                       pp = xmalloc(baselen+1);
                        memcpy(pp, base, baselen+1);
                        p = pp;
                        while (1) {
@@ -676,12 +679,12 @@ int read_directory(struct dir_struct *dir, const char *path, const char *base, i
                                else
                                        p = pp + baselen;
                        }
-                       free(pp);
                }
        }
 
        read_directory_recursive(dir, path, base, baselen, 0, simplify);
        free_simplify(simplify);
+       free(pp);
        qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);
        qsort(dir->ignored, dir->ignored_nr, sizeof(struct dir_entry *), cmp_name);
        return dir->nr;
@@ -777,3 +780,15 @@ int remove_dir_recursively(struct strbuf *path, int only_empty)
                ret = rmdir(path->buf);
        return ret;
 }
+
+void setup_standard_excludes(struct dir_struct *dir)
+{
+       const char *path;
+
+       dir->exclude_per_dir = ".gitignore";
+       path = git_path("info/exclude");
+       if (!access(path, R_OK))
+               add_excludes_from_file(dir, path);
+       if (excludes_file && !access(excludes_file, R_OK))
+               add_excludes_from_file(dir, excludes_file);
+}
diff --git a/dir.h b/dir.h
index aaa247b2569fc5ae923f12dcd3cdede5c2dccd8d..82009dc13e4b685bc6f4f6e9206d621c7d361c65 100644 (file)
--- a/dir.h
+++ b/dir.h
@@ -71,6 +71,7 @@ extern struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathna
 extern char *get_relative_cwd(char *buffer, int size, const char *dir);
 extern int is_inside_dir(const char *dir);
 
+extern void setup_standard_excludes(struct dir_struct *dir);
 extern int remove_dir_recursively(struct strbuf *path, int only_empty);
 
 #endif
diff --git a/entry.c b/entry.c
index cfadc6a292033d349f6b1efff75d2c4f9f2525fe..257ab46e943f1f8b7445f01c10d949224c17112f 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -203,7 +203,7 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
        strcpy(path + len, ce->name);
 
        if (!lstat(path, &st)) {
-               unsigned changed = ce_match_stat(ce, &st, 1);
+               unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);
                if (!changed)
                        return 0;
                if (!state->force) {
index b5a6c69f7c1d214daa2556d04dd35e0976fc6e5e..1dab72ec1525ca6dd15ca20666cd91506b85890c 100644 (file)
@@ -34,6 +34,7 @@ char *pager_program;
 int pager_in_use;
 int pager_use_color = 1;
 char *editor_program;
+char *excludes_file;
 int auto_crlf = 0;     /* 1: both ways, -1: only when adding git objects */
 
 /* This is set by setup_git_dir_gently() and/or git_default_config() */
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 ac598f88e62fc8f48aaaac8376ccde63cb3e2643..0317ad9127b374a9ded536e6fb2c825a3b13828c 100755 (executable)
@@ -37,10 +37,7 @@ sub list_untracked {
                chomp $_;
                $_;
        }
-       run_cmd_pipe(qw(git ls-files --others
-                       --exclude-per-directory=.gitignore),
-                    "--exclude-from=$GIT_DIR/info/exclude",
-                    '--', @_);
+       run_cmd_pipe(qw(git ls-files --others --exclude-standard --), @_);
 }
 
 my $status_fmt = '%12s %12s %s';
index c18bd32bf430c4cde07777e160cc3d4c81ee8999..3aac8164c62c1f4af8df76832322df9f25a05b38 100755 (executable)
@@ -276,7 +276,8 @@ exit_if_skipped_commits () {
        if expr "$_tried" : ".*[|].*" > /dev/null ; then
                echo "There are only 'skip'ped commit left to test."
                echo "The first bad commit could be any of:"
-               echo "$_tried" | sed -e 's/[|]/\n/g'
+               echo "$_tried" | sed -e 's/[|]/\
+/g'
                echo "We cannot bisect more!"
                exit 2
        fi
index 35a5142c56f8d6f9007fcde840bf0d90b1d02a3a..01c95e9fe8a19afcf331ed5ffd47eea478886213 100755 (executable)
@@ -26,12 +26,13 @@ require_work_tree
 ignored=
 ignoredonly=
 cleandir=
-disabled="`git config --bool clean.requireForce`"
 rmf="rm -f --"
 rmrf="rm -rf --"
 rm_refuse="echo Not removing"
 echo1="echo"
 
+disabled=$(git config --bool clean.requireForce)
+
 while test $# != 0
 do
        case "$1" in
@@ -39,10 +40,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,9 +69,17 @@ do
        shift
 done
 
-if [ "$disabled" = true ]; then
+# 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"
-fi
+       ;;
+esac
 
 if [ "$ignored,$ignoredonly" = "1,1" ]; then
        die "-x and -X cannot be set together"
@@ -78,15 +87,22 @@ fi
 
 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 9a636e55ccb41cb1eba6cde7a54fd33d9d735d94..485339754ca3567c86b824af656700654c68e173 100755 (executable)
@@ -27,7 +27,7 @@ refuse_partial () {
 }
 
 TMP_INDEX=
-THIS_INDEX="$GIT_DIR/index"
+THIS_INDEX="${GIT_INDEX_FILE:-$GIT_DIR/index}"
 NEXT_INDEX="$GIT_DIR/next-index$$"
 rm -f "$NEXT_INDEX"
 save_index () {
@@ -283,9 +283,9 @@ unset only
 case "$all,$interactive,$also,$#" in
 *t,*t,*)
        die "Cannot use -a, --interactive or -i at the same time." ;;
-t,,[1-9]*)
+t,,,[1-9]*)
        die "Paths with -a does not make sense." ;;
-,t,[1-9]*)
+,t,,[1-9]*)
        die "Paths with --interactive does not make sense." ;;
 ,,t,0)
        die "No paths with -i does not make sense." ;;
index 7b29d1b905c618a50704a7b2c38041f71c942e71..ede9408bbd14880b3534110586562c2e6df8b07b 100644 (file)
@@ -183,6 +183,22 @@ void *gitmemmem(const void *haystack, size_t haystacklen,
                 const void *needle, size_t needlelen);
 #endif
 
+#ifdef __GLIBC_PREREQ
+#if __GLIBC_PREREQ(2, 1)
+#define HAVE_STRCHRNUL
+#endif
+#endif
+
+#ifndef HAVE_STRCHRNUL
+#define strchrnul gitstrchrnul
+static inline char *gitstrchrnul(const char *s, int c)
+{
+       while (*s && *s != c)
+               s++;
+       return (char *)s;
+}
+#endif
+
 extern void release_pack_memory(size_t, int);
 
 static inline char* xstrdup(const char *str)
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 f05884c1fab547ab7db5dddc7c399ef90916f3ed..8503ae40309e6c8b1547289c9950d99f4bf736b5 100755 (executable)
@@ -27,7 +27,7 @@ browser="`git config --get instaweb.browser`"
 port=`git config --get instaweb.port`
 module_path="`git config --get instaweb.modulepath`"
 
-conf=$GIT_DIR/gitweb/httpd.conf
+conf="$GIT_DIR/gitweb/httpd.conf"
 
 # Defaults:
 
@@ -44,7 +44,7 @@ start_httpd () {
        httpd_only="`echo $httpd | cut -f1 -d' '`"
        if case "$httpd_only" in /*) : ;; *) which $httpd_only >/dev/null;; esac
        then
-               $httpd $fqgitdir/gitweb/httpd.conf
+               $httpd "$fqgitdir/gitweb/httpd.conf"
        else
                # many httpds are installed in /usr/sbin or /usr/local/sbin
                # these days and those are not in most users $PATHs
@@ -171,14 +171,14 @@ server.pid-file = "$fqgitdir/pid"
 cgi.assign = ( ".cgi" => "" )
 mimetype.assign = ( ".css" => "text/css" )
 EOF
-       test "$local" = true && echo 'server.bind = "127.0.0.1"' >> "$conf"
+       test x"$local" = xtrue && echo 'server.bind = "127.0.0.1"' >> "$conf"
 }
 
 apache2_conf () {
        test -z "$module_path" && module_path=/usr/lib/apache2/modules
        mkdir -p "$GIT_DIR/gitweb/logs"
        bind=
-       test "$local" = true && bind='127.0.0.1:'
+       test x"$local" = xtrue && bind='127.0.0.1:'
        echo 'text/css css' > $fqgitdir/mime.types
        cat > "$conf" <<EOF
 ServerName "git-instaweb"
@@ -231,7 +231,7 @@ EOF
 }
 
 script='
-s#^\(my\|our\) $projectroot =.*#\1 $projectroot = "'`dirname $fqgitdir`'";#
+s#^\(my\|our\) $projectroot =.*#\1 $projectroot = "'$(dirname "$fqgitdir")'";#
 s#\(my\|our\) $gitbin =.*#\1 $gitbin = "'$GIT_EXEC_PATH'";#
 s#\(my\|our\) $projects_list =.*#\1 $projects_list = $projectroot;#
 s#\(my\|our\) $git_temp =.*#\1 $git_temp = "'$fqgitdir/gitweb/tmp'";#'
@@ -251,8 +251,8 @@ gitweb_css () {
 EOFGITWEB
 }
 
-gitweb_cgi $GIT_DIR/gitweb/gitweb.cgi
-gitweb_css $GIT_DIR/gitweb/gitweb.css
+gitweb_cgi "$GIT_DIR/gitweb/gitweb.cgi"
+gitweb_css "$GIT_DIR/gitweb/gitweb.css"
 
 case "$httpd" in
 *lighttpd*)
@@ -271,6 +271,5 @@ webrick)
 esac
 
 start_httpd
-test -z "$browser" && browser=echo
 url=http://127.0.0.1:$port
-$browser $url || echo $url
+"$browser" $url || echo $url
index a5a32e7c70f33369a016dd18ebb072c90b3a40f7..9cedaf80ceac1d4100adf3cfb152c76c7f945e4d 100755 (executable)
@@ -5,6 +5,8 @@ SUBDIRECTORY_OK='Yes'
 OPTIONS_SPEC=
 . git-sh-setup
 
+echo "WARNING: '$0' is deprecated in favor of 'git fsck --lost-found'" >&2
+
 if [ "$#" != "0" ]
 then
     usage
index 173d2325ed3fd8cea6ee47f6510e377d6cd4e3e2..1c123a37e6941b6727c6101bb29cbc485a380c20 100755 (executable)
@@ -40,20 +40,19 @@ allow_trivial_merge=t
 
 dropsave() {
        rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" \
-                "$GIT_DIR/MERGE_SAVE" || exit 1
+                "$GIT_DIR/MERGE_STASH" || exit 1
 }
 
 savestate() {
        # Stash away any local modifications.
-       git diff-index -z --name-only $head |
-       cpio -0 -o >"$GIT_DIR/MERGE_SAVE"
+       git stash create >"$GIT_DIR/MERGE_STASH"
 }
 
 restorestate() {
-        if test -f "$GIT_DIR/MERGE_SAVE"
+        if test -f "$GIT_DIR/MERGE_STASH"
        then
                git reset --hard $head >/dev/null
-               cpio -iuv <"$GIT_DIR/MERGE_SAVE"
+               git stash apply $(cat "$GIT_DIR/MERGE_STASH")
                git update-index --refresh >/dev/null
        fi
 }
@@ -419,7 +418,7 @@ case "$use_strategies" in
     single_strategy=no
     ;;
 *)
-    rm -f "$GIT_DIR/MERGE_SAVE"
+    rm -f "$GIT_DIR/MERGE_STASH"
     single_strategy=yes
     ;;
 esac
index 6d140928890fccc0b2ac8fd640a236ffbad21793..66c80d4e16e3217b93b9de12a4b02d107a2eeb71 100755 (executable)
@@ -392,7 +392,7 @@ do
        -s|--strategy)
                case "$#,$1" in
                *,*=*)
-                       STRATEGY="-s `expr "z$1" : 'z-[^=]*=\(.*\)'`" ;;
+                       STRATEGY="-s "$(expr "z$1" : 'z-[^=]*=\(.*\)') ;;
                1,*)
                        usage ;;
                *)
index e3ad7dedc4c27c505ae1278ed9e108d43bdca32d..df5fd65d56bde3ed046c9ed40e62e8a17ede2e8e 100755 (executable)
@@ -88,7 +88,7 @@ call_merge () {
        cmt="$(cat "$dotest/cmt.$1")"
        echo "$cmt" > "$dotest/current"
        hd=$(git rev-parse --verify HEAD)
-       cmt_name=$(git symbolic-ref HEAD)
+       cmt_name=$(git symbolic-ref HEAD 2> /dev/null || echo HEAD)
        msgnum=$(cat "$dotest/msgnum")
        end=$(cat "$dotest/end")
        eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
@@ -116,7 +116,24 @@ call_merge () {
        esac
 }
 
+move_to_original_branch () {
+       test -z "$head_name" &&
+               head_name="$(cat "$dotest"/head-name)" &&
+               onto="$(cat "$dotest"/onto)" &&
+               orig_head="$(cat "$dotest"/orig-head)"
+       case "$head_name" in
+       refs/*)
+               message="rebase finished: $head_name onto $onto"
+               git update-ref -m "$message" \
+                       $head_name $(git rev-parse HEAD) $orig_head &&
+               git symbolic-ref HEAD $head_name ||
+               die "Could not move back to $head_name"
+               ;;
+       esac
+}
+
 finish_rb_merge () {
+       move_to_original_branch
        rm -r "$dotest"
        echo "All done."
 }
@@ -154,7 +171,11 @@ do
                        finish_rb_merge
                        exit
                fi
-               git am --resolved --3way --resolvemsg="$RESOLVEMSG"
+               head_name=$(cat .dotest/head-name) &&
+               onto=$(cat .dotest/onto) &&
+               orig_head=$(cat .dotest/orig-head) &&
+               git am --resolved --3way --resolvemsg="$RESOLVEMSG" &&
+               move_to_original_branch
                exit
                ;;
        --skip)
@@ -174,16 +195,23 @@ do
                        finish_rb_merge
                        exit
                fi
-               git am -3 --skip --resolvemsg="$RESOLVEMSG"
+               head_name=$(cat .dotest/head-name) &&
+               onto=$(cat .dotest/onto) &&
+               orig_head=$(cat .dotest/orig-head) &&
+               git am -3 --skip --resolvemsg="$RESOLVEMSG" &&
+               move_to_original_branch
                exit
                ;;
        --abort)
                git rerere clear
                if test -d "$dotest"
                then
+                       move_to_original_branch
                        rm -r "$dotest"
                elif test -d .dotest
                then
+                       dotest=.dotest
+                       move_to_original_branch
                        rm -r .dotest
                else
                        die "No rebase in progress?"
@@ -319,6 +347,19 @@ then
        GIT_PAGER='' git diff --stat --summary "$mb" "$onto"
 fi
 
+# move to a detached HEAD
+orig_head=$(git rev-parse HEAD^0)
+head_name=$(git symbolic-ref HEAD 2> /dev/null)
+case "$head_name" in
+'')
+       head_name="detached HEAD"
+       ;;
+*)
+       git checkout "$orig_head" > /dev/null 2>&1 ||
+               die "could not detach HEAD"
+       ;;
+esac
+
 # Rewind the head to "$onto"; this saves our current head in ORIG_HEAD.
 echo "First, rewinding head to replay your work on top of it..."
 git-reset --hard "$onto"
@@ -328,14 +369,21 @@ git-reset --hard "$onto"
 if test "$mb" = "$branch"
 then
        echo >&2 "Fast-forwarded $branch_name to $onto_name."
+       move_to_original_branch
        exit 0
 fi
 
 if test -z "$do_merge"
 then
        git format-patch -k --stdout --full-index --ignore-if-in-upstream "$upstream"..ORIG_HEAD |
-       git am $git_am_opt --binary -3 -k --resolvemsg="$RESOLVEMSG"
-       exit $?
+       git am $git_am_opt --binary -3 -k --resolvemsg="$RESOLVEMSG" &&
+       move_to_original_branch
+       ret=$?
+       test 0 != $ret -a -d .dotest &&
+               echo $head_name > .dotest/head-name &&
+               echo $onto > .dotest/onto &&
+               echo $orig_head > .dotest/orig-head
+       exit $ret
 fi
 
 # start doing a rebase with git-merge
@@ -344,8 +392,10 @@ fi
 mkdir -p "$dotest"
 echo "$onto" > "$dotest/onto"
 echo "$onto_name" > "$dotest/onto_name"
-prev_head=`git rev-parse HEAD^0`
+prev_head=$orig_head
 echo "$prev_head" > "$dotest/prev_head"
+echo "$orig_head" > "$dotest/orig-head"
+echo "$head_name" > "$dotest/head-name"
 
 msgnum=0
 for cmt in `git rev-list --reverse --no-merges "$upstream"..ORIG_HEAD`
index 90d969c625f83860538f4cf17a2a2abde81fc945..068f5e0fc7308db601141bc3e70475ec2145ef67 100755 (executable)
@@ -25,13 +25,13 @@ headrev=`git rev-parse --verify "$head"^0` || exit
 merge_base=`git merge-base $baserev $headrev` ||
 die "fatal: No commits in common between $base and $head"
 
-url="`get_remote_url "$url"`"
-branch=`git peek-remote "$url" \
+url=$(get_remote_url "$url")
+branch=$(git peek-remote "$url" \
        | sed -n -e "/^$headrev refs.heads./{
                s/^.*   refs.heads.//
                p
                q
-       }"`
+       }")
 if [ -z "$branch" ]; then
        echo "warn: No branch of $url is at:" >&2
        git log --max-count=1 --pretty='format:warn:   %h: %s' $headrev >&2
index 96051bc01e1585a69a3e0746bbef7016ec01663e..fd0a4ad0c24dfedd2fea278733d8f6cff59b2eb5 100755 (executable)
@@ -88,8 +88,7 @@ sub usage {
 
    --smtp-ssl     If set, connects to the SMTP server using SSL.
 
-   --suppress-from Suppress sending emails to yourself if your address
-                  appears in a From: line. Defaults to off.
+   --suppress-from Suppress sending emails to yourself. Defaults to off.
 
    --thread       Specify that the "In-Reply-To:" header should be set on all
                   emails. Defaults to on.
@@ -353,7 +352,7 @@ sub expand_aliases {
 
 if (!defined $initial_subject && $compose) {
        do {
-               $_ = $term->readline("What subject should the emails start with? ",
+               $_ = $term->readline("What subject should the initial email start with? ",
                        $initial_subject);
        } while (!defined $_);
        $initial_subject = $_;
@@ -515,11 +514,13 @@ sub make_message_id
 
 sub unquote_rfc2047 {
        local ($_) = @_;
-       if (s/=\?utf-8\?q\?(.*)\?=/$1/g) {
+       my $encoding;
+       if (s/=\?([^?]+)\?q\?(.*)\?=/$2/g) {
+               $encoding = $1;
                s/_/ /g;
                s/=([0-9A-F]{2})/chr(hex($1))/eg;
        }
-       return "$_";
+       return wantarray ? ($_, $encoding) : $_;
 }
 
 # use the simplest quoting being able to handle the recipient
@@ -668,6 +669,9 @@ sub send_message
        open(F,"<",$t) or die "can't open file $t";
 
        my $author = undef;
+       my $author_encoding;
+       my $has_content_type;
+       my $body_encoding;
        @cc = @initial_cc;
        @xh = ();
        my $input_format = undef;
@@ -693,12 +697,20 @@ sub send_message
                                                next if ($suppress_from);
                                        }
                                        elsif ($1 eq 'From') {
-                                               $author = unquote_rfc2047($2);
+                                               ($author, $author_encoding)
+                                                 = unquote_rfc2047($2);
                                        }
                                        printf("(mbox) Adding cc: %s from line '%s'\n",
                                                $2, $_) unless $quiet;
                                        push @cc, $2;
                                }
+                               elsif (/^Content-type:/i) {
+                                       $has_content_type = 1;
+                                       if (/charset="?[^ "]+/) {
+                                               $body_encoding = $1;
+                                       }
+                                       push @xh, $_;
+                               }
                                elsif (!/^Date:\s/ && /^[-A-Za-z]+:\s+\S/) {
                                        push @xh, $_;
                                }
@@ -730,6 +742,7 @@ sub send_message
                        if (/^(Signed-off-by|Cc): (.*)$/i && $signed_off_cc) {
                                my $c = $2;
                                chomp $c;
+                               next if ($c eq $sender and $suppress_from);
                                push @cc, $c;
                                printf("(sob) Adding cc: %s from line '%s'\n",
                                        $c, $_) unless $quiet;
@@ -745,6 +758,7 @@ sub send_message
                        my $c = $_;
                        $c =~ s/^\s*//g;
                        $c =~ s/\n$//g;
+                       next if ($c eq $sender and $suppress_from);
                        push @cc, $c;
                        printf("(cc-cmd) Adding cc: %s from: '%s'\n",
                                $c, $cc_cmd) unless $quiet;
@@ -755,6 +769,21 @@ sub send_message
 
        if (defined $author) {
                $message = "From: $author\n\n$message";
+               if (defined $author_encoding) {
+                       if ($has_content_type) {
+                               if ($body_encoding eq $author_encoding) {
+                                       # ok, we already have the right encoding
+                               }
+                               else {
+                                       # uh oh, we should re-encode
+                               }
+                       }
+                       else {
+                               push @xh,
+                                 'MIME-Version: 1.0',
+                                 "Content-Type: text/plain; charset=$author_encoding";
+                       }
+               }
        }
 
        send_message();
index 9cabd5dc2cdbdd5de98acb3a0c839dfb07a3c9f3..534eb168abf8b0b8ae5c2195bf85b66d9cb6b21e 100755 (executable)
@@ -22,23 +22,17 @@ no_changes () {
 clear_stash () {
        if current=$(git rev-parse --verify $ref_stash 2>/dev/null)
        then
-               git update-ref -d refs/stash $current
+               git update-ref -d $ref_stash $current
        fi
 }
 
-save_stash () {
+create_stash () {
        stash_msg="$1"
 
        if no_changes
        then
-               echo >&2 'No local changes to save'
                exit 0
        fi
-       test -f "$GIT_DIR/logs/$ref_stash" ||
-               clear_stash || die "Cannot initialize stash"
-
-       # Make sure the reflog for stash is kept.
-       : >>"$GIT_DIR/logs/$ref_stash"
 
        # state of the base commit
        if b_commit=$(git rev-parse --verify HEAD)
@@ -85,6 +79,23 @@ save_stash () {
        w_commit=$(printf '%s\n' "$stash_msg" |
                git commit-tree $w_tree -p $b_commit -p $i_commit) ||
                die "Cannot record working tree state"
+}
+
+save_stash () {
+       stash_msg="$1"
+
+       if no_changes
+       then
+               echo >&2 'No local changes to save'
+               exit 0
+       fi
+       test -f "$GIT_DIR/logs/$ref_stash" ||
+               clear_stash || die "Cannot initialize stash"
+
+       create_stash "$stash_msg"
+
+       # Make sure the reflog for stash is kept.
+       : >>"$GIT_DIR/logs/$ref_stash"
 
        git update-ref -m "$stash_msg" $ref_stash $w_commit ||
                die "Cannot save the current status"
@@ -203,6 +214,13 @@ apply)
 clear)
        clear_stash
        ;;
+create)
+       if test $# -gt 0 && test "$1" = create
+       then
+               shift
+       fi
+       create_stash "$*" && echo "$w_commit"
+       ;;
 help | usage)
        usage
        ;;
index 1c656be1cfb6eb7d63e6a1f3cdda959cf90aca89..82ac28fa27dc41b821905f1a83155994d56c4f3b 100755 (executable)
@@ -74,7 +74,7 @@ resolve_relative_url ()
 module_name()
 {
        # Do we have "submodule.<something>.path = $1" defined in .gitmodules file?
-       re=$(printf '%s' "$1" | sed -e 's/\([^a-zA-Z0-9_]\)/\\\1/g')
+       re=$(printf '%s' "$1" | sed -e 's/[].[^$\\*]/\\&/g')
        name=$( GIT_CONFIG=.gitmodules \
                git config --get-regexp '^submodule\..*\.path$' |
                sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p' )
index dd93e320a7c0d20e8eec1c171c9c96a32ced406b..5b1deeab942aa2a63a6cbe6a92792dbbe6f17d01 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);
@@ -422,6 +425,9 @@ sub cmd_dcommit {
                        my %ed_opts = ( r => $last_rev,
                                        log => get_commit_entry($d)->{log},
                                        ra => Git::SVN::Ra->new($gs->full_url),
+                                       config => SVN::Core::config_get_config(
+                                               $Git::SVN::Ra::config_dir
+                                       ),
                                        tree_a => "$d~1",
                                        tree_b => $d,
                                        editor_cb => sub {
@@ -2393,10 +2399,15 @@ sub rev_db_get {
        $ret;
 }
 
+# Finds the first svn revision that exists on (if $eq_ok is true) or
+# before $rev for the current branch.  It will not search any lower
+# than $min_rev.  Returns the git commit hash and svn revision number
+# if found, else (undef, undef).
 sub find_rev_before {
-       my ($self, $rev, $eq_ok) = @_;
+       my ($self, $rev, $eq_ok, $min_rev) = @_;
        --$rev unless $eq_ok;
-       while ($rev > 0) {
+       $min_rev ||= 1;
+       while ($rev >= $min_rev) {
                if (my $c = $self->rev_db_get($rev)) {
                        return ($rev, $c);
                }
@@ -2405,6 +2416,23 @@ sub find_rev_before {
        return (undef, undef);
 }
 
+# Finds the first svn revision that exists on (if $eq_ok is true) or
+# after $rev for the current branch.  It will not search any higher
+# than $max_rev.  Returns the git commit hash and svn revision number
+# if found, else (undef, undef).
+sub find_rev_after {
+       my ($self, $rev, $eq_ok, $max_rev) = @_;
+       ++$rev unless $eq_ok;
+       $max_rev ||= $self->rev_db_max();
+       while ($rev <= $max_rev) {
+               if (my $c = $self->rev_db_get($rev)) {
+                       return ($rev, $c);
+               }
+               ++$rev;
+       }
+       return (undef, undef);
+}
+
 sub _new {
        my ($class, $repo_id, $ref_id, $path) = @_;
        unless (defined $repo_id && length $repo_id) {
@@ -3220,6 +3248,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 +3299,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 +3429,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)?://#) {
@@ -3675,6 +3723,7 @@ package Git::SVN::Log;
 use strict;
 use warnings;
 use POSIX qw/strftime/;
+use constant commit_log_separator => ('-' x 72) . "\n";
 use vars qw/$TZ $limit $color $pager $non_recursive $verbose $oneline
             %rusers $show_commit $incremental/;
 my $l_fmt;
@@ -3768,19 +3817,19 @@ sub git_svn_log_cmd {
                        push @cmd, $c;
                }
        } elsif (defined $r_max) {
-               my ($c_min, $c_max);
-               $c_max = $gs->rev_db_get($r_max);
-               $c_min = $gs->rev_db_get($r_min);
-               if (defined $c_min && defined $c_max) {
-                       if ($r_max > $r_max) {
-                               push @cmd, "$c_min..$c_max";
-                       } else {
-                               push @cmd, "$c_max..$c_min";
-                       }
-               } elsif ($r_max > $r_min) {
-                       push @cmd, $c_max;
+               if ($r_max < $r_min) {
+                       ($r_min, $r_max) = ($r_max, $r_min);
+               }
+               my (undef, $c_max) = $gs->find_rev_before($r_max, 1, $r_min);
+               my (undef, $c_min) = $gs->find_rev_after($r_min, 1, $r_max);
+               # If there are no commits in the range, both $c_max and $c_min
+               # will be undefined.  If there is at least 1 commit in the
+               # range, both will be defined.
+               return () if !defined $c_min || !defined $c_max;
+               if ($c_min eq $c_max) {
+                       push @cmd, '--max-count=1', $c_min;
                } else {
-                       push @cmd, $c_min;
+                       push @cmd, '--boundary', "$c_min..$c_max";
                }
        }
        return (@cmd, @files);
@@ -3888,7 +3937,7 @@ sub show_commit_changed_paths {
 
 sub show_commit_normal {
        my ($c) = @_;
-       print '-' x72, "\nr$c->{r} | ";
+       print commit_log_separator, "r$c->{r} | ";
        print "$c->{c} | " if $show_commit;
        print "$c->{a} | ", strftime("%Y-%m-%d %H:%M:%S %z (%a, %d %b %Y)",
                                 localtime($c->{t_utc})), ' | ';
@@ -3949,12 +3998,16 @@ sub cmd_show_log {
 
        config_pager();
        @args = git_svn_log_cmd($r_min, $r_max, @args);
+       if (!@args) {
+               print commit_log_separator unless $incremental || $oneline;
+               return;
+       }
        my $log = command_output_pipe(@args);
        run_pager();
        my (@k, $c, $d, $stat);
        my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/;
        while (<$log>) {
-               if (/^${esc_color}commit ($::sha1_short)/o) {
+               if (/^${esc_color}commit -?($::sha1_short)/o) {
                        my $cmt = $1;
                        if ($c && cmt_showable($c) && $c->{r} != $r_last) {
                                $r_last = $c->{r};
@@ -3997,14 +4050,12 @@ sub cmd_show_log {
                process_commit($c, $r_min, $r_max, \@k);
        }
        if (@k) {
-               my $swap = $r_max;
-               $r_max = $r_min;
-               $r_min = $swap;
+               ($r_min, $r_max) = ($r_max, $r_min);
                process_commit($_, $r_min, $r_max) foreach reverse @k;
        }
 out:
        close $log;
-       print '-' x72,"\n" unless $incremental || $oneline;
+       print commit_log_separator unless $incremental || $oneline;
 }
 
 package Git::SVN::Migration;
diff --git a/git.c b/git.c
index b843da4d424d23d2855d84f55eef52e8a3fa1bb7..7604319b5a9e8c12b2f00b4d5e6480445e02daa6 100644 (file)
--- a/git.c
+++ b/git.c
@@ -249,14 +249,9 @@ static int run_command(struct cmd_struct *p, int argc, const char **argv)
                prefix = setup_git_directory();
        if (p->option & USE_PAGER)
                setup_pager();
-       if (p->option & NEED_WORK_TREE) {
-               const char *work_tree = get_git_work_tree();
-               const char *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("%s must be run in a work tree", p->cmd);
-       }
+       if (p->option & NEED_WORK_TREE)
+               setup_work_tree();
+
        trace_argv_printf(argv, argc, "trace: built-in: git");
 
        status = p->fn(argc, argv, prefix);
@@ -345,7 +340,7 @@ static void handle_internal_command(int argc, const char **argv)
                { "rev-list", cmd_rev_list, RUN_SETUP },
                { "rev-parse", cmd_rev_parse },
                { "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
-               { "rm", cmd_rm, RUN_SETUP | NEED_WORK_TREE },
+               { "rm", cmd_rm, RUN_SETUP },
                { "runstatus", cmd_runstatus, RUN_SETUP | NEED_WORK_TREE },
                { "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER },
                { "show-branch", cmd_show_branch, RUN_SETUP },
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")) {
diff --git a/help.c b/help.c
index 855aeef92f00689fd7b283c42e42b90df42f897e..8217d97787b2ba38a5327c1204797044b2b4cd72 100644 (file)
--- a/help.c
+++ b/help.c
@@ -79,7 +79,8 @@ static void uniq(struct cmdnames *cmds)
        cmds->cnt = j;
 }
 
-static void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes) {
+static void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
+{
        int ci, cj, ei;
        int cmp;
 
index 715a5bb7a6e42694b3e35de703e44e792a5442fe..9fd6982a979a40e701dcb6bcaf117eafbf6ff161 100644 (file)
@@ -87,9 +87,9 @@ static void *fill(int min)
                                die("early EOF");
                        die("read error on input: %s", strerror(errno));
                }
-               if (from_stdin)
-                       display_throughput(progress, ret);
                input_len += ret;
+               if (from_stdin)
+                       display_throughput(progress, consumed_bytes + input_len);
        } while (input_len < min);
        return input_buffer;
 }
@@ -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;
@@ -792,6 +792,7 @@ int main(int argc, char **argv)
                flush();
        } else {
                if (fix_thin_pack) {
+                       char msg[48];
                        int nr_unresolved = nr_deltas - nr_resolved_deltas;
                        int nr_objects_initial = nr_objects;
                        if (nr_unresolved <= 0)
@@ -800,12 +801,11 @@ int main(int argc, char **argv)
                                           (nr_objects + nr_unresolved + 1)
                                           * sizeof(*objects));
                        fix_unresolved_deltas(nr_unresolved);
-                       stop_progress(&progress);
-                       if (verbose)
-                               fprintf(stderr, "%d objects were added to complete this thin pack.\n",
-                                       nr_objects - nr_objects_initial);
+                       sprintf(msg, "completed with %d local objects",
+                               nr_objects - nr_objects_initial);
+                       stop_progress_msg(&progress, msg);
                        fixup_pack_header_footer(output_fd, sha1,
-                               curr_pack, nr_objects);
+                                                curr_pack, nr_objects);
                }
                if (nr_deltas != nr_resolved_deltas)
                        die("pack has %d unresolved deltas",
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);
index 3f4080cbf84e16ab3dd21a82d9948c5646c1c40f..dca92c8adb52e212ef96410d3efd4deaa28e385f 100644 (file)
@@ -812,7 +812,7 @@ sub _cmd_exec {
                $self->wc_subdir() and chdir($self->wc_subdir());
        }
        _execv_git_cmd(@args);
-       die "exec failed: $!";
+       die qq[exec "@args" failed: $!];
 }
 
 # Execute the given Git command ($_[0]) with arguments ($_[1..])
index 490cede263020dc15f4d48af06faf8d77552883f..9db75b4e4f24b28ca44d65750ec6ebb4feb99eee 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -1,6 +1,5 @@
 #include "cache.h"
 #include "commit.h"
-#include "interpolate.h"
 #include "utf8.h"
 #include "diff.h"
 #include "revision.h"
@@ -283,7 +282,8 @@ static char *logmsg_reencode(const struct commit *commit,
        return out;
 }
 
-static void fill_person(struct interp *table, const char *msg, int len)
+static void format_person_part(struct strbuf *sb, char part,
+                               const char *msg, int len)
 {
        int start, end, tz = 0;
        unsigned long date;
@@ -295,7 +295,10 @@ static void fill_person(struct interp *table, const char *msg, int len)
        start = end + 1;
        while (end > 0 && isspace(msg[end - 1]))
                end--;
-       table[0].value = xmemdupz(msg, end);
+       if (part == 'n') {      /* name */
+               strbuf_add(sb, msg, end);
+               return;
+       }
 
        if (start >= len)
                return;
@@ -307,7 +310,10 @@ static void fill_person(struct interp *table, const char *msg, int len)
        if (end >= len)
                return;
 
-       table[1].value = xmemdupz(msg + start, end - start);
+       if (part == 'e') {      /* email */
+               strbuf_add(sb, msg + start, end - start);
+               return;
+       }
 
        /* parse date */
        for (start = end + 1; start < len && isspace(msg[start]); start++)
@@ -318,7 +324,10 @@ static void fill_person(struct interp *table, const char *msg, int len)
        if (msg + start == ep)
                return;
 
-       table[5].value = xmemdupz(msg + start, ep - (msg + start));
+       if (part == 't') {      /* date, UNIX timestamp */
+               strbuf_add(sb, msg + start, ep - (msg + start));
+               return;
+       }
 
        /* parse tz */
        for (start = ep - msg + 1; start < len && isspace(msg[start]); start++)
@@ -329,115 +338,66 @@ static void fill_person(struct interp *table, const char *msg, int len)
                        tz = -tz;
        }
 
-       interp_set_entry(table, 2, show_date(date, tz, DATE_NORMAL));
-       interp_set_entry(table, 3, show_date(date, tz, DATE_RFC2822));
-       interp_set_entry(table, 4, show_date(date, tz, DATE_RELATIVE));
-       interp_set_entry(table, 6, show_date(date, tz, DATE_ISO8601));
+       switch (part) {
+       case 'd':       /* date */
+               strbuf_addstr(sb, show_date(date, tz, DATE_NORMAL));
+               return;
+       case 'D':       /* date, RFC2822 style */
+               strbuf_addstr(sb, show_date(date, tz, DATE_RFC2822));
+               return;
+       case 'r':       /* date, relative */
+               strbuf_addstr(sb, show_date(date, tz, DATE_RELATIVE));
+               return;
+       case 'i':       /* date, ISO 8601 */
+               strbuf_addstr(sb, show_date(date, tz, DATE_ISO8601));
+               return;
+       }
 }
 
-void format_commit_message(const struct commit *commit,
-                           const void *format, struct strbuf *sb)
-{
-       struct interp table[] = {
-               { "%H" },       /* commit hash */
-               { "%h" },       /* abbreviated commit hash */
-               { "%T" },       /* tree hash */
-               { "%t" },       /* abbreviated tree hash */
-               { "%P" },       /* parent hashes */
-               { "%p" },       /* abbreviated parent hashes */
-               { "%an" },      /* author name */
-               { "%ae" },      /* author email */
-               { "%ad" },      /* author date */
-               { "%aD" },      /* author date, RFC2822 style */
-               { "%ar" },      /* author date, relative */
-               { "%at" },      /* author date, UNIX timestamp */
-               { "%ai" },      /* author date, ISO 8601 */
-               { "%cn" },      /* committer name */
-               { "%ce" },      /* committer email */
-               { "%cd" },      /* committer date */
-               { "%cD" },      /* committer date, RFC2822 style */
-               { "%cr" },      /* committer date, relative */
-               { "%ct" },      /* committer date, UNIX timestamp */
-               { "%ci" },      /* committer date, ISO 8601 */
-               { "%e" },       /* encoding */
-               { "%s" },       /* subject */
-               { "%b" },       /* body */
-               { "%Cred" },    /* red */
-               { "%Cgreen" },  /* green */
-               { "%Cblue" },   /* blue */
-               { "%Creset" },  /* reset color */
-               { "%n" },       /* newline */
-               { "%m" },       /* left/right/bottom */
-       };
-       enum interp_index {
-               IHASH = 0, IHASH_ABBREV,
-               ITREE, ITREE_ABBREV,
-               IPARENTS, IPARENTS_ABBREV,
-               IAUTHOR_NAME, IAUTHOR_EMAIL,
-               IAUTHOR_DATE, IAUTHOR_DATE_RFC2822, IAUTHOR_DATE_RELATIVE,
-               IAUTHOR_TIMESTAMP, IAUTHOR_ISO8601,
-               ICOMMITTER_NAME, ICOMMITTER_EMAIL,
-               ICOMMITTER_DATE, ICOMMITTER_DATE_RFC2822,
-               ICOMMITTER_DATE_RELATIVE, ICOMMITTER_TIMESTAMP,
-               ICOMMITTER_ISO8601,
-               IENCODING,
-               ISUBJECT,
-               IBODY,
-               IRED, IGREEN, IBLUE, IRESET_COLOR,
-               INEWLINE,
-               ILEFT_RIGHT,
-       };
-       struct commit_list *p;
-       char parents[1024];
-       unsigned long len;
-       int i;
-       enum { HEADER, SUBJECT, BODY } state;
-       const char *msg = commit->buffer;
+struct chunk {
+       size_t off;
+       size_t len;
+};
 
-       if (ILEFT_RIGHT + 1 != ARRAY_SIZE(table))
-               die("invalid interp table!");
+struct format_commit_context {
+       const struct commit *commit;
+
+       /* These offsets are relative to the start of the commit message. */
+       int commit_header_parsed;
+       struct chunk subject;
+       struct chunk author;
+       struct chunk committer;
+       struct chunk encoding;
+       size_t body_off;
+
+       /* The following ones are relative to the result struct strbuf. */
+       struct chunk abbrev_commit_hash;
+       struct chunk abbrev_tree_hash;
+       struct chunk abbrev_parent_hashes;
+};
 
-       /* these are independent of the commit */
-       interp_set_entry(table, IRED, "\033[31m");
-       interp_set_entry(table, IGREEN, "\033[32m");
-       interp_set_entry(table, IBLUE, "\033[34m");
-       interp_set_entry(table, IRESET_COLOR, "\033[m");
-       interp_set_entry(table, INEWLINE, "\n");
+static int add_again(struct strbuf *sb, struct chunk *chunk)
+{
+       if (chunk->len) {
+               strbuf_adddup(sb, chunk->off, chunk->len);
+               return 1;
+       }
 
-       /* these depend on the commit */
-       if (!commit->object.parsed)
-               parse_object(commit->object.sha1);
-       interp_set_entry(table, IHASH, sha1_to_hex(commit->object.sha1));
-       interp_set_entry(table, IHASH_ABBREV,
-                       find_unique_abbrev(commit->object.sha1,
-                               DEFAULT_ABBREV));
-       interp_set_entry(table, ITREE, sha1_to_hex(commit->tree->object.sha1));
-       interp_set_entry(table, ITREE_ABBREV,
-                       find_unique_abbrev(commit->tree->object.sha1,
-                               DEFAULT_ABBREV));
-       interp_set_entry(table, ILEFT_RIGHT,
-                        (commit->object.flags & BOUNDARY)
-                        ? "-"
-                        : (commit->object.flags & SYMMETRIC_LEFT)
-                        ? "<"
-                        : ">");
-
-       parents[1] = 0;
-       for (i = 0, p = commit->parents;
-                       p && i < sizeof(parents) - 1;
-                       p = p->next)
-               i += snprintf(parents + i, sizeof(parents) - i - 1, " %s",
-                       sha1_to_hex(p->item->object.sha1));
-       interp_set_entry(table, IPARENTS, parents + 1);
-
-       parents[1] = 0;
-       for (i = 0, p = commit->parents;
-                       p && i < sizeof(parents) - 1;
-                       p = p->next)
-               i += snprintf(parents + i, sizeof(parents) - i - 1, " %s",
-                       find_unique_abbrev(p->item->object.sha1,
-                               DEFAULT_ABBREV));
-       interp_set_entry(table, IPARENTS_ABBREV, parents + 1);
+       /*
+        * We haven't seen this chunk before.  Our caller is surely
+        * going to add it the hard way now.  Remember the most likely
+        * start of the to-be-added chunk: the current end of the
+        * struct strbuf.
+        */
+       chunk->off = sb->len;
+       return 0;
+}
+
+static void parse_commit_header(struct format_commit_context *context)
+{
+       const char *msg = context->commit->buffer;
+       int i;
+       enum { HEADER, SUBJECT, BODY } state;
 
        for (i = 0, state = HEADER; msg[i] && state < BODY; i++) {
                int eol;
@@ -445,7 +405,8 @@ void format_commit_message(const struct commit *commit,
                        ; /* do nothing */
 
                if (state == SUBJECT) {
-                       table[ISUBJECT].value = xmemdupz(msg + i, eol - i);
+                       context->subject.off = i;
+                       context->subject.len = eol - i;
                        i = eol;
                }
                if (i == eol) {
@@ -453,29 +414,170 @@ void format_commit_message(const struct commit *commit,
                        /* strip empty lines */
                        while (msg[eol + 1] == '\n')
                                eol++;
-               } else if (!prefixcmp(msg + i, "author "))
-                       fill_person(table + IAUTHOR_NAME,
-                                       msg + i + 7, eol - i - 7);
-               else if (!prefixcmp(msg + i, "committer "))
-                       fill_person(table + ICOMMITTER_NAME,
-                                       msg + i + 10, eol - i - 10);
-               else if (!prefixcmp(msg + i, "encoding "))
-                       table[IENCODING].value =
-                               xmemdupz(msg + i + 9, eol - i - 9);
+               } else if (!prefixcmp(msg + i, "author ")) {
+                       context->author.off = i + 7;
+                       context->author.len = eol - i - 7;
+               } else if (!prefixcmp(msg + i, "committer ")) {
+                       context->committer.off = i + 10;
+                       context->committer.len = eol - i - 10;
+               } else if (!prefixcmp(msg + i, "encoding ")) {
+                       context->encoding.off = i + 9;
+                       context->encoding.len = eol - i - 9;
+               }
                i = eol;
        }
-       if (msg[i])
-               table[IBODY].value = xstrdup(msg + i);
+       context->body_off = i;
+       context->commit_header_parsed = 1;
+}
+
+static void format_commit_item(struct strbuf *sb, const char *placeholder,
+                               void *context)
+{
+       struct format_commit_context *c = context;
+       const struct commit *commit = c->commit;
+       const char *msg = commit->buffer;
+       struct commit_list *p;
+
+       /* these are independent of the commit */
+       switch (placeholder[0]) {
+       case 'C':
+               switch (placeholder[3]) {
+               case 'd':       /* red */
+                       strbuf_addstr(sb, "\033[31m");
+                       return;
+               case 'e':       /* green */
+                       strbuf_addstr(sb, "\033[32m");
+                       return;
+               case 'u':       /* blue */
+                       strbuf_addstr(sb, "\033[34m");
+                       return;
+               case 's':       /* reset color */
+                       strbuf_addstr(sb, "\033[m");
+                       return;
+               }
+       case 'n':               /* newline */
+               strbuf_addch(sb, '\n');
+               return;
+       }
 
-       len = interpolate(sb->buf + sb->len, strbuf_avail(sb),
-                               format, table, ARRAY_SIZE(table));
-       if (len > strbuf_avail(sb)) {
-               strbuf_grow(sb, len);
-               interpolate(sb->buf + sb->len, strbuf_avail(sb) + 1,
-                                       format, table, ARRAY_SIZE(table));
+       /* these depend on the commit */
+       if (!commit->object.parsed)
+               parse_object(commit->object.sha1);
+
+       switch (placeholder[0]) {
+       case 'H':               /* commit hash */
+               strbuf_addstr(sb, sha1_to_hex(commit->object.sha1));
+               return;
+       case 'h':               /* abbreviated commit hash */
+               if (add_again(sb, &c->abbrev_commit_hash))
+                       return;
+               strbuf_addstr(sb, find_unique_abbrev(commit->object.sha1,
+                                                    DEFAULT_ABBREV));
+               c->abbrev_commit_hash.len = sb->len - c->abbrev_commit_hash.off;
+               return;
+       case 'T':               /* tree hash */
+               strbuf_addstr(sb, sha1_to_hex(commit->tree->object.sha1));
+               return;
+       case 't':               /* abbreviated tree hash */
+               if (add_again(sb, &c->abbrev_tree_hash))
+                       return;
+               strbuf_addstr(sb, find_unique_abbrev(commit->tree->object.sha1,
+                                                    DEFAULT_ABBREV));
+               c->abbrev_tree_hash.len = sb->len - c->abbrev_tree_hash.off;
+               return;
+       case 'P':               /* parent hashes */
+               for (p = commit->parents; p; p = p->next) {
+                       if (p != commit->parents)
+                               strbuf_addch(sb, ' ');
+                       strbuf_addstr(sb, sha1_to_hex(p->item->object.sha1));
+               }
+               return;
+       case 'p':               /* abbreviated parent hashes */
+               if (add_again(sb, &c->abbrev_parent_hashes))
+                       return;
+               for (p = commit->parents; p; p = p->next) {
+                       if (p != commit->parents)
+                               strbuf_addch(sb, ' ');
+                       strbuf_addstr(sb, find_unique_abbrev(
+                                       p->item->object.sha1, DEFAULT_ABBREV));
+               }
+               c->abbrev_parent_hashes.len = sb->len -
+                                             c->abbrev_parent_hashes.off;
+               return;
+       case 'm':               /* left/right/bottom */
+               strbuf_addch(sb, (commit->object.flags & BOUNDARY)
+                                ? '-'
+                                : (commit->object.flags & SYMMETRIC_LEFT)
+                                ? '<'
+                                : '>');
+               return;
+       }
+
+       /* For the rest we have to parse the commit header. */
+       if (!c->commit_header_parsed)
+               parse_commit_header(c);
+
+       switch (placeholder[0]) {
+       case 's':
+               strbuf_add(sb, msg + c->subject.off, c->subject.len);
+               return;
+       case 'a':
+               format_person_part(sb, placeholder[1],
+                                  msg + c->author.off, c->author.len);
+               return;
+       case 'c':
+               format_person_part(sb, placeholder[1],
+                                  msg + c->committer.off, c->committer.len);
+               return;
+       case 'e':
+               strbuf_add(sb, msg + c->encoding.off, c->encoding.len);
+               return;
+       case 'b':
+               strbuf_addstr(sb, msg + c->body_off);
+               return;
        }
-       strbuf_setlen(sb, sb->len + len);
-       interp_clear_table(table, ARRAY_SIZE(table));
+}
+
+void format_commit_message(const struct commit *commit,
+                           const void *format, struct strbuf *sb)
+{
+       const char *placeholders[] = {
+               "H",            /* commit hash */
+               "h",            /* abbreviated commit hash */
+               "T",            /* tree hash */
+               "t",            /* abbreviated tree hash */
+               "P",            /* parent hashes */
+               "p",            /* abbreviated parent hashes */
+               "an",           /* author name */
+               "ae",           /* author email */
+               "ad",           /* author date */
+               "aD",           /* author date, RFC2822 style */
+               "ar",           /* author date, relative */
+               "at",           /* author date, UNIX timestamp */
+               "ai",           /* author date, ISO 8601 */
+               "cn",           /* committer name */
+               "ce",           /* committer email */
+               "cd",           /* committer date */
+               "cD",           /* committer date, RFC2822 style */
+               "cr",           /* committer date, relative */
+               "ct",           /* committer date, UNIX timestamp */
+               "ci",           /* committer date, ISO 8601 */
+               "e",            /* encoding */
+               "s",            /* subject */
+               "b",            /* body */
+               "Cred",         /* red */
+               "Cgreen",       /* green */
+               "Cblue",        /* blue */
+               "Creset",       /* reset color */
+               "n",            /* newline */
+               "m",            /* left/right/bottom */
+               NULL
+       };
+       struct format_commit_context context;
+
+       memset(&context, 0, sizeof(context));
+       context.commit = commit;
+       strbuf_expand(sb, format, placeholders, format_commit_item, &context);
 }
 
 static void pp_header(enum cmit_fmt fmt,
index 3f6a602a534a7bd5dfea2fca4239af6f9ed5ceca..4bd650f9ba496786029791bc8a0a40b611bdeb63 100644 (file)
 #define TP_IDX_MAX      8
 
 struct throughput {
+       off_t curr_total;
+       off_t prev_total;
        struct timeval prev_tv;
-       off_t total;
-       unsigned long count;
-       unsigned long avg_bytes;
-       unsigned long last_bytes[TP_IDX_MAX];
+       unsigned int avg_bytes;
        unsigned int avg_misecs;
+       unsigned int last_bytes[TP_IDX_MAX];
        unsigned int last_misecs[TP_IDX_MAX];
        unsigned int idx;
        char display[32];
@@ -69,9 +69,9 @@ static void clear_progress_signal(void)
        progress_update = 0;
 }
 
-static int display(struct progress *progress, unsigned n, int done)
+static int display(struct progress *progress, unsigned n, const char *done)
 {
-       char *eol, *tp;
+       const char *eol, *tp;
 
        if (progress->delay) {
                if (!progress_update || --progress->delay)
@@ -90,7 +90,7 @@ static int display(struct progress *progress, unsigned n, int done)
 
        progress->last_value = n;
        tp = (progress->throughput) ? progress->throughput->display : "";
-       eol = done ? ", done.   \n" : "   \r";
+       eol = done ? done : "   \r";
        if (progress->total) {
                unsigned percent = n * 100 / progress->total;
                if (percent != progress->last_percent || progress_update) {
@@ -110,7 +110,31 @@ static int display(struct progress *progress, unsigned n, int done)
        return 0;
 }
 
-void display_throughput(struct progress *progress, unsigned long n)
+static void throughput_string(struct throughput *tp, off_t total,
+                             unsigned int rate)
+{
+       int l = sizeof(tp->display);
+       if (total > 1 << 30) {
+               l -= snprintf(tp->display, l, ", %u.%2.2u GiB",
+                             (int)(total >> 30),
+                             (int)(total & ((1 << 30) - 1)) / 10737419);
+       } else if (total > 1 << 20) {
+               l -= snprintf(tp->display, l, ", %u.%2.2u MiB",
+                             (int)(total >> 20),
+                             ((int)(total & ((1 << 20) - 1)) * 100) >> 20);
+       } else if (total > 1 << 10) {
+               l -= snprintf(tp->display, l, ", %u.%2.2u KiB",
+                             (int)(total >> 10),
+                             ((int)(total & ((1 << 10) - 1)) * 100) >> 10);
+       } else {
+               l -= snprintf(tp->display, l, ", %u bytes", (int)total);
+       }
+       if (rate)
+               snprintf(tp->display + sizeof(tp->display) - l, l,
+                        " | %u KiB/s", rate);
+}
+
+void display_throughput(struct progress *progress, off_t total)
 {
        struct throughput *tp;
        struct timeval tv;
@@ -124,13 +148,13 @@ void display_throughput(struct progress *progress, unsigned long n)
 
        if (!tp) {
                progress->throughput = tp = calloc(1, sizeof(*tp));
-               if (tp)
+               if (tp) {
+                       tp->prev_total = tp->curr_total = total;
                        tp->prev_tv = tv;
+               }
                return;
        }
-
-       tp->total += n;
-       tp->count += n;
+       tp->curr_total = total;
 
        /*
         * We have x = bytes and y = microsecs.  We want z = KiB/s:
@@ -151,47 +175,29 @@ void display_throughput(struct progress *progress, unsigned long n)
        misecs += (int)(tv.tv_usec - tp->prev_tv.tv_usec) / 977;
 
        if (misecs > 512) {
-               int l = sizeof(tp->display);
+               unsigned int count, rate;
+
+               count = total - tp->prev_total;
+               tp->prev_total = total;
                tp->prev_tv = tv;
-               tp->avg_bytes += tp->count;
+               tp->avg_bytes += count;
                tp->avg_misecs += misecs;
-
-               if (tp->total > 1 << 30) {
-                       l -= snprintf(tp->display, l, ", %u.%2.2u GiB",
-                                     (int)(tp->total >> 30),
-                                     (int)(tp->total & ((1 << 30) - 1)) / 10737419);
-               } else if (tp->total > 1 << 20) {
-                       l -= snprintf(tp->display, l, ", %u.%2.2u MiB",
-                                     (int)(tp->total >> 20),
-                                     ((int)(tp->total & ((1 << 20) - 1))
-                                      * 100) >> 20);
-               } else if (tp->total > 1 << 10) {
-                       l -= snprintf(tp->display, l, ", %u.%2.2u KiB",
-                                     (int)(tp->total >> 10),
-                                     ((int)(tp->total & ((1 << 10) - 1))
-                                      * 100) >> 10);
-               } else {
-                       l -= snprintf(tp->display, l, ", %u bytes",
-                                     (int)tp->total);
-               }
-               snprintf(tp->display + sizeof(tp->display) - l, l,
-                        " | %lu KiB/s", tp->avg_bytes / tp->avg_misecs);
-
+               rate = tp->avg_bytes / tp->avg_misecs;
                tp->avg_bytes -= tp->last_bytes[tp->idx];
                tp->avg_misecs -= tp->last_misecs[tp->idx];
-               tp->last_bytes[tp->idx] = tp->count;
+               tp->last_bytes[tp->idx] = count;
                tp->last_misecs[tp->idx] = misecs;
                tp->idx = (tp->idx + 1) % TP_IDX_MAX;
-               tp->count = 0;
 
+               throughput_string(tp, total, rate);
                if (progress->last_value != -1 && progress_update)
-                       display(progress, progress->last_value, 0);
+                       display(progress, progress->last_value, NULL);
        }
 }
 
 int display_progress(struct progress *progress, unsigned n)
 {
-       return progress ? display(progress, n, 0) : 0;
+       return progress ? display(progress, n, NULL) : 0;
 }
 
 struct progress *start_progress_delay(const char *title, unsigned total,
@@ -220,6 +226,11 @@ struct progress *start_progress(const char *title, unsigned total)
 }
 
 void stop_progress(struct progress **p_progress)
+{
+       stop_progress_msg(p_progress, "done");
+}
+
+void stop_progress_msg(struct progress **p_progress, const char *msg)
 {
        struct progress *progress = *p_progress;
        if (!progress)
@@ -227,8 +238,16 @@ void stop_progress(struct progress **p_progress)
        *p_progress = NULL;
        if (progress->last_value != -1) {
                /* Force the last update */
+               char buf[strlen(msg) + 5];
+               struct throughput *tp = progress->throughput;
+               if (tp) {
+                       unsigned int rate = !tp->avg_misecs ? 0 :
+                                       tp->avg_bytes / tp->avg_misecs;
+                       throughput_string(tp, tp->curr_total, rate);
+               }
                progress_update = 1;
-               display(progress, progress->last_value, 1);
+               sprintf(buf, ", %s.\n", msg);
+               display(progress, progress->last_value, buf);
        }
        clear_progress_signal();
        free(progress->throughput);
index 61cb68dfa512bb3668d7e6060262041937aa82d3..611e4c4d42d8d1164add09f926ad5b2ce088db5e 100644 (file)
@@ -3,11 +3,12 @@
 
 struct progress;
 
-void display_throughput(struct progress *progress, unsigned long n);
+void display_throughput(struct progress *progress, off_t total);
 int display_progress(struct progress *progress, unsigned n);
 struct progress *start_progress(const char *title, unsigned total);
 struct progress *start_progress_delay(const char *title, unsigned total,
                                       unsigned percent_treshold, unsigned delay);
 void stop_progress(struct progress **progress);
+void stop_progress_msg(struct progress **progress, const char *msg);
 
 #endif
diff --git a/quote.c b/quote.c
index 919d0920abfc0bd2becbcc35fd065514b9651281..04557833a561b4613a511af8fb9f0fb18b36b2fa 100644 (file)
--- a/quote.c
+++ b/quote.c
@@ -131,7 +131,8 @@ static signed char const sq_lookup[256] = {
        /* 0x80 */ /* set to 0 */
 };
 
-static inline int sq_must_quote(char c) {
+static inline int sq_must_quote(char c)
+{
        return sq_lookup[(unsigned char)c] + quote_path_fully > 0;
 }
 
index 056b322fb0c83aeda378f548e13f84d4a65c1e29..7db55883d65fd28c2eaa291b5688273532988d88 100644 (file)
@@ -194,11 +194,12 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
 }
 
 int ie_match_stat(struct index_state *istate,
-                 struct cache_entry *ce, struct stat *st, int options)
+                 struct cache_entry *ce, struct stat *st,
+                 unsigned int options)
 {
        unsigned int changed;
-       int ignore_valid = options & 01;
-       int assume_racy_is_modified = options & 02;
+       int ignore_valid = options & CE_MATCH_IGNORE_VALID;
+       int assume_racy_is_modified = options & CE_MATCH_RACY_IS_DIRTY;
 
        /*
         * If it's marked as always valid in the index, it's
@@ -238,10 +239,11 @@ int ie_match_stat(struct index_state *istate,
 }
 
 int ie_modified(struct index_state *istate,
-               struct cache_entry *ce, struct stat *st, int really)
+               struct cache_entry *ce, struct stat *st, unsigned int options)
 {
        int changed, changed_fs;
-       changed = ie_match_stat(istate, ce, st, really);
+
+       changed = ie_match_stat(istate, ce, st, options);
        if (!changed)
                return 0;
        /*
@@ -387,6 +389,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose)
        int size, namelen, pos;
        struct stat st;
        struct cache_entry *ce;
+       unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY;
 
        if (lstat(path, &st))
                die("%s: unable to stat (%s)", path, strerror(errno));
@@ -421,7 +424,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose)
        pos = index_name_pos(istate, ce->name, namelen);
        if (0 <= pos &&
            !ce_stage(istate->cache[pos]) &&
-           !ie_modified(istate, istate->cache[pos], &st, 1)) {
+           !ie_match_stat(istate, istate->cache[pos], &st, ce_option)) {
                /* Nothing changed, really */
                free(ce);
                return 0;
@@ -783,11 +786,13 @@ int add_index_entry(struct index_state *istate, struct cache_entry *ce, int opti
  * to link up the stat cache details with the proper files.
  */
 static struct cache_entry *refresh_cache_ent(struct index_state *istate,
-                                            struct cache_entry *ce, int really, int *err)
+                                            struct cache_entry *ce,
+                                            unsigned int options, int *err)
 {
        struct stat st;
        struct cache_entry *updated;
        int changed, size;
+       int ignore_valid = options & CE_MATCH_IGNORE_VALID;
 
        if (lstat(ce->name, &st) < 0) {
                if (err)
@@ -795,16 +800,23 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
                return NULL;
        }
 
-       changed = ie_match_stat(istate, ce, &st, really);
+       changed = ie_match_stat(istate, ce, &st, options);
        if (!changed) {
-               if (really && assume_unchanged &&
+               /*
+                * The path is unchanged.  If we were told to ignore
+                * valid bit, then we did the actual stat check and
+                * found that the entry is unmodified.  If the entry
+                * is not marked VALID, this is the place to mark it
+                * valid again, under "assume unchanged" mode.
+                */
+               if (ignore_valid && assume_unchanged &&
                    !(ce->ce_flags & htons(CE_VALID)))
                        ; /* mark this one VALID again */
                else
                        return ce;
        }
 
-       if (ie_modified(istate, ce, &st, really)) {
+       if (ie_modified(istate, ce, &st, options)) {
                if (err)
                        *err = EINVAL;
                return NULL;
@@ -815,13 +827,14 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
        memcpy(updated, ce, size);
        fill_stat_cache_info(updated, &st);
 
-       /* In this case, if really is not set, we should leave
-        * CE_VALID bit alone.  Otherwise, paths marked with
-        * --no-assume-unchanged (i.e. things to be edited) will
-        * reacquire CE_VALID bit automatically, which is not
-        * really what we want.
+       /*
+        * If ignore_valid is not set, we should leave CE_VALID bit
+        * alone.  Otherwise, paths marked with --no-assume-unchanged
+        * (i.e. things to be edited) will reacquire CE_VALID bit
+        * automatically, which is not really what we want.
         */
-       if (!really && assume_unchanged && !(ce->ce_flags & htons(CE_VALID)))
+       if (!ignore_valid && assume_unchanged &&
+           !(ce->ce_flags & htons(CE_VALID)))
                updated->ce_flags &= ~htons(CE_VALID);
 
        return updated;
@@ -835,6 +848,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
        int allow_unmerged = (flags & REFRESH_UNMERGED) != 0;
        int quiet = (flags & REFRESH_QUIET) != 0;
        int not_new = (flags & REFRESH_IGNORE_MISSING) != 0;
+       unsigned int options = really ? CE_MATCH_IGNORE_VALID : 0;
 
        for (i = 0; i < istate->cache_nr; i++) {
                struct cache_entry *ce, *new;
@@ -856,7 +870,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
                if (pathspec && !match_pathspec(pathspec, ce->name, strlen(ce->name), 0, seen))
                        continue;
 
-               new = refresh_cache_ent(istate, ce, really, &cache_errno);
+               new = refresh_cache_ent(istate, ce, options, &cache_errno);
                if (new == ce)
                        continue;
                if (!new) {
diff --git a/refs.c b/refs.c
index aff02cd09d4e40b04f6764a6f6ab43240b736a08..ae532540cf2592aee2be7610ac811082c3a9b6be 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -580,18 +580,6 @@ int for_each_remote_ref(each_ref_fn fn, void *cb_data)
        return do_for_each_ref("refs/remotes/", fn, 13, cb_data);
 }
 
-/* NEEDSWORK: This is only used by ssh-upload and it should go; the
- * caller should do resolve_ref or read_ref like everybody else.  Or
- * maybe everybody else should use get_ref_sha1() instead of doing
- * read_ref().
- */
-int get_ref_sha1(const char *ref, unsigned char *sha1)
-{
-       if (check_ref_format(ref))
-               return -1;
-       return read_ref(mkpath("refs/%s", ref), sha1);
-}
-
 /*
  * Make sure "ref" is something reasonable to have under ".git/refs/";
  * We do not like it if:
diff --git a/refs.h b/refs.h
index 6eb98a4caf150776c26fb04699133b1a976d0122..9dc8aa01d181dbdbf1c8f643a1bd7de1d311ffa3 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -26,9 +26,6 @@ extern int for_each_remote_ref(each_ref_fn, void *);
 
 extern int peel_ref(const char *, unsigned char *);
 
-/** Reads the refs file specified into sha1 **/
-extern int get_ref_sha1(const char *ref, unsigned char *sha1);
-
 /** Locks a "refs/" ref returning the lock on success and NULL on failure. **/
 extern struct ref_lock *lock_ref_sha1(const char *ref, const unsigned char *old_sha1);
 
index d99a6c4ea7c776bec717c9952f77db7fa9a69c21..476d00c2182e3af82a0cfe495c61c9df1eb44d26 100644 (file)
@@ -41,7 +41,7 @@ int start_command(struct child_process *cmd)
                cmd->close_out = 1;
        }
 
-       need_err = cmd->err < 0;
+       need_err = !cmd->no_stderr && cmd->err < 0;
        if (need_err) {
                if (pipe(fderr) < 0) {
                        if (need_in)
@@ -87,7 +87,9 @@ int start_command(struct child_process *cmd)
                        close(cmd->out);
                }
 
-               if (need_err) {
+               if (cmd->no_stderr)
+                       dup_devnull(2);
+               else if (need_err) {
                        dup2(fderr[1], 2);
                        close_pair(fderr);
                }
index 94e1e9d516887d818f99f8f6d6b3ded3f3be6d6f..1fc781d7668468f9e74bd430b7569dc040440ba8 100644 (file)
@@ -23,6 +23,7 @@ struct child_process {
        unsigned close_out:1;
        unsigned no_stdin:1;
        unsigned no_stdout:1;
+       unsigned no_stderr:1;
        unsigned git_cmd:1; /* if this is to be git sub-command */
        unsigned stdout_to_stderr:1;
 };
diff --git a/setup.c b/setup.c
index 145eca50f41d811c4c8fcb21ed2604e6b2971aba..43cd3f94ea31a7a2a8f8a07cbb67598bb1e52c39 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -206,6 +206,22 @@ static const char *set_work_tree(const char *dir)
        return NULL;
 }
 
+void setup_work_tree(void)
+{
+       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;
+}
+
 /*
  * We cannot decide in this function whether we are in the work tree or
  * not, since the config can only be read _after_ this function was called.
index ab8a1e990db39155efc624ca99e85c1cf8eaefa9..756bbc28d71448781294151cbacd30f68b2bb97b 100644 (file)
  * stream, aka "verbose").  A message over band #3 is a signal that
  * the remote died unexpectedly.  A flush() concludes the stream.
  */
+
+#define PREFIX "remote:"
+#define SUFFIX "\033[K"  /* change to "        " if ANSI sequences don't work */
+
 int recv_sideband(const char *me, int in_stream, int out, int err)
 {
-       char buf[7 + LARGE_PACKET_MAX + 1];
-       strcpy(buf, "remote:");
+       unsigned pf = strlen(PREFIX);
+       unsigned sf = strlen(SUFFIX);
+       char buf[pf + LARGE_PACKET_MAX + sf + 1];
+       memcpy(buf, PREFIX, pf);
        while (1) {
                int band, len;
-               len = packet_read_line(in_stream, buf+7, LARGE_PACKET_MAX);
+               len = packet_read_line(in_stream, buf + pf, LARGE_PACKET_MAX);
                if (len == 0)
                        break;
                if (len < 1) {
@@ -25,35 +31,52 @@ int recv_sideband(const char *me, int in_stream, int out, int err)
                        safe_write(err, buf, len);
                        return SIDEBAND_PROTOCOL_ERROR;
                }
-               band = buf[7] & 0xff;
+               band = buf[pf] & 0xff;
                len--;
                switch (band) {
                case 3:
-                       buf[7] = ' ';
-                       buf[8+len] = '\n';
-                       safe_write(err, buf, 8+len+1);
+                       buf[pf] = ' ';
+                       buf[pf+1+len] = '\n';
+                       safe_write(err, buf, pf+1+len+1);
                        return SIDEBAND_REMOTE_ERROR;
                case 2:
-                       buf[7] = ' ';
-                       len += 8;
+                       buf[pf] = ' ';
+                       len += pf+1;
                        while (1) {
-                               int brk = 8;
+                               int brk = pf+1;
+
+                               /* Break the buffer into separate lines. */
                                while (brk < len) {
                                        brk++;
                                        if (buf[brk-1] == '\n' ||
                                            buf[brk-1] == '\r')
                                                break;
                                }
-                               safe_write(err, buf, brk);
+
+                               /*
+                                * Let's insert a suffix to clear the end
+                                * of the screen line, but only if current
+                                * line data actually contains something.
+                                */
+                               if (brk > pf+1 + 1) {
+                                       char save[sf];
+                                       memcpy(save, buf + brk, sf);
+                                       buf[brk + sf - 1] = buf[brk - 1];
+                                       memcpy(buf + brk - 1, SUFFIX, sf);
+                                       safe_write(err, buf, brk + sf);
+                                       memcpy(buf + brk, save, sf);
+                               } else
+                                       safe_write(err, buf, brk);
+
                                if (brk < len) {
-                                       memmove(buf + 8, buf + brk, len - brk);
-                                       len = len - brk + 8;
+                                       memmove(buf + pf+1, buf + brk, len - brk);
+                                       len = len - brk + pf+1;
                                } else
                                        break;
                        }
                        continue;
                case 1:
-                       safe_write(out, buf+8, len);
+                       safe_write(out, buf + pf+1, len);
                        continue;
                default:
                        len = sprintf(buf,
index f4201e160de2ccb9f2d9adef695c73a124e676d5..b9b194b3200e950cfdb3c696d92ece0657e9d344 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -106,17 +106,25 @@ void strbuf_add(struct strbuf *sb, const void *data, size_t len)
        strbuf_setlen(sb, sb->len + len);
 }
 
+void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len)
+{
+       strbuf_grow(sb, len);
+       memcpy(sb->buf + sb->len, sb->buf + pos, len);
+       strbuf_setlen(sb, sb->len + len);
+}
+
 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);
@@ -129,6 +137,30 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
        strbuf_setlen(sb, sb->len + len);
 }
 
+void strbuf_expand(struct strbuf *sb, const char *format,
+                   const char **placeholders, expand_fn_t fn, void *context)
+{
+       for (;;) {
+               const char *percent, **p;
+
+               percent = strchrnul(format, '%');
+               strbuf_add(sb, format, percent - format);
+               if (!*percent)
+                       break;
+               format = percent + 1;
+
+               for (p = placeholders; *p; p++) {
+                       if (!prefixcmp(format, *p))
+                               break;
+               }
+               if (*p) {
+                       fn(sb, *p, context);
+                       format += strlen(*p);
+               } else
+                       strbuf_addch(sb, '%');
+       }
+}
+
 size_t strbuf_fread(struct strbuf *sb, size_t size, FILE *f)
 {
        size_t res;
index cd7f295b65237aaa1f4e4031482af43cbe9d9115..13919123dc5261e7b8e4a4fdfc696f2355482b6c 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
@@ -101,6 +101,10 @@ static inline void strbuf_addstr(struct strbuf *sb, const char *s) {
 static inline void strbuf_addbuf(struct strbuf *sb, struct strbuf *sb2) {
        strbuf_add(sb, sb2->buf, sb2->len);
 }
+extern void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len);
+
+typedef void (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context);
+extern void strbuf_expand(struct strbuf *sb, const char *format, const char **placeholders, expand_fn_t fn, void *context);
 
 __attribute__((format(printf,2,3)))
 extern void strbuf_addf(struct strbuf *sb, const char *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 ce045b2a57c13de3ef8a01f806e3472d18bdef37..a90824ba8ab0e6df5c4afad528e30d118e23455c 100755 (executable)
@@ -205,7 +205,7 @@ test_expect_success \
         echo $h_TEST >.git/MERGE_HEAD &&
         GIT_AUTHOR_DATE="2005-05-26 23:45" \
         GIT_COMMITTER_DATE="2005-05-26 23:45" git-commit -F M &&
-        h_MERGED=$(git rev-parse --verify HEAD)
+        h_MERGED=$(git rev-parse --verify HEAD) &&
         rm -f M'
 
 cat >expect <<EOF
index eb1ced3c371ecaeab9d0dc14be888bf7df110483..24f892f79386478fd5f1162654cb9b72d940bbe4 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-test_description='git add -u with path limiting
+test_description='git add -u
 
 This test creates a working tree state with three files:
 
@@ -9,7 +9,10 @@ This test creates a working tree state with three files:
   dir/other (untracked)
 
 and issues a git add -u with path limiting on "dir" to add
-only the updates to dir/sub.'
+only the updates to dir/sub.
+
+Also tested are "git add -u" without limiting, and "git add -u"
+without contents changes.'
 
 . ./test-lib.sh
 
@@ -85,4 +88,27 @@ test_expect_success 'replace a file with a symlink' '
 
 '
 
+test_expect_success 'add everything changed' '
+
+       git add -u &&
+       test -z "$(git diff-files)"
+
+'
+
+test_expect_success 'touch and then add -u' '
+
+       touch check &&
+       git add -u &&
+       test -z "$(git diff-files)"
+
+'
+
+test_expect_success 'touch and then add explicitly' '
+
+       touch check &&
+       git add check &&
+       test -z "$(git diff-files)"
+
+'
+
 test_done
index 0779aaa9aba16f0f8502505b4df5cc49cfe8af82..7b7d07269ae35f56dd02a223f350ae0da97bae85 100755 (executable)
@@ -48,9 +48,14 @@ test_expect_success 'reference merge' '
        git merge -s recursive "reference merge" HEAD master
 '
 
+PRE_REBASE=$(git rev-parse test-rebase)
 test_expect_success rebase '
        git checkout test-rebase &&
-       git rebase --merge master
+       GIT_TRACE=1 git rebase --merge master
+'
+
+test_expect_success 'test-rebase@{1} is pre rebase' '
+       test $PRE_REBASE = $(git rev-parse test-rebase@{1})
 '
 
 test_expect_success 'merge and rebase should match' '
index eab053c3e0e1cbe82bc7824d43109ba56acdb54d..2ee5a00ea794e31946ee3228bc66ecc8e7d3b38f 100755 (executable)
@@ -39,6 +39,19 @@ test_expect_success 'rebase --skip with am -3' '
        git reset --hard HEAD &&
        git rebase --skip
        '
+
+test_expect_success 'rebase moves back to skip-reference' '
+       test refs/heads/skip-reference = $(git symbolic-ref HEAD) &&
+       git branch post-rebase &&
+       git reset --hard pre-rebase &&
+       ! git rebase master &&
+       echo "hello" > hello &&
+       git add hello &&
+       git rebase --continue &&
+       test refs/heads/skip-reference = $(git symbolic-ref HEAD) &&
+       git reset --hard post-rebase
+'
+
 test_expect_success 'checkout skip-merge' 'git checkout -f skip-merge'
 
 test_expect_failure 'rebase with --merge' 'git rebase --merge master'
@@ -51,6 +64,10 @@ test_expect_success 'rebase --skip with --merge' '
 test_expect_success 'merge and reference trees equal' \
        'test -z "`git diff-tree skip-merge skip-reference`"'
 
+test_expect_success 'moved back to branch correctly' '
+       test refs/heads/skip-merge = $(git symbolic-ref HEAD)
+'
+
 test_debug 'gitk --all & sleep 1'
 
 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' '
index a328bf57eb67fd96a88020f02948d380ec699496..287e058e3766df129dcde82aeddecac59b46e2a6 100755 (executable)
@@ -104,9 +104,33 @@ test_expect_success 'add ignored ones with -f' '
        git ls-files --error-unmatch d.ig/d.if d.ig/d.ig
 '
 
+test_expect_success 'add ignored ones with -f' '
+       rm -f .git/index &&
+       git add -f d.?? &&
+       git ls-files --error-unmatch d.ig/d.if d.ig/d.ig
+'
+
+test_expect_success '.gitignore with subdirectory' '
+
+       rm -f .git/index &&
+       mkdir -p sub/dir &&
+       echo "!dir/a.*" >sub/.gitignore &&
+       >sub/a.ig &&
+       >sub/dir/a.ig &&
+       git add sub/dir &&
+       git ls-files --error-unmatch sub/dir/a.ig &&
+       rm -f .git/index &&
+       (
+               cd sub/dir &&
+               git add .
+       ) &&
+       git ls-files --error-unmatch sub/dir/a.ig
+'
+
 mkdir 1 1/2 1/3
 touch 1/2/a 1/3/b 1/2/c
 test_expect_success 'check correct prefix detection' '
+       rm -f .git/index &&
        git add 1/2/a 1/3/b 1/2/c
 '
 
diff --git a/t/t4021-format-patch-numbered.sh b/t/t4021-format-patch-numbered.sh
new file mode 100755 (executable)
index 0000000..43d64bb
--- /dev/null
@@ -0,0 +1,106 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Brian C Gernhardt
+#
+
+test_description='Format-patch numbering options'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+
+       echo A > file &&
+       git add file &&
+       git commit -m First &&
+
+       echo B >> file &&
+       git commit -a -m Second &&
+
+       echo C >> file &&
+       git commit -a -m Third
+
+'
+
+# Each of these gets used multiple times.
+
+test_num_no_numbered() {
+       cnt=$(grep "^Subject: \[PATCH\]" $1 | wc -l) &&
+       test $cnt = $2
+}
+
+test_single_no_numbered() {
+       test_num_no_numbered $1 1
+}
+
+test_no_numbered() {
+       test_num_no_numbered $1 2
+}
+
+test_single_numbered() {
+       grep "^Subject: \[PATCH 1/1\]" $1
+}
+
+test_numbered() {
+       grep "^Subject: \[PATCH 1/2\]" $1 &&
+       grep "^Subject: \[PATCH 2/2\]" $1
+}
+
+test_expect_success 'Default: no numbered' '
+
+       git format-patch --stdout HEAD~2 >patch0 &&
+       test_no_numbered patch0
+
+'
+
+test_expect_success 'Use --numbered' '
+
+       git format-patch --numbered --stdout HEAD~2 >patch1 &&
+       test_numbered patch1
+
+'
+
+test_expect_success 'format.numbered = true' '
+
+       git config format.numbered true &&
+       git format-patch --stdout HEAD~2 >patch2 &&
+       test_numbered patch2
+
+'
+
+test_expect_success 'format.numbered && single patch' '
+
+       git format-patch --stdout HEAD^ > patch3 &&
+       test_single_numbered patch3
+
+'
+
+test_expect_success 'format.numbered && --no-numbered' '
+
+       git format-patch --no-numbered --stdout HEAD~2 >patch4 &&
+       test_no_numbered patch4
+
+'
+
+test_expect_success 'format.numbered = auto' '
+
+       git config format.numbered auto
+       git format-patch --stdout HEAD~2 > patch5 &&
+       test_numbered patch5
+
+'
+
+test_expect_success 'format.numbered = auto && single patch' '
+
+       git format-patch --stdout HEAD^ > patch6 &&
+       test_single_no_numbered patch6
+
+'
+
+test_expect_success 'format.numbered = auto && --no-numbered' '
+
+       git format-patch --no-numbered --stdout HEAD~2 > patch7 &&
+       test_no_numbered patch7
+
+'
+
+test_done
index b4760f2dc0bb690429b358cefde911db1fb26e9a..16eadd6b68664884836976aafb6dcbb582603c09 100755 (executable)
@@ -86,4 +86,37 @@ test_expect_success 'quickfetch should not leave a corrupted repository' '
 
 '
 
+test_expect_success 'quickfetch should not copy from alternate' '
+
+       (
+               mkdir quickclone &&
+               cd quickclone &&
+               git init-db &&
+               (cd ../.git/objects && pwd) >.git/objects/info/alternates &&
+               git remote add origin .. &&
+               git fetch -k -k
+       ) &&
+       obj_cnt=$( (
+               cd quickclone &&
+               git count-objects | sed -e "s/ *objects,.*//"
+       ) ) &&
+       pck_cnt=$( (
+               cd quickclone &&
+               git count-objects -v | sed -n -e "/packs:/{
+                               s/packs://
+                               p
+                               q
+                       }"
+       ) ) &&
+       origin_master=$( (
+               cd quickclone &&
+               git rev-parse origin/master
+       ) ) &&
+       echo "loose objects: $obj_cnt, packfiles: $pck_cnt" &&
+       test $obj_cnt -eq 0 &&
+       test $pck_cnt -eq 0 &&
+       test z$origin_master = z$(git rev-parse master)
+
+'
+
 test_done
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 0d07bc39c745ade65370dde35f43f16a37231179..5f7e388d7add06b8392997037a86c4d0f8524ceb 100755 (executable)
@@ -1004,4 +1004,30 @@ test_expect_failure \
        'verify signed tag fails when public key is not present' \
        'git-tag -v signed-tag'
 
+test_expect_failure \
+       'git-tag -a fails if tag annotation is empty' '
+       GIT_EDITOR=cat git tag -a initial-comment
+'
+
+test_expect_success \
+       'message in editor has initial comment' '
+       GIT_EDITOR=cat git tag -a initial-comment > actual
+       # check the first line --- should be empty
+       first=$(sed -e 1q <actual) &&
+       test -z "$first" &&
+       # remove commented lines from the remainder -- should be empty
+       rest=$(sed -e 1d -e '/^#/d' <actual) &&
+       test -z "$rest"
+'
+
+get_tag_header reuse $commit commit $time >expect
+echo "An annotation to be reused" >> expect
+test_expect_success \
+       'overwriting an annoted tag should use its previous body' '
+       git tag -a -m "An annotation to be reused" reuse &&
+       GIT_EDITOR=true git tag -f -a reuse &&
+       get_tag_msg reuse >actual &&
+       git diff expect actual
+'
+
 test_done
index 01cc0c02b1c20afef664110389b88af702c52ef7..44228b5ac12f5df9d6def93dc74e3687ba2d8e73 100755 (executable)
@@ -15,7 +15,6 @@ do
 done
 unset vi
 mv e-vi.sh vi
-PATH=".:$PATH"
 unset EDITOR VISUAL GIT_EDITOR
 
 test_expect_success setup '
@@ -61,7 +60,7 @@ do
                ;;
        esac
        test_expect_success "Using $i" '
-               git commit --amend &&
+               git --exec-path=. commit --amend &&
                git show -s --pretty=oneline |
                sed -e "s/^[0-9a-f]* //" >actual &&
                diff actual expect
@@ -83,7 +82,7 @@ do
                ;;
        esac
        test_expect_success "Using $i (override)" '
-               git commit --amend &&
+               git --exec-path=. commit --amend &&
                git show -s --pretty=oneline |
                sed -e "s/^[0-9a-f]* //" >actual &&
                diff actual expect
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 ed2e9ee3c6fea4767f0aa288dca02825569abedf..55558aba8b862b93cb8ad97a681a4749bae3b3e1 100755 (executable)
@@ -77,7 +77,7 @@ test_expect_success "checkout with dirty tree without -m" '
 test_expect_success "checkout -m with dirty tree" '
 
        git checkout -f master &&
-       git clean &&
+       git clean -f &&
 
        fill 0 1 2 3 4 5 6 7 8 >one &&
        git checkout -m side &&
@@ -99,7 +99,7 @@ test_expect_success "checkout -m with dirty tree" '
 
 test_expect_success "checkout -m with dirty tree, renamed" '
 
-       git checkout -f master && git clean &&
+       git checkout -f master && git clean -f &&
 
        fill 1 2 3 4 5 7 8 >one &&
        if git checkout renamer
@@ -121,7 +121,7 @@ test_expect_success "checkout -m with dirty tree, renamed" '
 
 test_expect_success 'checkout -m with merge conflict' '
 
-       git checkout -f master && git clean &&
+       git checkout -f master && git clean -f &&
 
        fill 1 T 3 4 5 6 S 8 >one &&
        if git checkout renamer
@@ -144,7 +144,7 @@ test_expect_success 'checkout -m with merge conflict' '
 
 test_expect_success 'checkout to detach HEAD' '
 
-       git checkout -f renamer && git clean &&
+       git checkout -f renamer && git clean -f &&
        git checkout renamer^ &&
        H=$(git rev-parse --verify HEAD) &&
        M=$(git show-ref -s --verify refs/heads/master) &&
@@ -160,7 +160,7 @@ test_expect_success 'checkout to detach HEAD' '
 
 test_expect_success 'checkout to detach HEAD with branchname^' '
 
-       git checkout -f master && git clean &&
+       git checkout -f master && git clean -f &&
        git checkout renamer^ &&
        H=$(git rev-parse --verify HEAD) &&
        M=$(git show-ref -s --verify refs/heads/master) &&
@@ -176,7 +176,7 @@ test_expect_success 'checkout to detach HEAD with branchname^' '
 
 test_expect_success 'checkout to detach HEAD with HEAD^0' '
 
-       git checkout -f master && git clean &&
+       git checkout -f master && git clean -f &&
        git checkout HEAD^0 &&
        H=$(git rev-parse --verify HEAD) &&
        M=$(git show-ref -s --verify refs/heads/master) &&
index 23274361877e6d09eec51793cf6c2253541622f8..f013c176ed910d278cbb886004429869f288ebc7 100755 (executable)
@@ -7,6 +7,8 @@ test_description='git-clean basic tests'
 
 . ./test-lib.sh
 
+git config clean.requireForce no
+
 test_expect_success 'setup' '
 
        mkdir -p src &&
@@ -244,6 +246,13 @@ test_expect_success 'git-clean -d -X' '
 
 '
 
+test_expect_success 'clean.requireForce defaults to true' '
+
+       git config --unset clean.requireForce &&
+       ! git-clean
+
+'
+
 test_expect_success 'clean.requireForce' '
 
        git config clean.requireForce true &&
@@ -282,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 abbf54ba63693bbb3e839786bf97284c22912333..cf389b81da041e6bcbc7d20cd367b4274001353f 100755 (executable)
@@ -93,4 +93,36 @@ test_expect_success 'commit message from file should override template' '
        commit_msg_is "standard input msg"
 '
 
+test_expect_success 'using alternate GIT_INDEX_FILE (1)' '
+
+       cp .git/index saved-index &&
+       (
+               echo some new content >file &&
+               GIT_INDEX_FILE=.git/another_index &&
+               export GIT_INDEX_FILE &&
+               git add file &&
+               git commit -m "commit using another index" &&
+               git diff-index --exit-code HEAD &&
+               git diff-files --exit-code
+       ) &&
+       cmp .git/index saved-index >/dev/null
+
+'
+
+test_expect_success 'using alternate GIT_INDEX_FILE (2)' '
+
+       cp .git/index saved-index &&
+       (
+               rm -f .git/no-such-index &&
+               GIT_INDEX_FILE=.git/no-such-index &&
+               export GIT_INDEX_FILE &&
+               git commit -m "commit using nonexistent index" &&
+               test -z "$(git ls-files)" &&
+               test -z "$(git ls-tree HEAD)"
+
+       ) &&
+       cmp .git/index saved-index >/dev/null
+
+'
+
 test_done
index b151b51a3420fdba921da16979ec4a480b61a973..9dba104b1f8bf9125f1a947a2fd115b684a94095 100644 (file)
@@ -33,6 +33,16 @@ test_expect_failure \
        "invalid options 2" \
        "git-commit -C HEAD -m illegal"
 
+test_expect_failure \
+       "using paths with -a" \
+       "echo King of the bongo >file &&
+       git-commit -m foo -a file"
+
+test_expect_failure \
+       "using paths with --interactive" \
+       "echo bong-o-bong >file &&
+       echo 7 | git-commit -m foo --interactive file"
+
 test_expect_failure \
        "using invalid commit with -C" \
        "git-commit -C bogus"
@@ -163,4 +173,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 3c83127a0e862dd89837755103a97ed967c80e0b..d7a704754ea13f17c098e56a7b068cb4f44c1fd0 100755 (executable)
@@ -48,7 +48,7 @@ EOF
        printf "\r\n" > empty_crlf
        a_empty_crlf=`git-hash-object -w empty_crlf`
 
-       svn import -m 'import for git-svn' . "$svnrepo" >/dev/null
+       svn import --no-auto-props -m 'import for git-svn' . "$svnrepo" >/dev/null
 cd ..
 
 rm -rf import
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
index 0d4e6b3f040a2cbbcfa16209c3e486427af75f55..902ed4145de5f41f3b0522fac464594e9f6e792b 100755 (executable)
@@ -30,6 +30,12 @@ test_expect_success 'setup repository and import' "
        git reset --hard trunk &&
        echo aye >> README &&
        git commit -a -m aye &&
+       git svn dcommit &&
+       git reset --hard b &&
+       echo spy >> README &&
+       git commit -a -m spy &&
+       echo try >> README &&
+       git commit -a -m try &&
        git svn dcommit
        "
 
@@ -45,4 +51,78 @@ test_expect_success 'run log against a from trunk' "
        git svn log -r3 a | grep ^r3
        "
 
+printf 'r1 \nr2 \nr4 \n' > expected-range-r1-r2-r4
+
+test_expect_success 'test ascending revision range' "
+       git reset --hard trunk &&
+       git svn log -r 1:4 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r1-r2-r4 -
+       "
+
+printf 'r4 \nr2 \nr1 \n' > expected-range-r4-r2-r1
+
+test_expect_success 'test descending revision range' "
+       git reset --hard trunk &&
+       git svn log -r 4:1 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4-r2-r1 -
+       "
+
+printf 'r1 \nr2 \n' > expected-range-r1-r2
+
+test_expect_success 'test ascending revision range with unreachable revision' "
+       git reset --hard trunk &&
+       git svn log -r 1:3 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r1-r2 -
+       "
+
+printf 'r2 \nr1 \n' > expected-range-r2-r1
+
+test_expect_success 'test descending revision range with unreachable revision' "
+       git reset --hard trunk &&
+       git svn log -r 3:1 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r2-r1 -
+       "
+
+printf 'r2 \n' > expected-range-r2
+
+test_expect_success 'test ascending revision range with unreachable upper boundary revision and 1 commit' "
+       git reset --hard trunk &&
+       git svn log -r 2:3 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r2 -
+       "
+
+test_expect_success 'test descending revision range with unreachable upper boundary revision and 1 commit' "
+       git reset --hard trunk &&
+       git svn log -r 3:2 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r2 -
+       "
+
+printf 'r4 \n' > expected-range-r4
+
+test_expect_success 'test ascending revision range with unreachable lower boundary revision and 1 commit' "
+       git reset --hard trunk &&
+       git svn log -r 3:4 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4 -
+       "
+
+test_expect_success 'test descending revision range with unreachable lower boundary revision and 1 commit' "
+       git reset --hard trunk &&
+       git svn log -r 4:3 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4 -
+       "
+
+printf -- '------------------------------------------------------------------------\n' > expected-separator
+
+test_expect_success 'test ascending revision range with unreachable boundary revisions and no commits' "
+       git reset --hard trunk &&
+       git svn log -r 5:6 | diff -u expected-separator -
+       "
+
+test_expect_success 'test descending revision range with unreachable boundary revisions and no commits' "
+       git reset --hard trunk &&
+       git svn log -r 6:5 | diff -u expected-separator -
+       "
+
+test_expect_success 'test ascending revision range with unreachable boundary revisions and 1 commit' "
+       git reset --hard trunk &&
+       git svn log -r 3:5 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4 -
+       "
+
+test_expect_success 'test descending revision range with unreachable boundary revisions and 1 commit' "
+       git reset --hard trunk &&
+       git svn log -r 5:3 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4 -
+       "
+
 test_done
diff --git a/t/t9117-git-svn-init-clone.sh b/t/t9117-git-svn-init-clone.sh
new file mode 100755 (executable)
index 0000000..d482b40
--- /dev/null
@@ -0,0 +1,55 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Eric Wong
+#
+
+test_description='git-svn init/clone tests'
+
+. ./lib-git-svn.sh
+
+# setup, run inside tmp so we don't have any conflicts with $svnrepo
+set -e
+rm -r .git
+mkdir tmp
+cd tmp
+
+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/project &&
+       rm -rf project
+       "
+
+test_expect_success 'basic clone' "
+       test ! -d trunk &&
+       git svn clone $svnrepo/project/trunk &&
+       test -d trunk/.git/svn &&
+       test -e trunk/foo &&
+       rm -rf trunk
+       "
+
+test_expect_success 'clone to target directory' "
+       test ! -d target &&
+       git svn clone $svnrepo/project/trunk target &&
+       test -d target/.git/svn &&
+       test -e target/foo &&
+       rm -rf target
+       "
+
+test_expect_success 'clone with --stdlayout' "
+       test ! -d project &&
+       git svn clone -s $svnrepo/project &&
+       test -d project/.git/svn &&
+       test -e project/foo &&
+       rm -rf project
+       "
+
+test_expect_success 'clone to target directory with --stdlayout' "
+       test ! -d target &&
+       git svn clone -s $svnrepo/project target &&
+       test -d target/.git/svn &&
+       test -e target/foo &&
+       rm -rf target
+       "
+
+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 d8c76264beaf198f1f3558ca8429349c8eab9ead..bd93dd1977b2a19e0dcded9c31ec37e78b331af6 100644 (file)
 # hooks.allowunannotated
 #   This boolean sets whether unannotated tags will be allowed into the
 #   repository.  By default they won't be.
+# hooks.allowdeletetag
+#   This boolean sets whether deleting tags will be allowed in the
+#   repository.  By default they won't be.
+# hooks.allowdeletebranch
+#   This boolean sets whether deleting branches will be allowed in the
+#   repository.  By default they won't be.
 #
 
 # --- Command line
@@ -32,18 +38,20 @@ fi
 
 # --- Config
 allowunannotated=$(git-repo-config --bool hooks.allowunannotated)
+allowdeletebranch=$(git-repo-config --bool hooks.allowdeletebranch)
+allowdeletetag=$(git-repo-config --bool hooks.allowdeletetag)
 
 # check for no description
-projectdesc=$(sed -e '1p' "$GIT_DIR/description")
-if [ -z "$projectdesc" -o "$projectdesc" = "Unnamed repository; edit this file to name it for gitweb" ]; then
+projectdesc=$(sed -e '1q' "$GIT_DIR/description")
+if [ -z "$projectdesc" -o "$projectdesc" = "Unnamed repository; edit this file to name it for gitweb." ]; then
        echo "*** Project description file hasn't been set" >&2
        exit 1
 fi
 
 # --- Check types
-# if $newrev is 0000...0000, it's a commit to delete a branch
+# if $newrev is 0000...0000, it's a commit to delete a ref.
 if [ "$newrev" = "0000000000000000000000000000000000000000" ]; then
-       newrev_type=commit
+       newrev_type=delete
 else
        newrev_type=$(git-cat-file -t $newrev)
 fi
@@ -58,15 +66,36 @@ case "$refname","$newrev_type" in
                        exit 1
                fi
                ;;
+       refs/tags/*,delete)
+               # delete tag
+               if [ "$allowdeletetag" != "true" ]; then
+                       echo "*** Deleting a tag is not allowed in this repository" >&2
+                       exit 1
+               fi
+               ;;
        refs/tags/*,tag)
                # annotated tag
                ;;
        refs/heads/*,commit)
                # branch
                ;;
+       refs/heads/*,delete)
+               # delete branch
+               if [ "$allowdeletebranch" != "true" ]; then
+                       echo "*** Deleting a branch is not allowed in this repository" >&2
+                       exit 1
+               fi
+               ;;
        refs/remotes/*,commit)
                # tracking branch
                ;;
+       refs/remotes/*,delete)
+               # delete tracking branch
+               if [ "$allowdeletebranch" != "true" ]; then
+                       echo "*** Deleting a tracking branch is not allowed in this repository" >&2
+                       exit 1
+               fi
+               ;;
        *)
                # Anything else (is there anything else?)
                echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
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 d44fe7cee7bd8f0e524eff6b516cd2c8b8c919e2..e8a2608372de06ef3f77d9a450776e3095057c9f 100644 (file)
@@ -380,12 +380,13 @@ static int disconnect_walker(struct transport *transport)
 }
 
 #ifndef NO_CURL
-static int curl_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) {
+static int curl_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags)
+{
        const char **argv;
        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)
@@ -394,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++;
@@ -646,14 +649,15 @@ static int fetch_refs_via_pack(struct transport *transport,
        return 0;
 }
 
-static int git_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags) {
+static int git_transport_push(struct transport *transport, int refspec_nr, const char **refspec, int flags)
+{
        struct git_transport_data *data = transport->data;
        const char **argv;
        char *rem;
        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)
@@ -662,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 c527d7d049155d1808e0bf69aba42d49cea7b68f..aea16adde846b404900555f5f0dd6d87daea8bbf 100644 (file)
@@ -404,7 +404,7 @@ static void verify_uptodate(struct cache_entry *ce,
                return;
 
        if (!lstat(ce->name, &st)) {
-               unsigned changed = ce_match_stat(ce, &st, 1);
+               unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);
                if (!changed)
                        return;
                /*
@@ -925,7 +925,7 @@ int oneway_merge(struct cache_entry **src,
                if (o->reset) {
                        struct stat st;
                        if (lstat(old->name, &st) ||
-                           ce_match_stat(old, &st, 1))
+                           ce_match_stat(old, &st, CE_MATCH_IGNORE_VALID))
                                old->ce_flags |= htons(CE_UPDATE);
                }
                return keep_entry(old, o);
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)
diff --git a/utf8.c b/utf8.c
index 4efef6faf7c71f3201935f81611806af084c45d4..9efcdb9c09970127ebe37923879274b95efd526c 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -11,7 +11,8 @@ struct interval {
 };
 
 /* auxiliary function for binary search in interval table */
-static int bisearch(ucs_char_t ucs, const struct interval *table, int max) {
+static int bisearch(ucs_char_t ucs, const struct interval *table, int max)
+{
        int min = 0;
        int mid;
 
@@ -283,7 +284,6 @@ int print_wrapped_text(const char *text, int indent, int indent2, int width)
                        text++;
                }
        }
-       return w;
 }
 
 int is_encoding_utf8(const char *name)
index 03b5ec4488cb25bca2f9d96493e874d7c12d3636..9a6ef4a89ae659855ae0d2fa3006daf080190ed4 100644 (file)
@@ -22,7 +22,6 @@ static const char use_add_rm_msg[] =
 "use \"git add/rm <file>...\" to update what will be committed";
 static const char use_add_to_include_msg[] =
 "use \"git add <file>...\" to include in what will be committed";
-static const char *excludes_file;
 
 static int parse_status_slot(const char *var, int offset)
 {
@@ -251,22 +250,16 @@ static void wt_status_print_changed(struct wt_status *s)
 static void wt_status_print_untracked(struct wt_status *s)
 {
        struct dir_struct dir;
-       const char *x;
        int i;
        int shown_header = 0;
 
        memset(&dir, 0, sizeof(dir));
 
-       dir.exclude_per_dir = ".gitignore";
        if (!s->untracked) {
                dir.show_other_directories = 1;
                dir.hide_empty_directories = 1;
        }
-       x = git_path("info/exclude");
-       if (file_exists(x))
-               add_excludes_from_file(&dir, x);
-       if (excludes_file && file_exists(excludes_file))
-               add_excludes_from_file(&dir, excludes_file);
+       setup_standard_excludes(&dir);
 
        read_directory(&dir, ".", "", 0, NULL);
        for(i = 0; i < dir.nr; i++) {
@@ -364,11 +357,5 @@ int git_status_config(const char *k, const char *v)
                int slot = parse_status_slot(k, 13);
                color_parse(v, k, wt_status_colors[slot]);
        }
-       if (!strcmp(k, "core.excludesfile")) {
-               if (!v)
-                       die("core.excludesfile without value");
-               excludes_file = xstrdup(v);
-               return 0;
-       }
        return git_default_config(k, v);
 }
index 5cb7171a8f528881c6171defa5b102e87d7aa522..1bad8462fb32cffdc9ff20a278d513e7a444b257 100644 (file)
@@ -257,8 +257,6 @@ static long xdl_split(unsigned long const *ha1, long off1, long lim1,
                        return ec;
                }
        }
-
-       return -1;
 }
 
 
index 2ade97b2574a9f77e7ae4002a4e07a6a38e46d07..d7974d1a3e612a235b0c8adfde08ba802e782b5a 100644 (file)
@@ -232,8 +232,6 @@ int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags)
                return i1 >= s1 && i2 >= s2;
        } else
                return s1 == s2 && !memcmp(l1, l2, s1);
-
-       return 0;
 }
 
 static unsigned long xdl_hash_record_with_whitespace(char const **data,