Merge branch 'fc/remote-hg'
authorJunio C Hamano <gitster@pobox.com>
Mon, 22 Apr 2013 01:39:58 +0000 (18:39 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 22 Apr 2013 01:39:58 +0000 (18:39 -0700)
Updates remote-hg helper (in contrib/).

* fc/remote-hg: (21 commits)
remote-hg: activate graphlog extension for hg_log()
remote-hg: fix bad file paths
remote-hg: document location of stored hg repository
remote-hg: fix bad state issue
remote-hg: add 'insecure' option
remote-hg: add simple mail test
remote-hg: add basic author tests
remote-hg: show more proper errors
remote-hg: force remote push
remote-hg: push to the appropriate branch
remote-hg: update tags globally
remote-hg: update remote bookmarks
remote-hg: refactor export
remote-hg: split bookmark handling
remote-hg: redirect buggy mercurial output
remote-hg: trivial test cleanups
remote-hg: make sure fake bookmarks are updated
remote-hg: fix for files with spaces
remote-hg: properly report errors on bookmark pushes
remote-hg: add missing config variable in doc
...

199 files changed:
.mailmap
Documentation/RelNotes/1.8.1.6.txt [new file with mode: 0644]
Documentation/RelNotes/1.8.2.1.txt
Documentation/RelNotes/1.8.3.txt
Documentation/cat-texi.perl
Documentation/config.txt
Documentation/git-archive.txt
Documentation/git-commit-tree.txt
Documentation/git-commit.txt
Documentation/git-count-objects.txt
Documentation/git-credential.txt
Documentation/git-daemon.txt
Documentation/git-fast-export.txt
Documentation/git-format-patch.txt
Documentation/git-help.txt
Documentation/git-remote-ext.txt
Documentation/git-rev-parse.txt
Documentation/git-send-email.txt
Documentation/git-svn.txt
Documentation/git-tag.txt
Documentation/git-tools.txt
Documentation/git.txt
Documentation/gitremote-helpers.txt
Documentation/glossary-content.txt
Documentation/merge-options.txt
Documentation/merge-strategies.txt
Documentation/pretty-formats.txt
Documentation/revisions.txt
Documentation/technical/api-argv-array.txt
Documentation/technical/api-credentials.txt
Documentation/technical/api-ref-iteration.txt
Documentation/technical/api-strbuf.txt
Documentation/technical/pack-format.txt
INSTALL
advice.c
advice.h
attr.c
bisect.c
branch.c
builtin/add.c
builtin/apply.c
builtin/branch.c
builtin/checkout.c
builtin/clone.c
builtin/commit-tree.c
builtin/count-objects.c
builtin/fast-export.c
builtin/fmt-merge-msg.c
builtin/help.c
builtin/log.c
builtin/merge-tree.c
builtin/merge.c
builtin/push.c
builtin/rm.c
builtin/show-branch.c
bundle.c
cache.h
combine-diff.c
commit.c
commit.h
compat/cygwin.c
compat/cygwin.h
compat/nedmalloc/malloc.c.h
compat/obstack.h
compat/precompose_utf8.c
compat/regex/regcomp.c
compat/regex/regex.c
compat/regex/regex_internal.c
config.mak.uname
contrib/completion/git-completion.bash
contrib/completion/git-prompt.sh
contrib/mw-to-git/git-remote-mediawiki.perl
contrib/mw-to-git/git-remote-mediawiki.txt
contrib/mw-to-git/t/README
contrib/mw-to-git/t/install-wiki/LocalSettings.php
contrib/mw-to-git/t/t9362-mw-to-git-utf8.sh
contrib/remote-helpers/Makefile
contrib/remote-helpers/git-remote-bzr
contrib/remote-helpers/git-remote-hg
contrib/remote-helpers/test-bzr.sh
contrib/remote-helpers/test-hg-hg-git.sh
contrib/remote-helpers/test-hg.sh
contrib/subtree/t/t7900-subtree.sh
convert.c
diff.c
diffcore-break.c
diffcore-pickaxe.c
dir.c
entry.c
git-add--interactive.perl
git-compat-util.h
git-cvsserver.perl
git-difftool.perl
git-filter-branch.sh
git-pull.sh
git-quiltimport.sh
git-rebase--am.sh
git-send-email.perl
git-submodule.sh
git-web--browse.sh
git.c
gitweb/INSTALL
gitweb/gitweb.perl
gpg-interface.h
help.c
http-backend.c
http-push.c
http.c
http.h
kwset.c
log-tree.c
match-trees.c
path.c
perl/Git.pm
perl/Git/I18N.pm
perl/private-Error.pm
po/README
pretty.c
progress.c
read-cache.c
remote-curl.c
remote.c
remote.h
rerere.c
resolve-undo.c
resolve-undo.h
revision.c
run-command.c
sequencer.c
sha1_file.c
sha1_name.c
strbuf.c
strbuf.h
streaming.c
submodule.c
submodule.h
t/README
t/lib-gpg/pubring.gpg
t/lib-gpg/random_seed
t/lib-gpg/secring.gpg
t/lib-gpg/trustdb.gpg
t/lib-httpd/apache.conf
t/t1006-cat-file.sh
t/t1060-object-corruption.sh [new file with mode: 0755]
t/t1300-repo-config.sh
t/t2022-checkout-paths.sh
t/t2030-unresolve-info.sh
t/t3200-branch.sh
t/t3508-cherry-pick-many-commits.sh
t/t3600-rm.sh
t/t3701-add-interactive.sh
t/t4014-format-patch.sh
t/t4038-diff-combined.sh
t/t4124-apply-ws-rule.sh
t/t4150-am.sh
t/t4209-log-pickaxe.sh
t/t4300-merge-tree.sh
t/t5002-archive-attr-pattern.sh
t/t5004-archive-corner-cases.sh
t/t5404-tracking-branches.sh
t/t5505-remote.sh
t/t5516-fetch-push.sh
t/t5517-push-mirror.sh
t/t5519-push-alternates.sh
t/t5531-deep-submodule-push.sh
t/t5550-http-fetch.sh
t/t5551-http-fetch.sh
t/t5570-git-daemon.sh
t/t5704-bundle.sh
t/t5710-info-alternate.sh
t/t6012-rev-list-simplify.sh
t/t6030-bisect-porcelain.sh
t/t6200-fmt-merge-msg.sh
t/t7003-filter-branch.sh
t/t7400-submodule-basic.sh
t/t7406-submodule-update.sh
t/t7512-status-help.sh
t/t7601-merge-pull-config.sh
t/t7610-mergetool.sh
t/t7612-merge-verify-signatures.sh [new file with mode: 0755]
t/t7800-difftool.sh
t/t9001-send-email.sh
t/t9010-svn-fe.sh
t/t9300-fast-import.sh
t/t9400-git-cvsserver-server.sh
t/t9401-git-cvsserver-crlf.sh
t/t9700/test.pl
t/t9902-completion.sh
t/t9903-bash-prompt.sh
t/test-lib-functions.sh
t/test-lib.sh
t/valgrind/valgrind.sh
transport-helper.c
transport.h
usage.c
wt-status.c
wt-status.h
xdiff/xdiffi.c
xdiff/xhistogram.c
index c7e86183001a00ad2105765708b5b59852ef6640..48d7acf013c611d4885cddffdf516bb5d0ea5a86 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -73,6 +73,7 @@ Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
 <nico@fluxnic.net> <nico@cam.org>
 Peter Krefting <peter@softwolves.pp.se> <peter@svarten.intern.softwolves.pp.se>
 Peter Krefting <peter@softwolves.pp.se> <peter@softwolves.pp.se>
+Petr Baudis <pasky@ucw.cz> <pasky@suse.cz>
 Philippe Bruhat <book@cpan.org>
 Ralf Thielow <ralf.thielow@gmail.com> <ralf.thielow@googlemail.com>
 Ramsay Allan Jones <ramsay@ramsay1.demon.co.uk>
diff --git a/Documentation/RelNotes/1.8.1.6.txt b/Documentation/RelNotes/1.8.1.6.txt
new file mode 100644 (file)
index 0000000..c15cf2e
--- /dev/null
@@ -0,0 +1,39 @@
+Git 1.8.1.6 Release Notes
+=========================
+
+Fixes since v1.8.1.5
+--------------------
+
+ * An earlier change to the attribute system introduced at v1.8.1.2 by
+   mistake stopped a pattern "dir" (without trailing slash) from
+   matching a directory "dir" (it only wanted to allow pattern "dir/"
+   to also match).
+
+ * The code to keep track of what directory names are known to Git on
+   platforms with case insensitive filesystems can get confused upon a
+   hash collision between these pathnames and looped forever.
+
+ * When the "--prefix" option is used to "checkout-index", the code
+   did not pick the correct output filter based on the attribute
+   setting.
+
+ * Annotated tags outside refs/tags/ hierarchy were not advertised
+   correctly to the ls-remote and fetch with recent version of Git.
+
+ * The logic used by "git diff -M --stat" to shorten the names of
+   files before and after a rename did not work correctly when the
+   common prefix and suffix between the two filenames overlapped.
+
+ * "git update-index -h" did not do the usual "-h(elp)" thing.
+
+ * perl/Git.pm::cat_blob slurped everything in core only to write it
+   out to a file descriptor, which was not a very smart thing to do.
+
+ * The SSL peer verification done by "git imap-send" did not ask for
+   Server Name Indication (RFC 4366), failing to connect SSL/TLS
+   sites that serve multiple hostnames on a single IP.
+
+ * "git bundle verify" did not say "records a complete history" for a
+   bundle that does not have any prerequisites.
+
+Also contains various documentation fixes.
index 2cd562233eac46c67f2eb06d7a84f57ca1540d3b..1354ad03f5e65cf85ec4c1e2b68c6152c3f295b8 100644 (file)
@@ -4,6 +4,46 @@ Git v1.8.2.1 Release Notes
 Fixes since v1.8.2
 ------------------
 
+ * An earlier change to the attribute system introduced at v1.8.1.2 by
+   mistake stopped a pattern "dir" (without trailing slash) from
+   matching a directory "dir" (it only wanted to allow pattern "dir/"
+   to also match).
+
+ * Verification of signed tags were not done correctly when not in C
+   or en/US locale.
+
+ * 'git commit -m "$msg"' used to add an extra newline even when
+   $msg already ended with one.
+
+ * The "--match=<pattern>" option of "git describe", when used with
+   "--all" to allow refs that are not annotated tags to be used as a
+   base of description, did not restrict the output from the command
+   to those that match the given pattern.
+
+ * An aliased command spawned from a bare repository that does not say
+   it is bare with "core.bare = yes" is treated as non-bare by mistake.
+
+ * When "format-patch" quoted a non-ascii strings on the header files,
+   it incorrectly applied rfc2047 and chopped a single character in
+   the middle of it.
+
+ * "git archive" reports a failure when asked to create an archive out
+   of an empty tree.  It would be more intuitive to give an empty
+   archive back in such a case.
+
+ * "git tag -f <tag>" always said "Updated tag '<tag>'" even when
+   creating a new tag (i.e. not overwriting nor updating).
+
+ * "git cmd -- ':(top'" was not diagnosed as an invalid syntax, and
+   instead the parser kept reading beyond the end of the string.
+
+ * Annotated tags outside refs/tags/ hierarchy were not advertised
+   correctly to the ls-remote and fetch with recent version of Git.
+
+ * The code to keep track of what directory names are known to Git on
+   platforms with case insensitive filesystems can get confused upon a
+   hash collision between these pathnames and looped forever.
+
  * The logic used by "git diff -M --stat" to shorten the names of
    files before and after a rename did not work correctly when the
    common prefix and suffix between the two filenames overlapped.
index dcef36e671d91b6f2e9abd3c5c2b744c2a1fb822..7799cec1dddbdd24121885360f77c88c8b97a746 100644 (file)
@@ -24,7 +24,10 @@ mechanism to make "git add -u" behave as if "git add -u .", it is
 important for those who are used to "git add -u" (without pathspec)
 updating the index only for paths in the current subdirectory to start
 training their fingers to explicitly say "git add -u ." when they mean
-it before Git 2.0 comes.
+it before Git 2.0 comes.  A warning is issued when these commands are
+run without a pathspec and when you have local changes outside the
+current directory, because the behaviour in Git 2.0 will be different
+from today's version in such a situation.
 
 
 Updates since v1.8.2
@@ -32,8 +35,46 @@ Updates since v1.8.2
 
 UI, Workflows & Features
 
+ * "git branch --vv" learned to paint the name of the branch it
+   integrates with in a different color (color.branch.upstream,
+   which defaults to blue).
+
+ * "git count-objects" learned "--human-readable" aka "-H" option to
+   show various large numbers in Ki/Mi/GiB scaled as necessary.
+
+ * "git cherry-pick $blob" and "git cherry-pick $tree" are nonsense,
+   and a more readable error message e.g. "can't cherry-pick a tree"
+   is given (we used to say "expected exactly one commit").
+
+ * The "--annotate" option to "git send-email" can be turned on (or
+   off) by default with sendemail.annotate configuration variable (you
+   can use --no-annotate from the command line to override it).
+
+ * The "--cover-letter" option to "git format-patch" can be turned on
+   (or off) by default with format.coverLetter configuration
+   variable. By setting it to 'auto', you can turn it on only for a
+   series with two or more patches.
+
+ * The bash completion support (in contrib/) learned that cherry-pick
+   takes a few more options than it already knew about.
+
+ * "git help" learned "-g" option to show the list of guides just like
+   list of commands are given with "-a".
+
+ * A triangular "pull from one place, push to another place" workflow
+   is supported better by new remote.pushdefault (overrides the
+   "origin" thing) and branch.*.pushremote (overrides the
+   branch.*.remote) configuration variables.
+
+ * "git status" learned to report that you are in the middle of a
+   revert session, just like it does for a cherry-pick and a bisect
+   session.
+
+ * The handling by "git branch --set-upstream-to" against various forms
+   of erroneous inputs was suboptimal and has been improved.
+
  * When the interactive access to git-shell is not enabled, it issues
-   a message meant to help the system admininstrator to enable it.
+   a message meant to help the system administrator to enable it.
    An explicit way to help the end users who connect to the service by
    issuing custom messages to refuse such an access has been added.
 
@@ -52,6 +93,9 @@ UI, Workflows & Features
    ref by specifying a raw object name from the command line when the
    server side supports this feature.
 
+ * Output from "git log --graph" works better with submodule log
+   output now.
+
  * "git count-objects -v" learned to report leftover temporary
    packfiles and other garbage in the object store.
 
@@ -70,16 +114,47 @@ UI, Workflows & Features
  * The new "--follow-tags" option tells "git push" to push relevant
    annotated tags when pushing branches out.
 
+ * "git merge" and "git pull" can optionally be told to inspect and
+   reject when merging a commit that does not carry a trusted GPG
+   signature.
+
  * "git mergetool" now feeds files to the "p4merge" backend in the
    order that matches the p4 convention, where "theirs" is usually
    shown on the left side, which is the opposite from other backend
    expects.
 
+ * "show/log" now honors gpg.program configuration just like other
+   parts of the code that use GnuPG.
+
+ * "git log" that shows the difference between the parent and the
+   child has been optimized somewhat.
+
+ * "git difftool" allows the user to write into the temporary files
+   being shown; if the user makes changes to the working tree at the
+   same time, one of the changes has to be lost in such a case, but it
+   tells the user what happened and refrains from overwriting the copy
+   in the working tree.
+
+ * There was no good way to ask "I have a random string that came from
+   outside world. I want to turn it into a 40-hex object name while
+   making sure such an object exists".  A new peeling suffix ^{object}
+   can be used for that purpose, together with "rev-parse --verify".
+
 
 Performance, Internal Implementation, etc.
 
  * Updates for building under msvc.
 
+ * The stack footprint of some codepaths that access an object from a
+   pack has been shrunk.
+
+ * The logic to coalesce the same lines removed from the parents in
+   the output from "diff -c/--cc" has been updated, but with an O(n^2)
+   complexity, so this might turn out to be undesirable.
+
+ * The code to enforce permission bits on files in $GIT_DIR/ for
+   shared repositories have been simplified.
+
  * A few codepaths knew how much data they need to put in the
    hashtables they use upfront, but still started from a small table
    repeatedly growing and rehashing.
@@ -94,8 +169,20 @@ Performance, Internal Implementation, etc.
  * The pkt-line API, implementation and its callers have been cleaned
    up to make them more robust.
 
+ * Cygwin port has a faster-but-lying lstat(2) emulation whose
+   incorrectness does not matter in practice except for a few
+   codepaths, and setting permission bits to directories is a codepath
+   that needs to use a more correct one.
+
+ * "git checkout" had repeated pathspec matches on the same paths,
+   which have been consolidated.  Also a bug in "git checkout dir/"
+   that is started from an unmerged index has been fixed.
+
+ * A few bugfixes to "git rerere" working on corner case merge
+   conflicts have been applied.
+
 
-Also contains minor documentation updates and code clean-ups.
+Also contains various documentation updates and code clean-ups.
 
 
 Fixes since v1.8.2
@@ -105,8 +192,85 @@ Unless otherwise noted, all the fixes since v1.8.2 in the maintenance
 track are contained in this release (see release notes to them for
 details).
 
- * "index-pack --fix-thin" used uninitialize value to compute delta
-   depths of objects it appends to the resulting pack.
+ * When "upload-pack" fails while generating a pack in response to
+   "git fetch" (or "git clone"), the receiving side mistakenly said
+   there was a programming error to trigger the die handler
+   recursively.
+   (merge 1ece66b jk/a-thread-only-dies-once later to maint).
+
+ * "rev-list --stdin" and friends kept bogus pointers into input
+   buffer around as human readble object names.  This was not a huge
+   problem but was exposed by a new change that uses these names in
+   error output.
+   (merge 70d26c6 tr/copy-revisions-from-stdin later to maint).
+
+ * Smart-capable HTTP servers were not restricted via the
+   GIT_NAMESPACE mechanism when talking with commit-walker clients,
+   like they do when talking with smart HTTP clients.
+   (merge 6130f86 jk/http-dumb-namespaces later to maint).
+
+ * "git merge-tree" did not omit a merge result that is identical to
+   "our" side in certain cases.
+   (merge aacecc3 jk/merge-tree-added-identically later to maint).
+
+ * Perl scripts like "git-svn" closed (not redirecting to /dev/null)
+   the standard error stream, which is not a very smart thing to do.
+   Later open may return file descriptor #2 for unrelated purpose, and
+   error reporting code may write into them.
+   (merge a749c0b tr/perl-keep-stderr-open later to maint).
+
+ * "git show-branch" was not prepared to show a very long run of
+   ancestor operators e.g. foobar^2~2^2^2^2...^2~4 correctly.
+   (merge aaa07e3 jk/show-branch-strbuf later to maint).
+
+ * "git diff --diff-algorithm algo" is also understood as "git diff
+   --diff-algorithm=algo".
+   (merge 0895c6d jk/diff-algo-finishing-touches later to maint).
+
+ * The new core.commentchar configuration was not applied to a few
+   places.
+   (merge 89c3bbd rt/commentchar-fmt-merge-msg later to maint).
+
+ * "git bundle" did not like a bundle created using a commit without
+   any message as its one of the prerequistes.
+   (merge 5446e33 lf/bundle-with-tip-wo-message later to maint).
+
+ * "git log -S/-G" started paying attention to textconv filter, but
+   there was no way to disable this.  Make it honor --no-textconv
+   option.
+   (merge 61690bf sr/log-SG-no-textconv later to maint).
+
+ * When used with "-d temporary-directory" option, "git filter-branch"
+   failed to come back to the original working tree to perform the
+   final clean-up procedure.
+   (merge 9727601 jk/filter-branch-come-back-to-original later to maint).
+
+ * "git merge $(git rev-parse v1.8.2)" behaved quite differently from
+   "git merge v1.8.2", as if v1.8.2 were written as v1.8.2^0 and did
+   not pay much attention to the annotated tag payload.  Make the code
+   notice the type of the tag object, in addition to the dwim_ref()
+   based classification the current code uses (i.e. the name appears
+   in refs/tags/) to decide when to special case merging of tags.
+   (merge a38d3d7 jc/merge-tag-object later to maint).
+
+ * Fix 1.8.1.x regression that stopped matching "dir" (without
+   trailing slash) to a directory "dir".
+   (merge efa5f82 jc/directory-attrs-regression-fix later to maint-1.8.1).
+
+ * "git apply --whitespace=fix" was not prepared to see a line getting
+   longer after fixing whitespaces (e.g. tab-in-indent aka Python).
+   (merge 329b26e jc/apply-ws-fix-tab-in-indent later to maint-1.8.1).
+
+ * The prompt string generator (in contrib/completion/) did not notice
+   when we are in a middle of a "git revert" session.
+   (merge 3ee4452 rr/prompt-revert-head later to maint).
+
+ * "submodule summary --summary-limit" option did not support
+   "--option=value" form.
+   (merge 862ae6c rs/submodule-summary-limit later to maint).
+
+ * "index-pack --fix-thin" used an uninitialized value to compute
+   delta depths of objects it appends to the resulting pack.
    (merge 57165db jk/index-pack-correct-depth-fix later to maint).
 
  * "index-pack --verify-stat" used a few counters outside protection
@@ -116,22 +280,18 @@ details).
  * The code to keep track of what directory names are known to Git on
    platforms with case insensitive filesystems can get confused upon a
    hash collision between these pathnames and looped forever.
-   (merge 2092678 kb/name-hash later to maint).
 
  * Annotated tags outside refs/tags/ hierarchy were not advertised
    correctly to the ls-remote and fetch with recent version of Git.
-   (merge c29c46f jk/fully-peeled-packed-ref later to maint).
 
  * Recent optimization broke shallow clones.
    (merge f59de5d jk/peel-ref later to maint).
 
  * "git cmd -- ':(top'" was not diagnosed as an invalid syntax, and
    instead the parser kept reading beyond the end of the string.
-   (merge f612a67 lf/setup-prefix-pathspec later to maint).
 
  * "git tag -f <tag>" always said "Updated tag '<tag>'" even when
    creating a new tag (i.e. not overwriting nor updating).
-   (merge 3ae851e ph/tag-force-no-warn-on-creation later to maint).
 
  * "git p4" did not behave well when the path to the root of the P4
    client was not its real path.
@@ -140,16 +300,13 @@ details).
  * "git archive" reports a failure when asked to create an archive out
    of an empty tree.  It would be more intuitive to give an empty
    archive back in such a case.
-   (merge bd54cf1 jk/empty-archive later to maint).
 
  * When "format-patch" quoted a non-ascii strings on the header files,
    it incorrectly applied rfc2047 and chopped a single character in
    the middle of it.
-   (merge 6cd3c05 ks/rfc2047-one-char-at-a-time later to maint).
 
  * An aliased command spawned from a bare repository that does not say
    it is bare with "core.bare = yes" is treated as non-bare by mistake.
-   (merge 2cd83d1 jk/alias-in-bare later to maint).
 
  * In "git reflog expire", REACHABLE bit was not cleared from the
    correct objects.
@@ -162,7 +319,6 @@ details).
    "--all" to allow refs that are not annotated tags to be used as a
    base of description, did not restrict the output from the command
    to those that match the given pattern.
-   (merge 46e1d6e jc/describe later to maint).
 
  * Clarify in the documentation "what" gets pushed to "where" when the
    command line to "git push" does not say these explicitly.
@@ -199,7 +355,6 @@ details).
 
  * 'git commit -m "$msg"' used to add an extra newline even when
    $msg already ended with one.
-   (merge 46fbf75 bc/commit-complete-lines-given-via-m-option later to maint).
 
  * The SSL peer verification done by "git imap-send" did not ask for
    Server Name Indication (RFC 4366), failing to connect SSL/TLS
@@ -213,7 +368,6 @@ details).
 
  * Verification of signed tags were not done correctly when not in C
    or en/US locale.
-   (merge 0174eea mg/gpg-interface-using-status later to maint).
 
  * Some platforms and users spell UTF-8 differently; retry with the
    most official "UTF-8" when the system does not understand the
@@ -230,4 +384,4 @@ details).
    alphabetical order.
 
  * "git submodule update", when recursed into sub-submodules, did not
-   acccumulate the prefix paths.
+   accumulate the prefix paths.
index 828ec62554fe927eb16a03f835448e6db0c303a1..87437f8a95768595e040b8c4c1d48e5c29ada087 100755 (executable)
@@ -12,6 +12,7 @@
                push @menu, $1;
        }
        s/\(\@pxref{\[(URLS|REMOTES)\]}\)//;
+       s/\@anchor\{[^{}]*\}//g;
        print TMP;
 }
 close TMP;
index f79184c0a83170ea54298f2b8ac960372371b0f3..29559c88af2e5cc2aeffdc29626b6710446bc10f 100644 (file)
@@ -727,9 +727,22 @@ branch.autosetuprebase::
        This option defaults to never.
 
 branch.<name>.remote::
-       When in branch <name>, it tells 'git fetch' and 'git push' which
-       remote to fetch from/push to.  It defaults to `origin` if no remote is
-       configured. `origin` is also used if you are not on any branch.
+       When on branch <name>, it tells 'git fetch' and 'git push'
+       which remote to fetch from/push to.  The remote to push to
+       may be overridden with `remote.pushdefault` (for all branches).
+       The remote to push to, for the current branch, may be further
+       overridden by `branch.<name>.pushremote`.  If no remote is
+       configured, or if you are not on any branch, it defaults to
+       `origin` for fetching and `remote.pushdefault` for pushing.
+
+branch.<name>.pushremote::
+       When on branch <name>, it overrides `branch.<name>.remote` for
+       pushing.  It also overrides `remote.pushdefault` for pushing
+       from branch <name>.  When you pull from one place (e.g. your
+       upstream) and push to another place (e.g. your own publishing
+       repository), you would want to set `remote.pushdefault` to
+       specify the remote to push to for all branches, and use this
+       option to override it for a specific branch.
 
 branch.<name>.merge::
        Defines, together with branch.<name>.remote, the upstream branch
@@ -794,7 +807,8 @@ color.branch::
 color.branch.<slot>::
        Use customized color for branch coloration. `<slot>` is one of
        `current` (the current branch), `local` (a local branch),
-       `remote` (a remote-tracking branch in refs/remotes/), `plain` (other
+       `remote` (a remote-tracking branch in refs/remotes/),
+       `upstream` (upstream tracking branch), `plain` (other
        refs).
 +
 The value for these configuration variables is a list of colors (at most
@@ -1096,6 +1110,11 @@ format.signoff::
     the rights to submit this work under the same open source license.
     Please see the 'SubmittingPatches' document for further discussion.
 
+format.coverLetter::
+       A boolean that controls whether to generate a cover-letter when
+       format-patch is invoked, but in addition can be set to "auto", to
+       generate a cover-letter only when there's more than one patch.
+
 filter.<driver>.clean::
        The command which is used to convert the content of a worktree
        file to a blob upon checkin.  See linkgit:gitattributes[5] for
@@ -1447,6 +1466,14 @@ http.sslCAPath::
        with when fetching or pushing over HTTPS. Can be overridden
        by the 'GIT_SSL_CAPATH' environment variable.
 
+http.sslTry::
+       Attempt to use AUTH SSL/TLS and encrypted data transfers
+       when connecting via regular FTP protocol. This might be needed
+       if the FTP server requires it for security reasons or you wish
+       to connect securely whenever remote FTP server supports it.
+       Default is false since it might trigger certificate verification
+       errors on misconfigured servers.
+
 http.maxRequests::
        How many HTTP requests to launch in parallel. Can be overridden
        by the 'GIT_HTTP_MAX_REQUESTS' environment variable. Default is 5.
@@ -1898,6 +1925,11 @@ receive.updateserverinfo::
        If set to true, git-receive-pack will run git-update-server-info
        after receiving data from git-push and updating refs.
 
+remote.pushdefault::
+       The remote to push to by default.  Overrides
+       `branch.<name>.remote` for all branches, and is overridden by
+       `branch.<name>.pushremote` for specific branches.
+
 remote.<name>.url::
        The URL of a remote repository.  See linkgit:git-fetch[1] or
        linkgit:git-push[1].
@@ -1998,6 +2030,7 @@ sendemail.<identity>.*::
 
 sendemail.aliasesfile::
 sendemail.aliasfiletype::
+sendemail.annotate::
 sendemail.bcc::
 sendemail.cc::
 sendemail.cccmd::
index b4c2e24849b1154fb55608fa95cead9e405a03bf..250e5228a35165e72f2f55fd347941c3a2a1d08c 100644 (file)
@@ -56,7 +56,8 @@ OPTIONS
        Write the archive to <file> instead of stdout.
 
 --worktree-attributes::
-       Look for attributes in .gitattributes in working directory too.
+       Look for attributes in .gitattributes files in the working tree
+       as well (see <<ATTRIBUTES>>).
 
 <extra>::
        This can be any options that the archiver backend understands.
@@ -120,6 +121,7 @@ tar.<format>.remote::
        user-defined formats, but true for the "tar.gz" and "tgz"
        formats.
 
+[[ATTRIBUTES]]
 ATTRIBUTES
 ----------
 
index 86ef56e7c8760d622848da4131ebf231d27eb873..cafdc9642d312776b0122c4d010a9e9246bad8ff 100644 (file)
@@ -10,7 +10,9 @@ SYNOPSIS
 --------
 [verse]
 'git commit-tree' <tree> [(-p <parent>)...] < changelog
-'git commit-tree' [(-p <parent>)...] [(-m <message>)...] [(-F <file>)...] <tree>
+'git commit-tree' [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...]
+                 [(-F <file>)...] <tree>
+
 
 DESCRIPTION
 -----------
@@ -52,6 +54,9 @@ OPTIONS
        Read the commit log message from the given file. Use `-` to read
        from the standard input.
 
+-S[<keyid>]::
+       GPG-sign commit.
+
 
 Commit Information
 ------------------
index 05f82973687bb3fd7fbb066f725d72d386cd446f..9b1be5581d34b9911e3d60f23dcdda440d3bc17f 100644 (file)
@@ -207,14 +207,15 @@ variable (see linkgit:git-config[1]).
        without changing its commit message.
 
 --amend::
-       Used to amend the tip of the current branch. Prepare the tree
-       object you would want to replace the latest commit as usual
-       (this includes the usual -i/-o and explicit paths), and the
-       commit log editor is seeded with the commit message from the
-       tip of the current branch. The commit you create replaces the
-       current tip -- if it was a merge, it will have the parents of
-       the current tip as parents -- so the current top commit is
-       discarded.
+       Replace the tip of the current branch by creating a new
+       commit. The recorded tree is prepared as usual (including
+       the effect of the `-i` and `-o` options and explicit
+       pathspec), and the message from the original commit is used
+       as the starting point, instead of an empty message, when no
+       other message is specified from the command line via options
+       such as `-m`, `-F`, `-c`, etc.  The new commit has the same
+       parents and author as the current one (the `--reset-author`
+       option can countermand this).
 +
 --
 It is a rough equivalent for:
index da6e72e696d4af013b3c717d31a0e98cd41922d4..b300e846f13d6a7f340286b4624dc3b0da4ac740 100644 (file)
@@ -8,7 +8,7 @@ git-count-objects - Count unpacked number of objects and their disk consumption
 SYNOPSIS
 --------
 [verse]
-'git count-objects' [-v]
+'git count-objects' [-v] [-H | --human-readable]
 
 DESCRIPTION
 -----------
@@ -24,11 +24,11 @@ OPTIONS
 +
 count: the number of loose objects
 +
-size: disk space consumed by loose objects, in KiB
+size: disk space consumed by loose objects, in KiB (unless -H is specified)
 +
 in-pack: the number of in-pack objects
 +
-size-pack: disk space consumed by the packs, in KiB
+size-pack: disk space consumed by the packs, in KiB (unless -H is specified)
 +
 prune-packable: the number of loose objects that are also present in
 the packs. These objects could be pruned using `git prune-packed`.
@@ -36,7 +36,13 @@ the packs. These objects could be pruned using `git prune-packed`.
 garbage: the number of files in object database that are not valid
 loose objects nor valid packs
 +
-size-garbage: disk space consumed by garbage files, in KiB
+size-garbage: disk space consumed by garbage files, in KiB (unless -H is
+specified)
+
+-H::
+--human-readable::
+
+Print sizes in human readable format
 
 GIT
 ---
index 472f00f607850d7298535eead2982915412400d9..7da0f13a5cb26e9e5d1cb7d9c73fd4af57443d72 100644 (file)
@@ -56,7 +56,7 @@ For example, if we want a password for
 `https://example.com/foo.git`, we might generate the following
 credential description (don't forget the blank line at the end; it
 tells `git credential` that the application finished feeding all the
-infomation it has):
+information it has):
 
         protocol=https
         host=example.com
index 77da564134f92e692e078888d7f87bd6710e821f..bfb106cccd5880f0cd40b03059aa79a5569acb63 100644 (file)
@@ -147,6 +147,13 @@ OPTIONS
 Giving these options is an error when used with `--inetd`; use
 the facility of inet daemon to achieve the same before spawning
 'git daemon' if needed.
++
+Like many programs that switch user id, the daemon does not reset
+environment variables such as `$HOME` when it runs git programs,
+e.g. `upload-pack` and `receive-pack`. When using this option, you
+may also want to set and export `HOME` to point at the home
+directory of `<user>` before starting the daemon, and make sure any
+Git configuration files in that directory are readable by `<user>`.
 
 --enable=<service>::
 --disable=<service>::
index d6487e1ce03a9c060ae41b7b7455c442c6ea58f3..feab7a3e4ecb56aa17c32bd555e907a51001ef1f 100644 (file)
@@ -66,6 +66,8 @@ produced incorrect results if you gave these options.
        incremental runs.  As <file> is only opened and truncated
        at completion, the same path can also be safely given to
        \--import-marks.
+       The file will not be written if no new object has been
+       marked/exported.
 
 --import-marks=<file>::
        Before processing any input, load the marks specified in
index 3a62f50edae9cdc772cb1009cf839b18e0079a9c..39118774afbbd730e4464f44e24a05af91432c30 100644 (file)
@@ -20,7 +20,7 @@ SYNOPSIS
                   [--ignore-if-in-upstream]
                   [--subject-prefix=Subject-Prefix] [(--reroll-count|-v) <n>]
                   [--to=<email>] [--cc=<email>]
-                  [--cover-letter] [--quiet] [--notes[=<ref>]]
+                  [--[no-]cover-letter] [--quiet] [--notes[=<ref>]]
                   [<common diff options>]
                   [ <since> | <revision range> ]
 
@@ -195,7 +195,7 @@ will want to ensure that threading is disabled for `git send-email`.
        `Cc:`, and custom) headers added so far from config or command
        line.
 
---cover-letter::
+--[no-]cover-letter::
        In addition to the patches, generate a cover letter file
        containing the shortlog and the overall diffstat.  You can
        fill in a description in the file before sending it out.
@@ -260,6 +260,7 @@ attachments, and sign off patches with configuration variables.
        cc = <email>
        attach [ = mime-boundary-string ]
        signoff = true
+       coverletter = auto
 ------------
 
 
index e07b6dc19ada9f3bb2ff4a6ae66eb587455fab11..b21e9d79be22cf134cf4e5f009fc8d71a635cc73 100644 (file)
@@ -8,31 +8,45 @@ git-help - Display help information about Git
 SYNOPSIS
 --------
 [verse]
-'git help' [-a|--all|-i|--info|-m|--man|-w|--web] [COMMAND]
+'git help' [-a|--all] [-g|--guide]
+          [-i|--info|-m|--man|-w|--web] [COMMAND|GUIDE]
 
 DESCRIPTION
 -----------
 
-With no options and no COMMAND given, the synopsis of the 'git'
+With no options and no COMMAND or GUIDE given, the synopsis of the 'git'
 command and a list of the most commonly used Git commands are printed
 on the standard output.
 
-If the option '--all' or '-a' is given, then all available commands are
+If the option '--all' or '-a' is given, all available commands are
 printed on the standard output.
 
-If a Git subcommand is named, a manual page for that subcommand is brought
-up. The 'man' program is used by default for this purpose, but this
-can be overridden by other options or configuration variables.
+If the option '--guide' or '-g' is given, a list of the useful
+Git guides is also printed on the standard output.
+
+If a command, or a guide, is given, a manual page for that command or
+guide is brought up. The 'man' program is used by default for this
+purpose, but this can be overridden by other options or configuration
+variables.
 
 Note that `git --help ...` is identical to `git help ...` because the
 former is internally converted into the latter.
 
+To display the linkgit:git[1] man page, use `git help git`.
+
+This page can be displayed with 'git help help' or `git help --help`
+
 OPTIONS
 -------
 -a::
 --all::
        Prints all the available commands on the standard output. This
-       option supersedes any other option.
+       option overrides any given command or guide name.
+
+-g::
+--guides::
+       Prints a list of useful guides on the standard output. This
+       option overrides any given command or guide name.
 
 -i::
 --info::
index 58b7facb09915a1856613dfcfd32b28d30cf896c..8cfc748ae2da4fce4c7ef804dcd50d2d923068d5 100644 (file)
@@ -86,7 +86,7 @@ begins with `ext::`.  Examples:
        edit .ssh/config.
 
 "ext::socat -t3600 - ABSTRACT-CONNECT:/git-server %G/somerepo"::
-       Represents repository with path /somerepo accessable over
+       Represents repository with path /somerepo accessible over
        git protocol at abstract namespace address /git-server.
 
 "ext::git-server-alias foo %G/repo"::
index 10a116faf8f681c9984c9b52949e84c227fdc26e..1f9ed6cfd28622afcf269eb8dac05fb9414d9901 100644 (file)
@@ -60,8 +60,19 @@ OPTIONS
        instead.
 
 --verify::
-       The parameter given must be usable as a single, valid
-       object name.  Otherwise barf and abort.
+       Verify that exactly one parameter is provided, and that it
+       can be turned into a raw 20-byte SHA-1 that can be used to
+       access the object database. If so, emit it to the standard
+       output; otherwise, error out.
++
+If you want to make sure that the output actually names an object in
+your object database and/or can be used as a specific type of object
+you require, you can add "^{type}" peeling operator to the parmeter.
+For example, `git rev-parse "$VAR^{commit}"` will make sure `$VAR`
+names an existing object that is a commit-ish (i.e. a commit, or an
+annotated tag that points at a commit).  To make sure that `$VAR`
+names an existing object of any type, `git rev-parse "$VAR^{object}"`
+can be used.
 
 -q::
 --quiet::
@@ -308,12 +319,12 @@ $ git rev-parse --verify HEAD
 * Print the commit object name from the revision in the $REV shell variable:
 +
 ------------
-$ git rev-parse --verify $REV
+$ git rev-parse --verify $REV^{commit}
 ------------
 +
 This will error out if $REV is empty or not a valid revision.
 
-* Same as above:
+* Similar to above:
 +
 ------------
 $ git rev-parse --default master --verify $REV
index 0cffef8aa51cc5c2f34393e39e45e84c4997b195..40a9a9abc14f175738986b244207655b296cc31d 100644 (file)
@@ -45,8 +45,9 @@ Composing
 ~~~~~~~~~
 
 --annotate::
-       Review and edit each patch you're about to send. See the
-       CONFIGURATION section for 'sendemail.multiedit'.
+       Review and edit each patch you're about to send. Default is the value
+       of 'sendemail.annotate'. See the CONFIGURATION section for
+       'sendemail.multiedit'.
 
 --bcc=<address>::
        Specify a "Bcc:" value for each email. Default is the value of
index 1b8b6498cd8afa4e2581e3597c4787981dc042df..7706d41c8704679c00a302306651628e5b99d1c1 100644 (file)
@@ -245,7 +245,7 @@ first have already been pushed into SVN.
        patch), "all" (accept all patches), or "quit".
        +
        'git svn dcommit' returns immediately if answer if "no" or "quit", without
-       commiting anything to SVN.
+       committing anything to SVN.
 
 'branch'::
        Create a branch in the SVN repository.
@@ -856,7 +856,7 @@ HANDLING OF SVN BRANCHES
 ------------------------
 If 'git svn' is configured to fetch branches (and --follow-branches
 is in effect), it sometimes creates multiple Git branches for one
-SVN branch, where the addtional branches have names of the form
+SVN branch, where the additional branches have names of the form
 'branchname@nnn' (with nnn an SVN revision number).  These additional
 branches are created if 'git svn' cannot find a parent commit for the
 first commit in an SVN branch, to connect the branch to the history of
index e3032c46c637f39a5a3dd965f122365ece197a5e..b21aa87fe87a26f738c971f8c3dffdcf44fb13cd 100644 (file)
@@ -126,6 +126,12 @@ This option is only applicable when listing tags without annotation lines.
        linkgit:git-check-ref-format[1].  Some of these checks
        may restrict the characters allowed in a tag name.
 
+<commit>::
+<object>::
+       The object that the new tag will refer to, usually a commit.
+       Defaults to HEAD.
+
+
 CONFIGURATION
 -------------
 By default, 'git tag' in sign-with-default mode (-s) will use your
index ad8b823f7732fe05e911fe5e8f2a1d60983c7a26..78a0d955ec22e22fbb1028f4eb6bfceeafc976f7 100644 (file)
@@ -109,7 +109,7 @@ Others
 
    - *git.el* (contrib/)
 
-   This is an Emacs interface for Git. The user interface is modeled on
+   This is an Emacs interface for Git. The user interface is modelled on
    pcl-cvs. It has been developed on Emacs 21 and will probably need some
    tweaking to work on XEmacs.
 
index 4307d62bd4a4e4b5361200ef54d8ecba60e4f1b0..6a875f2adefe34e27bc0fc3b6fdb9d7bcfd23301 100644 (file)
@@ -43,14 +43,16 @@ unreleased) version of Git, that is available from 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v1.8.2/git.html[documentation for release 1.8.2]
+* link:v1.8.2.1/git.html[documentation for release 1.8.2.1]
 
 * release notes for
+  link:RelNotes/1.8.2.1.txt[1.8.2.1].
   link:RelNotes/1.8.2.txt[1.8.2].
 
-* link:v1.8.1.5/git.html[documentation for release 1.8.1.5]
+* link:v1.8.1.6/git.html[documentation for release 1.8.1.6]
 
 * release notes for
+  link:RelNotes/1.8.1.6.txt[1.8.1.6],
   link:RelNotes/1.8.1.5.txt[1.8.1.5],
   link:RelNotes/1.8.1.4.txt[1.8.1.4],
   link:RelNotes/1.8.1.3.txt[1.8.1.3],
index 0c91aba86182f91206fcba5470b7202e4496f073..f506031ae49070e216e71914d8ef241da58430e1 100644 (file)
@@ -174,8 +174,8 @@ ref.
 This capability can be advertised multiple times.  The first
 applicable refspec takes precedence.  The left-hand of refspecs
 advertised with this capability must cover all refs reported by
-the list command.  If no 'refspec' capability is advertised,
-there is an implied `refspec *:*`.
+the list command.  If a helper does not need a specific 'refspec'
+capability then it should advertise `refspec *:*`.
 
 'bidi-import'::
        This modifies the 'import' capability.
index eb7ba84f1f65a316f3b1b3637983487b699a0a2c..2478a3963cc774f1bf73c56660a2d4c096ad4d94 100644 (file)
@@ -100,9 +100,22 @@ to point at the new commit.
 
 [[def_detached_HEAD]]detached HEAD::
        Normally the <<def_HEAD,HEAD>> stores the name of a
-       <<def_branch,branch>>.  However, Git also allows you to <<def_checkout,check out>>
-       an arbitrary <<def_commit,commit>> that isn't necessarily the tip of any
-       particular branch.  In this case HEAD is said to be "detached".
+       <<def_branch,branch>>, and commands that operate on the
+       history HEAD represents operate on the history leading to the
+       tip of the branch the HEAD points at.  However, Git also
+       allows you to <<def_checkout,check out>> an arbitrary
+       <<def_commit,commit>> that isn't necessarily the tip of any
+       particular branch.  The HEAD in such a state is called
+       "detached".
++
+Note that commands that operate on the history of the current branch
+(e.g. `git commit` to build a new history on top of it) still work
+while the HEAD is detached. They update the HEAD to point at the tip
+of the updated history without affecting any branch.  Commands that
+update or inquire information _about_ the current branch (e.g. `git
+branch --set-upstream-to` that sets what remote tracking branch the
+current branch integrates with) obviously do not work, as there is no
+(real) current branch to ask about in this state.
 
 [[def_dircache]]dircache::
        You are *waaaaay* behind. See <<def_index,index>>.
index 34a844582846ae409e17347a65ac6cbeb28202a5..2adccf8fec71c10f8223490f1be4b2a215ace5ea 100644 (file)
@@ -84,6 +84,11 @@ option can be used to override --squash.
        Pass merge strategy specific option through to the merge
        strategy.
 
+--verify-signatures::
+--no-verify-signatures::
+       Verify that the commits being merged have good and trusted GPG signatures
+       and abort the merge in case they do not.
+
 --summary::
 --no-summary::
        Synonyms to --stat and --no-stat; these are deprecated and will be
index 66db80296f505a9bd830c746f82bb54e3f49f313..49a9a7d53f5836ecf2c5bcadb30f0d314414afe0 100644 (file)
@@ -48,6 +48,12 @@ patience;;
        this when the branches to be merged have diverged wildly.
        See also linkgit:git-diff[1] `--patience`.
 
+diff-algorithm=[patience|minimal|histogram|myers];;
+       Tells 'merge-recursive' to use a different diff algorithm, which
+       can help avoid mismerges that occur due to unimportant matching
+       lines (such as braces from distinct functions).  See also
+       linkgit:git-diff[1] `--diff-algorithm`.
+
 ignore-space-change;;
 ignore-all-space;;
 ignore-space-at-eol;;
index 293965524e81b240996a795498ba127f723d18eb..afac703f21245b6fa34af90b1da4b3194372a81d 100644 (file)
@@ -131,7 +131,8 @@ The placeholders are:
 - '%B': raw body (unwrapped subject and body)
 - '%N': commit notes
 - '%GG': raw verification message from GPG for a signed commit
-- '%G?': show either "G" for Good or "B" for Bad for a signed commit
+- '%G?': show "G" for a Good signature, "B" for a Bad signature, "U" for a good,
+  untrusted signature and "N" for no signature
 - '%GS': show the name of the signer for a signed commit
 - '%GK': show the key used to sign a signed commit
 - '%gD': reflog selector, e.g., `refs/stash@{1}`
index 314e25da7344dda459ca5b3292aaaabdfc0d6495..8855b1a0ac99012fcd98fcb3272b39e465d84626 100644 (file)
@@ -55,7 +55,7 @@ when you run `git cherry-pick`.
 +
 Note that any of the 'refs/*' cases above may come either from
 the '$GIT_DIR/refs' directory or from the '$GIT_DIR/packed-refs' file.
-While the ref name encoding is unspecified, UTF-8 is prefered as
+While the ref name encoding is unspecified, UTF-8 is preferred as
 some output processing may assume ref names in UTF-8.
 
 '<refname>@\{<date>\}', e.g. 'master@\{yesterday\}', 'HEAD@\{5 minutes ago\}'::
@@ -116,6 +116,11 @@ some output processing may assume ref names in UTF-8.
   object of that type is found or the object cannot be
   dereferenced anymore (in which case, barf).  '<rev>{caret}0'
   is a short-hand for '<rev>{caret}\{commit\}'.
++
+'rev{caret}\{object\}' can be used to make sure 'rev' names an
+object that exists, without requiring 'rev' to be a tag, and
+without dereferencing 'rev'; because a tag is already an object,
+it does not have to be dereferenced even once to get to an object.
 
 '<rev>{caret}\{\}', e.g. 'v0.99.8{caret}\{\}'::
   A suffix '{caret}' followed by an empty brace pair
index a959517b2339847e92464c86a73f9c472bfdb2d0..a6b7d83a8eb05086cb88a9168117aa54cf018551 100644 (file)
@@ -55,7 +55,7 @@ Functions
        initial, empty state.
 
 `argv_array_detach`::
-       Detach the argv array from the `struct argv_array`, transfering
+       Detach the argv array from the `struct argv_array`, transferring
        ownership of the allocated array and strings.
 
 `argv_array_free_detached`::
index 516fda74120c18f4d124ee8e5402dda39b72777a..c1b42a40d3c0c297994cd2966b60cd48629e57fa 100644 (file)
@@ -160,7 +160,7 @@ int foo_login(struct foo_connection *f)
                break;
        default:
                /*
-                * Some other error occured. We don't know if the
+                * Some other error occurred. We don't know if the
                 * credential is good or bad, so report nothing to the
                 * credential subsystem.
                 */
index dbbea95db7a8104dcd5de4b1ac59235f2eadaaa8..aa1c50f181eb20e27a8299ca8ec691eeffa9d51b 100644 (file)
@@ -35,7 +35,7 @@ Iteration functions
 * `head_ref_submodule()`, `for_each_ref_submodule()`,
   `for_each_ref_in_submodule()`, `for_each_tag_ref_submodule()`,
   `for_each_branch_ref_submodule()`, `for_each_remote_ref_submodule()`
-  do the same as the functions descibed above but for a specified
+  do the same as the functions described above but for a specified
   submodule.
 
 * `for_each_rawref()` can be used to learn about broken ref and symref.
index 2c59cb2259d941232652241dc1cadcfc0c3ef812..3350d97dda2408f92dc44c1e3216facc50257a50 100644 (file)
@@ -230,6 +230,11 @@ which can be used by the programmer of the callback as she sees fit.
        destination. This is useful for literal data to be fed to either
        strbuf_expand or to the *printf family of functions.
 
+`strbuf_humanise_bytes`::
+
+       Append the given byte size as a human-readable string (i.e. 12.23 KiB,
+       3.50 MiB).
+
 `strbuf_addf`::
 
        Add a formatted string to the buffer.
index 0e37ec9de51bd4ecb99cecce1958c6cea9bea715..a37f1378d05d6def0ea3cac840acf62875536a70 100644 (file)
@@ -26,7 +26,9 @@ Git pack format
 
      (deltified representation)
      n-byte type and length (3-bit type, (n-1)*7+4-bit length)
-     20-byte base object name
+     20-byte base object name if OBJ_REF_DELTA or a negative relative
+        offset from the delta object's position in the pack if this
+        is an OBJ_OFS_DELTA object
      compressed delta data
 
      Observation: length of each object is encoded in a variable
diff --git a/INSTALL b/INSTALL
index 2dc3b61d1fe1b675377a6ece96feaddf8a0721ba..ba01e7421eb892cfe2b86c4b26786ae9e5bb00af 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -101,7 +101,7 @@ Issues of note:
        - "openssl" library is used by git-imap-send to use IMAP over SSL.
          If you don't need it, use NO_OPENSSL.
 
-         By default, git uses OpenSSL for SHA1 but it will use it's own
+         By default, git uses OpenSSL for SHA1 but it will use its own
          library (inspired by Mozilla's) with either NO_OPENSSL or
          BLK_SHA1.  Also included is a version optimized for PowerPC
          (PPC_SHA1).
index 3bc86260b8a2a809a379c91627f919ef0a529aa1..a8deee6e6419a1e867e06e90a70300cd2e01b556 100644 (file)
--- a/advice.c
+++ b/advice.c
@@ -13,6 +13,7 @@ int advice_commit_before_merge = 1;
 int advice_resolve_conflict = 1;
 int advice_implicit_identity = 1;
 int advice_detached_head = 1;
+int advice_set_upstream_failure = 1;
 
 static struct {
        const char *name;
@@ -31,6 +32,7 @@ static struct {
        { "resolveconflict", &advice_resolve_conflict },
        { "implicitidentity", &advice_implicit_identity },
        { "detachedhead", &advice_detached_head },
+       { "setupstreamfailure", &advice_set_upstream_failure },
 
        /* make this an alias for backward compatibility */
        { "pushnonfastforward", &advice_push_update_rejected }
index af0c983c686b9ca5be2e8631562e60bd19656c22..94caa32f9213f59a627176ec8b4aea022f6b0f8f 100644 (file)
--- a/advice.h
+++ b/advice.h
@@ -16,6 +16,7 @@ extern int advice_commit_before_merge;
 extern int advice_resolve_conflict;
 extern int advice_implicit_identity;
 extern int advice_detached_head;
+extern int advice_set_upstream_failure;
 
 int git_default_advice_config(const char *var, const char *value);
 void advise(const char *advice, ...);
diff --git a/attr.c b/attr.c
index e2f9377891a7f6e0d56803016726e3cd3137fdc2..0e774c6f22f9fd6c7e27490e5bed5be1f9f10de5 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -381,46 +381,13 @@ static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)
        return res;
 }
 
-static void *read_index_data(const char *path)
-{
-       int pos, len;
-       unsigned long sz;
-       enum object_type type;
-       void *data;
-       struct index_state *istate = use_index ? use_index : &the_index;
-
-       len = strlen(path);
-       pos = index_name_pos(istate, path, len);
-       if (pos < 0) {
-               /*
-                * We might be in the middle of a merge, in which
-                * case we would read stage #2 (ours).
-                */
-               int i;
-               for (i = -pos - 1;
-                    (pos < 0 && i < istate->cache_nr &&
-                     !strcmp(istate->cache[i]->name, path));
-                    i++)
-                       if (ce_stage(istate->cache[i]) == 2)
-                               pos = i;
-       }
-       if (pos < 0)
-               return NULL;
-       data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
-       if (!data || type != OBJ_BLOB) {
-               free(data);
-               return NULL;
-       }
-       return data;
-}
-
 static struct attr_stack *read_attr_from_index(const char *path, int macro_ok)
 {
        struct attr_stack *res;
        char *buf, *sp;
        int lineno = 0;
 
-       buf = read_index_data(path);
+       buf = read_blob_data_from_index(use_index ? use_index : &the_index, path, NULL);
        if (!buf)
                return NULL;
 
@@ -657,24 +624,24 @@ static void prepare_attr_stack(const char *path, int dirlen)
 }
 
 static int path_matches(const char *pathname, int pathlen,
-                       const char *basename,
+                       int basename_offset,
                        const struct pattern *pat,
                        const char *base, int baselen)
 {
        const char *pattern = pat->pattern;
        int prefix = pat->nowildcardlen;
+       int isdir = (pathlen && pathname[pathlen - 1] == '/');
 
-       if ((pat->flags & EXC_FLAG_MUSTBEDIR) &&
-           ((!pathlen) || (pathname[pathlen-1] != '/')))
+       if ((pat->flags & EXC_FLAG_MUSTBEDIR) && !isdir)
                return 0;
 
        if (pat->flags & EXC_FLAG_NODIR) {
-               return match_basename(basename,
-                                     pathlen - (basename - pathname),
+               return match_basename(pathname + basename_offset,
+                                     pathlen - basename_offset - isdir,
                                      pattern, prefix,
                                      pat->patternlen, pat->flags);
        }
-       return match_pathname(pathname, pathlen,
+       return match_pathname(pathname, pathlen - isdir,
                              base, baselen,
                              pattern, prefix, pat->patternlen, pat->flags);
 }
@@ -703,7 +670,7 @@ static int fill_one(const char *what, struct match_attr *a, int rem)
        return rem;
 }
 
-static int fill(const char *path, int pathlen, const char *basename,
+static int fill(const char *path, int pathlen, int basename_offset,
                struct attr_stack *stk, int rem)
 {
        int i;
@@ -713,7 +680,7 @@ static int fill(const char *path, int pathlen, const char *basename,
                struct match_attr *a = stk->attrs[i];
                if (a->is_macro)
                        continue;
-               if (path_matches(path, pathlen, basename,
+               if (path_matches(path, pathlen, basename_offset,
                                 &a->u.pat, base, stk->originlen))
                        rem = fill_one("fill", a, rem);
        }
@@ -752,7 +719,8 @@ static void collect_all_attrs(const char *path)
 {
        struct attr_stack *stk;
        int i, pathlen, rem, dirlen;
-       const char *basename, *cp, *last_slash = NULL;
+       const char *cp, *last_slash = NULL;
+       int basename_offset;
 
        for (cp = path; *cp; cp++) {
                if (*cp == '/' && cp[1])
@@ -760,10 +728,10 @@ static void collect_all_attrs(const char *path)
        }
        pathlen = cp - path;
        if (last_slash) {
-               basename = last_slash + 1;
+               basename_offset = last_slash + 1 - path;
                dirlen = last_slash - path;
        } else {
-               basename = path;
+               basename_offset = 0;
                dirlen = 0;
        }
 
@@ -773,7 +741,7 @@ static void collect_all_attrs(const char *path)
 
        rem = attr_nr;
        for (stk = attr_stack; 0 < rem && stk; stk = stk->prev)
-               rem = fill(path, pathlen, basename, stk, rem);
+               rem = fill(path, pathlen, basename_offset, stk, rem);
 }
 
 int git_check_attr(const char *path, int num, struct git_attr_check *check)
index bd1b7b5dac81ada592a16630214d1f2cbb655b88..374d9e24bd0a18b0453f3e948db93251a859ba18 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -525,9 +525,9 @@ struct commit_list *filter_skipped(struct commit_list *list,
  * is increased by one between each call, but that should not matter
  * for this application.
  */
-static int get_prn(int count) {
+static unsigned get_prn(unsigned count) {
        count = count * 1103515245 + 12345;
-       return ((unsigned)(count/65536) % PRN_MODULO);
+       return (count/65536) % PRN_MODULO;
 }
 
 /*
index 2bef1e7e71b7cb3375b3d96fab5c4f20e0c3adff..6ae6a4c321ab8866a3e21f15302b5549a95b4646 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -197,6 +197,20 @@ int validate_new_branchname(const char *name, struct strbuf *ref,
        return 1;
 }
 
+static const char upstream_not_branch[] =
+N_("Cannot setup tracking information; starting point '%s' is not a branch.");
+static const char upstream_missing[] =
+N_("the requested upstream branch '%s' does not exist");
+static const char upstream_advice[] =
+N_("\n"
+"If you are planning on basing your work on an upstream\n"
+"branch that already exists at the remote, you may need to\n"
+"run \"git fetch\" to retrieve it.\n"
+"\n"
+"If you are planning to push out a new local branch that\n"
+"will track its remote counterpart, you may want to use\n"
+"\"git push -u\" to set the upstream config as you push.");
+
 void create_branch(const char *head,
                   const char *name, const char *start_name,
                   int force, int reflog, int clobber_head,
@@ -224,21 +238,30 @@ void create_branch(const char *head,
        }
 
        real_ref = NULL;
-       if (get_sha1(start_name, sha1))
+       if (get_sha1(start_name, sha1)) {
+               if (explicit_tracking) {
+                       if (advice_set_upstream_failure) {
+                               error(_(upstream_missing), start_name);
+                               advise(_(upstream_advice));
+                               exit(1);
+                       }
+                       die(_(upstream_missing), start_name);
+               }
                die("Not a valid object name: '%s'.", start_name);
+       }
 
        switch (dwim_ref(start_name, strlen(start_name), sha1, &real_ref)) {
        case 0:
                /* Not branching from any existing branch */
                if (explicit_tracking)
-                       die("Cannot setup tracking information; starting point is not a branch.");
+                       die(_(upstream_not_branch), start_name);
                break;
        case 1:
                /* Unique completion -- good, only if it is a real branch */
                if (prefixcmp(real_ref, "refs/heads/") &&
                    prefixcmp(real_ref, "refs/remotes/")) {
                        if (explicit_tracking)
-                               die("Cannot setup tracking information; starting point is not a branch.");
+                               die(_(upstream_not_branch), start_name);
                        else
                                real_ref = NULL;
                }
index ab1c9e8fb7a0f7c6f60cc78ff0f345838210459a..daf02c6affb6115d058736a6859ceeb10e0791f0 100644 (file)
@@ -26,8 +26,52 @@ static int take_worktree_changes;
 struct update_callback_data {
        int flags;
        int add_errors;
+       const char *implicit_dot;
+       size_t implicit_dot_len;
 };
 
+static const char *option_with_implicit_dot;
+static const char *short_option_with_implicit_dot;
+
+static void warn_pathless_add(void)
+{
+       static int shown;
+       assert(option_with_implicit_dot && short_option_with_implicit_dot);
+
+       if (shown)
+               return;
+       shown = 1;
+
+       /*
+        * To be consistent with "git add -p" and most Git
+        * commands, we should default to being tree-wide, but
+        * this is not the original behavior and can't be
+        * changed until users trained themselves not to type
+        * "git add -u" or "git add -A". For now, we warn and
+        * keep the old behavior. Later, the behavior can be changed
+        * to tree-wide, keeping the warning for a while, and
+        * eventually we can drop the warning.
+        */
+       warning(_("The behavior of 'git add %s (or %s)' with no path argument from a\n"
+                 "subdirectory of the tree will change in Git 2.0 and should not be used anymore.\n"
+                 "To add content for the whole tree, run:\n"
+                 "\n"
+                 "  git add %s :/\n"
+                 "  (or git add %s :/)\n"
+                 "\n"
+                 "To restrict the command to the current directory, run:\n"
+                 "\n"
+                 "  git add %s .\n"
+                 "  (or git add %s .)\n"
+                 "\n"
+                 "With the current Git version, the command is restricted to "
+                 "the current directory.\n"
+                 ""),
+               option_with_implicit_dot, short_option_with_implicit_dot,
+               option_with_implicit_dot, short_option_with_implicit_dot,
+               option_with_implicit_dot, short_option_with_implicit_dot);
+}
+
 static int fix_unmerged_status(struct diff_filepair *p,
                               struct update_callback_data *data)
 {
@@ -54,10 +98,26 @@ static void update_callback(struct diff_queue_struct *q,
 {
        int i;
        struct update_callback_data *data = cbdata;
+       const char *implicit_dot = data->implicit_dot;
+       size_t implicit_dot_len = data->implicit_dot_len;
 
        for (i = 0; i < q->nr; i++) {
                struct diff_filepair *p = q->queue[i];
                const char *path = p->one->path;
+               /*
+                * Check if "git add -A" or "git add -u" was run from a
+                * subdirectory with a modified file outside that directory,
+                * and warn if so.
+                *
+                * "git add -u" will behave like "git add -u :/" instead of
+                * "git add -u ." in the future.  This warning prepares for
+                * that change.
+                */
+               if (implicit_dot &&
+                   strncmp_icase(path, implicit_dot, implicit_dot_len)) {
+                       warn_pathless_add();
+                       continue;
+               }
                switch (fix_unmerged_status(p, data)) {
                default:
                        die(_("unexpected diff status %c"), p->status);
@@ -85,20 +145,34 @@ int add_files_to_cache(const char *prefix, const char **pathspec, int flags)
 {
        struct update_callback_data data;
        struct rev_info rev;
+
+       memset(&data, 0, sizeof(data));
+       data.flags = flags & ~ADD_CACHE_IMPLICIT_DOT;
+       if ((flags & ADD_CACHE_IMPLICIT_DOT) && prefix) {
+               /*
+                * Check for modified files throughout the worktree so
+                * update_callback has a chance to warn about changes
+                * outside the cwd.
+                */
+               data.implicit_dot = prefix;
+               data.implicit_dot_len = strlen(prefix);
+               pathspec = NULL;
+       }
+
        init_revisions(&rev, prefix);
        setup_revisions(0, NULL, &rev, NULL);
        init_pathspec(&rev.prune_data, pathspec);
        rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
        rev.diffopt.format_callback = update_callback;
-       data.flags = flags;
-       data.add_errors = 0;
        rev.diffopt.format_callback_data = &data;
        rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
        run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
        return !!data.add_errors;
 }
 
-static char *prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)
+#define WARN_IMPLICIT_DOT (1u << 0)
+static char *prune_directory(struct dir_struct *dir, const char **pathspec,
+                            int prefix, unsigned flag)
 {
        char *seen;
        int i, specs;
@@ -115,6 +189,16 @@ static char *prune_directory(struct dir_struct *dir, const char **pathspec, int
                if (match_pathspec(pathspec, entry->name, entry->len,
                                   prefix, seen))
                        *dst++ = entry;
+               else if (flag & WARN_IMPLICIT_DOT)
+                       /*
+                        * "git add -A" was run from a subdirectory with a
+                        * new file outside that directory.
+                        *
+                        * "git add -A" will behave like "git add -A :/"
+                        * instead of "git add -A ." in the future.
+                        * Warn about the coming behavior change.
+                        */
+                       warn_pathless_add();
        }
        dir->nr = dst - dir->entries;
        add_pathspec_matches_against_index(pathspec, seen, specs);
@@ -321,35 +405,6 @@ static int add_files(struct dir_struct *dir, int flags)
        return exit_status;
 }
 
-static void warn_pathless_add(const char *option_name, const char *short_name) {
-       /*
-        * To be consistent with "git add -p" and most Git
-        * commands, we should default to being tree-wide, but
-        * this is not the original behavior and can't be
-        * changed until users trained themselves not to type
-        * "git add -u" or "git add -A". For now, we warn and
-        * keep the old behavior. Later, the behavior can be changed
-        * to tree-wide, keeping the warning for a while, and
-        * eventually we can drop the warning.
-        */
-       warning(_("The behavior of 'git add %s (or %s)' with no path argument from a\n"
-                 "subdirectory of the tree will change in Git 2.0 and should not be used anymore.\n"
-                 "To add content for the whole tree, run:\n"
-                 "\n"
-                 "  git add %s :/\n"
-                 "  (or git add %s :/)\n"
-                 "\n"
-                 "To restrict the command to the current directory, run:\n"
-                 "\n"
-                 "  git add %s .\n"
-                 "  (or git add %s .)\n"
-                 "\n"
-                 "With the current Git version, the command is restricted to the current directory."),
-               option_name, short_name,
-               option_name, short_name,
-               option_name, short_name);
-}
-
 int cmd_add(int argc, const char **argv, const char *prefix)
 {
        int exit_status = 0;
@@ -360,8 +415,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
        int add_new_files;
        int require_pathspec;
        char *seen = NULL;
-       const char *option_with_implicit_dot = NULL;
-       const char *short_option_with_implicit_dot = NULL;
+       int implicit_dot = 0;
 
        git_config(add_config, NULL);
 
@@ -391,11 +445,9 @@ int cmd_add(int argc, const char **argv, const char *prefix)
        }
        if (option_with_implicit_dot && !argc) {
                static const char *here[2] = { ".", NULL };
-               if (prefix)
-                       warn_pathless_add(option_with_implicit_dot,
-                                         short_option_with_implicit_dot);
                argc = 1;
                argv = here;
+               implicit_dot = 1;
        }
 
        add_new_files = !take_worktree_changes && !refresh_only;
@@ -408,7 +460,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
                 (intent_to_add ? ADD_CACHE_INTENT : 0) |
                 (ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
                 (!(addremove || take_worktree_changes)
-                 ? ADD_CACHE_IGNORE_REMOVAL : 0));
+                 ? ADD_CACHE_IGNORE_REMOVAL : 0)) |
+                (implicit_dot ? ADD_CACHE_IMPLICIT_DOT : 0);
 
        if (require_pathspec && argc == 0) {
                fprintf(stderr, _("Nothing specified, nothing added.\n"));
@@ -432,9 +485,10 @@ int cmd_add(int argc, const char **argv, const char *prefix)
                }
 
                /* This picks up the paths that are not tracked */
-               baselen = fill_directory(&dir, pathspec);
+               baselen = fill_directory(&dir, implicit_dot ? NULL : pathspec);
                if (pathspec)
-                       seen = prune_directory(&dir, pathspec, baselen);
+                       seen = prune_directory(&dir, pathspec, baselen,
+                                       implicit_dot ? WARN_IMPLICIT_DOT : 0);
        }
 
        if (refresh_only) {
index 06f5320b18bc5690ae944a722d19ec5496687228..30eefc3c7b390800e9452a06da18208d2fef4f11 100644 (file)
@@ -1921,7 +1921,7 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
 }
 
 /*
- * Read the patch text in "buffer" taht extends for "size" bytes; stop
+ * Read the patch text in "buffer" that extends for "size" bytes; stop
  * reading after seeing a single patch (i.e. changes to a single file).
  * Create fragments (i.e. patch hunks) and hang them to the given patch.
  * Return the number of bytes consumed, so that the caller can call us
@@ -2117,10 +2117,10 @@ static void update_pre_post_images(struct image *preimage,
 
        /*
         * Adjust the common context lines in postimage. This can be
-        * done in-place when we are just doing whitespace fixing,
-        * which does not make the string grow, but needs a new buffer
-        * when ignoring whitespace causes the update, since in this case
-        * we could have e.g. tabs converted to multiple spaces.
+        * done in-place when we are shrinking it with whitespace
+        * fixing, but needs a new buffer when ignoring whitespace or
+        * expanding leading tabs to spaces.
+        *
         * We trust the caller to tell us if the update can be done
         * in place (postlen==0) or not.
         */
@@ -2185,7 +2185,7 @@ static int match_fragment(struct image *img,
        int i;
        char *fixed_buf, *buf, *orig, *target;
        struct strbuf fixed;
-       size_t fixed_len;
+       size_t fixed_len, postlen;
        int preimage_limit;
 
        if (preimage->nr + try_lno <= img->nr) {
@@ -2335,6 +2335,7 @@ static int match_fragment(struct image *img,
        strbuf_init(&fixed, preimage->len + 1);
        orig = preimage->buf;
        target = img->buf + try;
+       postlen = 0;
        for (i = 0; i < preimage_limit; i++) {
                size_t oldlen = preimage->line[i].len;
                size_t tgtlen = img->line[try_lno + i].len;
@@ -2362,6 +2363,7 @@ static int match_fragment(struct image *img,
                match = (tgtfix.len == fixed.len - fixstart &&
                         !memcmp(tgtfix.buf, fixed.buf + fixstart,
                                             fixed.len - fixstart));
+               postlen += tgtfix.len;
 
                strbuf_release(&tgtfix);
                if (!match)
@@ -2399,8 +2401,10 @@ static int match_fragment(struct image *img,
         * hunk match.  Update the context lines in the postimage.
         */
        fixed_buf = strbuf_detach(&fixed, &fixed_len);
+       if (postlen < postimage->len)
+               postlen = 0;
        update_pre_post_images(preimage, postimage,
-                              fixed_buf, fixed_len, 0);
+                              fixed_buf, fixed_len, postlen);
        return 1;
 
  unmatch_exit:
@@ -3025,7 +3029,7 @@ static struct patch *in_fn_table(const char *name)
  *
  * The latter is needed to deal with a case where two paths A and B
  * are swapped by first renaming A to B and then renaming B to A;
- * moving A to B should not be prevented due to presense of B as we
+ * moving A to B should not be prevented due to presence of B as we
  * will remove it in a later patch.
  */
 #define PATH_TO_BE_DELETED ((struct patch *) -2)
@@ -3509,7 +3513,7 @@ static int check_patch(struct patch *patch)
         *
         * A patch to swap-rename between A and B would first rename A
         * to B and then rename B to A.  While applying the first one,
-        * the presense of B should not stop A from getting renamed to
+        * the presence of B should not stop A from getting renamed to
         * B; ask to_be_deleted() about the later rename.  Removal of
         * B and rename from A to B is handled the same way by asking
         * was_deleted().
index e09ce51c2ee59ee4a9f44dbf43c97a2d31911b7b..083689063f66a614ad6f8ee4a84c79e214d1b6e0 100644 (file)
@@ -41,13 +41,15 @@ static char branch_colors[][COLOR_MAXLEN] = {
        GIT_COLOR_RED,          /* REMOTE */
        GIT_COLOR_NORMAL,       /* LOCAL */
        GIT_COLOR_GREEN,        /* CURRENT */
+       GIT_COLOR_BLUE,         /* UPSTREAM */
 };
 enum color_branch {
        BRANCH_COLOR_RESET = 0,
        BRANCH_COLOR_PLAIN = 1,
        BRANCH_COLOR_REMOTE = 2,
        BRANCH_COLOR_LOCAL = 3,
-       BRANCH_COLOR_CURRENT = 4
+       BRANCH_COLOR_CURRENT = 4,
+       BRANCH_COLOR_UPSTREAM = 5
 };
 
 static enum merge_filter {
@@ -72,6 +74,8 @@ static int parse_branch_color_slot(const char *var, int ofs)
                return BRANCH_COLOR_LOCAL;
        if (!strcasecmp(var+ofs, "current"))
                return BRANCH_COLOR_CURRENT;
+       if (!strcasecmp(var+ofs, "upstream"))
+               return BRANCH_COLOR_UPSTREAM;
        return -1;
 }
 
@@ -418,36 +422,52 @@ static void fill_tracking_info(struct strbuf *stat, const char *branch_name,
        int ours, theirs;
        char *ref = NULL;
        struct branch *branch = branch_get(branch_name);
+       struct strbuf fancy = STRBUF_INIT;
 
        if (!stat_tracking_info(branch, &ours, &theirs)) {
                if (branch && branch->merge && branch->merge[0]->dst &&
-                   show_upstream_ref)
-                       strbuf_addf(stat, "[%s] ",
-                           shorten_unambiguous_ref(branch->merge[0]->dst, 0));
+                   show_upstream_ref) {
+                       ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
+                       if (want_color(branch_use_color))
+                               strbuf_addf(stat, "[%s%s%s] ",
+                                               branch_get_color(BRANCH_COLOR_UPSTREAM),
+                                               ref, branch_get_color(BRANCH_COLOR_RESET));
+                       else
+                               strbuf_addf(stat, "[%s] ", ref);
+               }
                return;
        }
 
-       if (show_upstream_ref)
+       if (show_upstream_ref) {
                ref = shorten_unambiguous_ref(branch->merge[0]->dst, 0);
+               if (want_color(branch_use_color))
+                       strbuf_addf(&fancy, "%s%s%s",
+                                       branch_get_color(BRANCH_COLOR_UPSTREAM),
+                                       ref, branch_get_color(BRANCH_COLOR_RESET));
+               else
+                       strbuf_addstr(&fancy, ref);
+       }
+
        if (!ours) {
                if (ref)
-                       strbuf_addf(stat, _("[%s: behind %d]"), ref, theirs);
+                       strbuf_addf(stat, _("[%s: behind %d]"), fancy.buf, theirs);
                else
                        strbuf_addf(stat, _("[behind %d]"), theirs);
 
        } else if (!theirs) {
                if (ref)
-                       strbuf_addf(stat, _("[%s: ahead %d]"), ref, ours);
+                       strbuf_addf(stat, _("[%s: ahead %d]"), fancy.buf, ours);
                else
                        strbuf_addf(stat, _("[ahead %d]"), ours);
        } else {
                if (ref)
                        strbuf_addf(stat, _("[%s: ahead %d, behind %d]"),
-                                   ref, ours, theirs);
+                                   fancy.buf, ours, theirs);
                else
                        strbuf_addf(stat, _("[ahead %d, behind %d]"),
                                    ours, theirs);
        }
+       strbuf_release(&fancy);
        strbuf_addch(stat, ' ');
        free(ref);
 }
@@ -904,7 +924,9 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                if (edit_branch_description(branch_name))
                        return 1;
        } else if (rename) {
-               if (argc == 1)
+               if (!argc)
+                       die(_("branch name required"));
+               else if (argc == 1)
                        rename_branch(head, argv[0], rename > 1);
                else if (argc == 2)
                        rename_branch(argv[0], argv[1], rename > 1);
index a9c1b5a95fea0a805819f995da2d2f1ba194433d..eb51872347d9b7d3e81c37d9ddb4272a99f2b75f 100644 (file)
@@ -271,24 +271,55 @@ static int checkout_paths(const struct checkout_opts *opts,
                ;
        ps_matched = xcalloc(1, pos);
 
+       /*
+        * Make sure all pathspecs participated in locating the paths
+        * to be checked out.
+        */
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
+               ce->ce_flags &= ~CE_MATCHED;
                if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
+                       /*
+                        * "git checkout tree-ish -- path", but this entry
+                        * is in the original index; it will not be checked
+                        * out to the working tree and it does not matter
+                        * if pathspec matched this entry.  We will not do
+                        * anything to this entry at all.
+                        */
                        continue;
-               match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, ps_matched);
+               /*
+                * Either this entry came from the tree-ish we are
+                * checking the paths out of, or we are checking out
+                * of the index.
+                *
+                * If it comes from the tree-ish, we already know it
+                * matches the pathspec and could just stamp
+                * CE_MATCHED to it from update_some(). But we still
+                * need ps_matched and read_tree_recursive (and
+                * eventually tree_entry_interesting) cannot fill
+                * ps_matched yet. Once it can, we can avoid calling
+                * match_pathspec() for _all_ entries when
+                * opts->source_tree != NULL.
+                */
+               if (match_pathspec(opts->pathspec, ce->name, ce_namelen(ce),
+                                  0, ps_matched))
+                       ce->ce_flags |= CE_MATCHED;
        }
 
-       if (report_path_error(ps_matched, opts->pathspec, opts->prefix))
+       if (report_path_error(ps_matched, opts->pathspec, opts->prefix)) {
+               free(ps_matched);
                return 1;
+       }
+       free(ps_matched);
 
        /* "checkout -m path" to recreate conflicted state */
        if (opts->merge)
-               unmerge_cache(opts->pathspec);
+               unmerge_marked_index(&the_index);
 
        /* Any unmerged paths? */
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
-               if (match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
+               if (ce->ce_flags & CE_MATCHED) {
                        if (!ce_stage(ce))
                                continue;
                        if (opts->force) {
@@ -313,9 +344,7 @@ static int checkout_paths(const struct checkout_opts *opts,
        state.refresh_cache = 1;
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
-               if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
-                       continue;
-               if (match_pathspec(opts->pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
+               if (ce->ce_flags & CE_MATCHED) {
                        if (!ce_stage(ce)) {
                                errs |= checkout_entry(ce, &state, NULL);
                                continue;
@@ -700,7 +729,7 @@ static void suggest_reattach(struct commit *commit, struct rev_info *revs)
                        "If you want to keep them by creating a new branch, "
                        "this may be a good time\nto do so with:\n\n"
                        " git branch new_branch_name %s\n\n"),
-                       sha1_to_hex(commit->object.sha1));
+                       find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
 }
 
 /*
index e0aaf13583376c7adf49f504cc9e7e1303fb4a4d..f9c380eb6c536b657ddc65b88f6839ec761f7f25 100644 (file)
@@ -23,6 +23,7 @@
 #include "branch.h"
 #include "remote.h"
 #include "run-command.h"
+#include "connected.h"
 
 /*
  * Overall FIXMEs:
@@ -376,10 +377,32 @@ static void clone_local(const char *src_repo, const char *dest_repo)
 static const char *junk_work_tree;
 static const char *junk_git_dir;
 static pid_t junk_pid;
+enum {
+       JUNK_LEAVE_NONE,
+       JUNK_LEAVE_REPO,
+       JUNK_LEAVE_ALL
+} junk_mode = JUNK_LEAVE_NONE;
+
+static const char junk_leave_repo_msg[] =
+N_("Clone succeeded, but checkout failed.\n"
+   "You can inspect what was checked out with 'git status'\n"
+   "and retry the checkout with 'git checkout -f HEAD'\n");
 
 static void remove_junk(void)
 {
        struct strbuf sb = STRBUF_INIT;
+
+       switch (junk_mode) {
+       case JUNK_LEAVE_REPO:
+               warning("%s", _(junk_leave_repo_msg));
+               /* fall-through */
+       case JUNK_LEAVE_ALL:
+               return;
+       default:
+               /* proceed to removal */
+               break;
+       }
+
        if (getpid() != junk_pid)
                return;
        if (junk_git_dir) {
@@ -485,12 +508,37 @@ static void write_followtags(const struct ref *refs, const char *msg)
        }
 }
 
+static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
+{
+       struct ref **rm = cb_data;
+       struct ref *ref = *rm;
+
+       /*
+        * Skip anything missing a peer_ref, which we are not
+        * actually going to write a ref for.
+        */
+       while (ref && !ref->peer_ref)
+               ref = ref->next;
+       /* Returning -1 notes "end of list" to the caller. */
+       if (!ref)
+               return -1;
+
+       hashcpy(sha1, ref->old_sha1);
+       *rm = ref->next;
+       return 0;
+}
+
 static void update_remote_refs(const struct ref *refs,
                               const struct ref *mapped_refs,
                               const struct ref *remote_head_points_at,
                               const char *branch_top,
                               const char *msg)
 {
+       const struct ref *rm = mapped_refs;
+
+       if (check_everything_connected(iterate_ref_map, 0, &rm))
+               die(_("remote did not send all necessary objects"));
+
        if (refs) {
                write_remote_refs(mapped_refs);
                if (option_single_branch)
@@ -579,7 +627,8 @@ static int checkout(void)
        tree = parse_tree_indirect(sha1);
        parse_tree(tree);
        init_tree_desc(&t, tree->buffer, tree->size);
-       unpack_trees(1, &t, &opts);
+       if (unpack_trees(1, &t, &opts) < 0)
+               die(_("unable to checkout working tree"));
 
        if (write_cache(fd, active_cache, active_nr) ||
            commit_locked_index(lock_file))
@@ -898,12 +947,13 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        transport_unlock_pack(transport);
        transport_disconnect(transport);
 
+       junk_mode = JUNK_LEAVE_REPO;
        err = checkout();
 
        strbuf_release(&reflog_msg);
        strbuf_release(&branch_top);
        strbuf_release(&key);
        strbuf_release(&value);
-       junk_pid = 0;
+       junk_mode = JUNK_LEAVE_ALL;
        return err;
 }
index eac901a0ee15f72eacffea32d1b327c7a336f19c..f641ff2a898cf76d288ed139772e247015ca554b 100644 (file)
@@ -10,7 +10,7 @@
 #include "utf8.h"
 #include "gpg-interface.h"
 
-static const char commit_tree_usage[] = "git commit-tree [(-p <sha1>)...] [-S<signer>] [-m <message>] [-F <file>] <sha1> <changelog";
+static const char commit_tree_usage[] = "git commit-tree [(-p <sha1>)...] [-S[<keyid>]] [-m <message>] [-F <file>] <sha1> <changelog";
 
 static void new_parent(struct commit *parent, struct commit_list **parents_p)
 {
index 3a01a8d08591d93426d436ce2e1e17fccd3ebf78..a7f70cb858e6574562957b739b8a3d42f0353b40 100644 (file)
@@ -79,13 +79,13 @@ static void count_objects(DIR *d, char *path, int len, int verbose,
 }
 
 static char const * const count_objects_usage[] = {
-       N_("git count-objects [-v]"),
+       N_("git count-objects [-v] [-H | --human-readable]"),
        NULL
 };
 
 int cmd_count_objects(int argc, const char **argv, const char *prefix)
 {
-       int i, verbose = 0;
+       int i, verbose = 0, human_readable = 0;
        const char *objdir = get_object_directory();
        int len = strlen(objdir);
        char *path = xmalloc(len + 50);
@@ -93,6 +93,8 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
        off_t loose_size = 0;
        struct option opts[] = {
                OPT__VERBOSE(&verbose, N_("be verbose")),
+               OPT_BOOL('H', "human-readable", &human_readable,
+                        N_("print sizes in human readable format")),
                OPT_END(),
        };
 
@@ -119,6 +121,9 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
                struct packed_git *p;
                unsigned long num_pack = 0;
                off_t size_pack = 0;
+               struct strbuf loose_buf = STRBUF_INIT;
+               struct strbuf pack_buf = STRBUF_INIT;
+               struct strbuf garbage_buf = STRBUF_INIT;
                if (!packed_git)
                        prepare_packed_git();
                for (p = packed_git; p; p = p->next) {
@@ -130,17 +135,40 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
                        size_pack += p->pack_size + p->index_size;
                        num_pack++;
                }
+
+               if (human_readable) {
+                       strbuf_humanise_bytes(&loose_buf, loose_size);
+                       strbuf_humanise_bytes(&pack_buf, size_pack);
+                       strbuf_humanise_bytes(&garbage_buf, size_garbage);
+               } else {
+                       strbuf_addf(&loose_buf, "%lu",
+                                   (unsigned long)(loose_size / 1024));
+                       strbuf_addf(&pack_buf, "%lu",
+                                   (unsigned long)(size_pack / 1024));
+                       strbuf_addf(&garbage_buf, "%lu",
+                                   (unsigned long)(size_garbage / 1024));
+               }
+
                printf("count: %lu\n", loose);
-               printf("size: %lu\n", (unsigned long) (loose_size / 1024));
+               printf("size: %s\n", loose_buf.buf);
                printf("in-pack: %lu\n", packed);
                printf("packs: %lu\n", num_pack);
-               printf("size-pack: %lu\n", (unsigned long) (size_pack / 1024));
+               printf("size-pack: %s\n", pack_buf.buf);
                printf("prune-packable: %lu\n", packed_loose);
                printf("garbage: %lu\n", garbage);
-               printf("size-garbage: %lu\n", (unsigned long) (size_garbage / 1024));
+               printf("size-garbage: %s\n", garbage_buf.buf);
+               strbuf_release(&loose_buf);
+               strbuf_release(&pack_buf);
+               strbuf_release(&garbage_buf);
+       } else {
+               struct strbuf buf = STRBUF_INIT;
+               if (human_readable)
+                       strbuf_humanise_bytes(&buf, loose_size);
+               else
+                       strbuf_addf(&buf, "%lu kilobytes",
+                                   (unsigned long)(loose_size / 1024));
+               printf("%lu objects, %s\n", loose, buf.buf);
+               strbuf_release(&buf);
        }
-       else
-               printf("%lu objects, %lu kilobytes\n",
-                      loose, (unsigned long) (loose_size / 1024));
        return 0;
 }
index d380155d9cf8fedf133dddbae479a910decd55b2..725c0a7dca70ae8cbb31f571e0284f5c31a61cff 100644 (file)
@@ -43,7 +43,7 @@ static int parse_opt_signed_tag_mode(const struct option *opt,
        else if (!strcmp(arg, "strip"))
                signed_tag_mode = STRIP;
        else
-               return error("Unknown signed-tag mode: %s", arg);
+               return error("Unknown signed-tags mode: %s", arg);
        return 0;
 }
 
@@ -420,7 +420,7 @@ static void handle_tag(const char *name, struct tag *tag)
                        switch(signed_tag_mode) {
                        case ABORT:
                                die ("Encountered signed tag %s; use "
-                                    "--signed-tag=<mode> to handle it.",
+                                    "--signed-tags=<mode> to handle it.",
                                     sha1_to_hex(tag->object.sha1));
                        case WARN:
                                warning ("Exporting signed tag %s",
@@ -618,9 +618,12 @@ static void import_marks(char *input_file)
                        || *mark_end != ' ' || get_sha1(mark_end + 1, sha1))
                        die("corrupt mark line: %s", line);
 
+               if (last_idnum < mark)
+                       last_idnum = mark;
+
                object = parse_object(sha1);
                if (!object)
-                       die ("Could not read blob %s", sha1_to_hex(sha1));
+                       continue;
 
                if (object->flags & SHOWN)
                        error("Object %s already has a mark", sha1_to_hex(sha1));
@@ -630,8 +633,6 @@ static void import_marks(char *input_file)
                        continue;
 
                mark_object(object, mark);
-               if (last_idnum < mark)
-                       last_idnum = mark;
 
                object->flags |= SHOWN;
        }
@@ -645,6 +646,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
        struct string_list extra_refs = STRING_LIST_INIT_NODUP;
        struct commit *commit;
        char *export_filename = NULL, *import_filename = NULL;
+       uint32_t lastimportid;
        struct option options[] = {
                OPT_INTEGER(0, "progress", &progress,
                            N_("show progress after <n> objects")),
@@ -688,6 +690,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 
        if (import_filename)
                import_marks(import_filename);
+       lastimportid = last_idnum;
 
        if (import_filename && revs.prune_data.nr)
                full_tree = 1;
@@ -710,7 +713,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 
        handle_tags_and_duplicates(&extra_refs);
 
-       if (export_filename)
+       if (export_filename && lastimportid != last_idnum)
                export_marks(export_filename);
 
        if (use_done_feature)
index 265a9253bfd7cacd730789212fdb5284fcd270ac..1c040708696c8d6e81023b3261966fa751f14ad4 100644 (file)
@@ -287,10 +287,10 @@ static void credit_people(struct strbuf *out,
        const char *me;
 
        if (kind == 'a') {
-               label = "\n# By ";
+               label = "By";
                me = git_author_info(IDENT_NO_DATE);
        } else {
-               label = "\n# Via ";
+               label = "Via";
                me = git_committer_info(IDENT_NO_DATE);
        }
 
@@ -300,7 +300,7 @@ static void credit_people(struct strbuf *out,
             (me = skip_prefix(me, them->items->string)) != NULL &&
             skip_prefix(me, " <")))
                return;
-       strbuf_addstr(out, label);
+       strbuf_addf(out, "\n%c %s ", comment_line_char, label);
        add_people_count(out, them);
 }
 
@@ -503,14 +503,18 @@ static void fmt_merge_msg_sigs(struct strbuf *out)
                } else {
                        if (tag_number == 2) {
                                struct strbuf tagline = STRBUF_INIT;
-                               strbuf_addf(&tagline, "\n# %s\n",
-                                           origins.items[first_tag].string);
+                               strbuf_addch(&tagline, '\n');
+                               strbuf_add_commented_lines(&tagline,
+                                               origins.items[first_tag].string,
+                                               strlen(origins.items[first_tag].string));
                                strbuf_insert(&tagbuf, 0, tagline.buf,
                                              tagline.len);
                                strbuf_release(&tagline);
                        }
-                       strbuf_addf(&tagbuf, "\n# %s\n",
-                                   origins.items[i].string);
+                       strbuf_addch(&tagbuf, '\n');
+                       strbuf_add_commented_lines(&tagbuf,
+                                       origins.items[i].string,
+                                       strlen(origins.items[i].string));
                        fmt_tag_signature(&tagbuf, &sig, buf, len);
                }
                strbuf_release(&sig);
index d1d71816a9df67721578bc29665c15887575caec..062957f629af09db81d78b9cb0be1ce60fd75ec4 100644 (file)
@@ -36,10 +36,12 @@ enum help_format {
 static const char *html_path;
 
 static int show_all = 0;
+static int show_guides = 0;
 static unsigned int colopts;
 static enum help_format help_format = HELP_FORMAT_NONE;
 static struct option builtin_help_options[] = {
-       OPT_BOOLEAN('a', "all", &show_all, N_("print all available commands")),
+       OPT_BOOL('a', "all", &show_all, N_("print all available commands")),
+       OPT_BOOL('g', "guides", &show_guides, N_("print list of useful guides")),
        OPT_SET_INT('m', "man", &help_format, N_("show man page"), HELP_FORMAT_MAN),
        OPT_SET_INT('w', "web", &help_format, N_("show manual in web browser"),
                        HELP_FORMAT_WEB),
@@ -49,7 +51,7 @@ static struct option builtin_help_options[] = {
 };
 
 static const char * const builtin_help_usage[] = {
-       N_("git help [--all] [--man|--web|--info] [command]"),
+       N_("git help [--all] [--guides] [--man|--web|--info] [command]"),
        NULL
 };
 
@@ -413,6 +415,37 @@ static void show_html_page(const char *git_cmd)
        open_html(page_path.buf);
 }
 
+static struct {
+       const char *name;
+       const char *help;
+} common_guides[] = {
+       { "attributes", N_("Defining attributes per path") },
+       { "glossary", N_("A Git glossary") },
+       { "ignore", N_("Specifies intentionally untracked files to ignore") },
+       { "modules", N_("Defining submodule properties") },
+       { "revisions", N_("Specifying revisions and ranges for Git") },
+       { "tutorial", N_("A tutorial introduction to Git (for version 1.5.1 or newer)") },
+       { "workflows", N_("An overview of recommended workflows with Git") },
+};
+
+static void list_common_guides_help(void)
+{
+       int i, longest = 0;
+
+       for (i = 0; i < ARRAY_SIZE(common_guides); i++) {
+               if (longest < strlen(common_guides[i].name))
+                       longest = strlen(common_guides[i].name);
+       }
+
+       puts(_("The common Git guides are:\n"));
+       for (i = 0; i < ARRAY_SIZE(common_guides); i++) {
+               printf("   %s   ", common_guides[i].name);
+               mput_char(' ', longest - strlen(common_guides[i].name));
+               puts(_(common_guides[i].help));
+       }
+       putchar('\n');
+}
+
 int cmd_help(int argc, const char **argv, const char *prefix)
 {
        int nongit;
@@ -428,7 +461,16 @@ int cmd_help(int argc, const char **argv, const char *prefix)
                git_config(git_help_config, NULL);
                printf(_("usage: %s%s"), _(git_usage_string), "\n\n");
                list_commands(colopts, &main_cmds, &other_cmds);
+       }
+
+       if (show_guides)
+               list_common_guides_help();
+
+       if (show_all || show_guides) {
                printf("%s\n", _(git_more_info_string));
+               /*
+               * We're done. Ignore any remaining args
+               */
                return 0;
        }
 
index 59de484bc29a38fb538e1146a91ddef708ebc3cc..ad46f72950f3e4fda292da25f936e48c59705410 100644 (file)
@@ -23,6 +23,7 @@
 #include "streaming.h"
 #include "version.h"
 #include "mailmap.h"
+#include "gpg-interface.h"
 
 /* Set a default date-time format for git log ("log.date" config variable) */
 static const char *default_date_mode = NULL;
@@ -99,9 +100,9 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
        int quiet = 0, source = 0, mailmap = 0;
 
        const struct option builtin_log_options[] = {
-               OPT_BOOLEAN(0, "quiet", &quiet, N_("suppress diff output")),
-               OPT_BOOLEAN(0, "source", &source, N_("show source")),
-               OPT_BOOLEAN(0, "use-mailmap", &mailmap, N_("Use mail map file")),
+               OPT_BOOL(0, "quiet", &quiet, N_("suppress diff output")),
+               OPT_BOOL(0, "source", &source, N_("show source")),
+               OPT_BOOL(0, "use-mailmap", &mailmap, N_("Use mail map file")),
                { OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"),
                  PARSE_OPT_OPTARG, decorate_callback},
                OPT_END()
@@ -367,6 +368,8 @@ static int git_log_config(const char *var, const char *value, void *cb)
 
        if (grep_config(var, value, cb) < 0)
                return -1;
+       if (git_gpg_config(var, value, cb) < 0)
+               return -1;
        return git_diff_ui_config(var, value, cb);
 }
 
@@ -619,6 +622,14 @@ static void add_header(const char *value)
 static int thread;
 static int do_signoff;
 static const char *signature = git_version_string;
+static int config_cover_letter;
+
+enum {
+       COVER_UNSET,
+       COVER_OFF,
+       COVER_ON,
+       COVER_AUTO
+};
 
 static int git_format_config(const char *var, const char *value, void *cb)
 {
@@ -680,6 +691,14 @@ static int git_format_config(const char *var, const char *value, void *cb)
        }
        if (!strcmp(var, "format.signature"))
                return git_config_string(&signature, var, value);
+       if (!strcmp(var, "format.coverletter")) {
+               if (value && !strcasecmp(value, "auto")) {
+                       config_cover_letter = COVER_AUTO;
+                       return 0;
+               }
+               config_cover_letter = git_config_bool(var, value) ? COVER_ON : COVER_OFF;
+               return 0;
+       }
 
        return git_log_config(var, value, cb);
 }
@@ -791,9 +810,37 @@ static void add_branch_description(struct strbuf *buf, const char *branch_name)
        }
 }
 
+static char *find_branch_name(struct rev_info *rev)
+{
+       int i, positive = -1;
+       unsigned char branch_sha1[20];
+       const unsigned char *tip_sha1;
+       const char *ref;
+       char *full_ref, *branch = NULL;
+
+       for (i = 0; i < rev->cmdline.nr; i++) {
+               if (rev->cmdline.rev[i].flags & UNINTERESTING)
+                       continue;
+               if (positive < 0)
+                       positive = i;
+               else
+                       return NULL;
+       }
+       if (positive < 0)
+               return NULL;
+       ref = rev->cmdline.rev[positive].name;
+       tip_sha1 = rev->cmdline.rev[positive].item->sha1;
+       if (dwim_ref(ref, strlen(ref), branch_sha1, &full_ref) &&
+           !prefixcmp(full_ref, "refs/heads/") &&
+           !hashcmp(tip_sha1, branch_sha1))
+               branch = xstrdup(full_ref + strlen("refs/heads/"));
+       free(full_ref);
+       return branch;
+}
+
 static void make_cover_letter(struct rev_info *rev, int use_stdout,
                              struct commit *origin,
-                             int nr, struct commit **list, struct commit *head,
+                             int nr, struct commit **list,
                              const char *branch_name,
                              int quiet)
 {
@@ -807,6 +854,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
        struct diff_options opts;
        int need_8bit_cte = 0;
        struct pretty_print_context pp = {0};
+       struct commit *head = list[0];
 
        if (rev->commit_format != CMIT_FMT_EMAIL)
                die(_("Cover letter needs email format"));
@@ -824,6 +872,9 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
                if (has_non_ascii(list[i]->buffer))
                        need_8bit_cte = 1;
 
+       if (!branch_name)
+               branch_name = find_branch_name(rev);
+
        msg = body;
        pp.fmt = CMIT_FMT_EMAIL;
        pp.date_mode = DATE_RFC2822;
@@ -1030,45 +1081,6 @@ static int cc_callback(const struct option *opt, const char *arg, int unset)
        return 0;
 }
 
-static char *find_branch_name(struct rev_info *rev)
-{
-       int i, positive = -1;
-       unsigned char branch_sha1[20];
-       const unsigned char *tip_sha1;
-       const char *ref;
-       char *full_ref, *branch = NULL;
-
-       for (i = 0; i < rev->cmdline.nr; i++) {
-               if (rev->cmdline.rev[i].flags & UNINTERESTING)
-                       continue;
-               if (positive < 0)
-                       positive = i;
-               else
-                       return NULL;
-       }
-       if (0 <= positive) {
-               ref = rev->cmdline.rev[positive].name;
-               tip_sha1 = rev->cmdline.rev[positive].item->sha1;
-       } else if (!rev->cmdline.nr && rev->pending.nr == 1 &&
-                  !strcmp(rev->pending.objects[0].name, "HEAD")) {
-               /*
-                * No actual ref from command line, but "HEAD" from
-                * rev->def was added in setup_revisions()
-                * e.g. format-patch --cover-letter -12
-                */
-               ref = "HEAD";
-               tip_sha1 = rev->pending.objects[0].item->sha1;
-       } else {
-               return NULL;
-       }
-       if (dwim_ref(ref, strlen(ref), branch_sha1, &full_ref) &&
-           !prefixcmp(full_ref, "refs/heads/") &&
-           !hashcmp(tip_sha1, branch_sha1))
-               branch = xstrdup(full_ref + strlen("refs/heads/"));
-       free(full_ref);
-       return branch;
-}
-
 int cmd_format_patch(int argc, const char **argv, const char *prefix)
 {
        struct commit *commit;
@@ -1080,10 +1092,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        int start_number = -1;
        int just_numbers = 0;
        int ignore_if_in_upstream = 0;
-       int cover_letter = 0;
+       int cover_letter = -1;
        int boundary_count = 0;
        int no_binary_diff = 0;
-       struct commit *origin = NULL, *head = NULL;
+       struct commit *origin = NULL;
        const char *in_reply_to = NULL;
        struct patch_ids ids;
        struct strbuf buf = STRBUF_INIT;
@@ -1098,12 +1110,12 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                { OPTION_CALLBACK, 'N', "no-numbered", &numbered, NULL,
                            N_("use [PATCH] even with multiple patches"),
                            PARSE_OPT_NOARG, no_numbered_callback },
-               OPT_BOOLEAN('s', "signoff", &do_signoff, N_("add Signed-off-by:")),
-               OPT_BOOLEAN(0, "stdout", &use_stdout,
+               OPT_BOOL('s', "signoff", &do_signoff, N_("add Signed-off-by:")),
+               OPT_BOOL(0, "stdout", &use_stdout,
                            N_("print patches to standard out")),
-               OPT_BOOLEAN(0, "cover-letter", &cover_letter,
+               OPT_BOOL(0, "cover-letter", &cover_letter,
                            N_("generate a cover letter")),
-               OPT_BOOLEAN(0, "numbered-files", &just_numbers,
+               OPT_BOOL(0, "numbered-files", &just_numbers,
                            N_("use simple number sequence for output file names")),
                OPT_STRING(0, "suffix", &fmt_patch_suffix, N_("sfx"),
                            N_("use <sfx> instead of '.patch'")),
@@ -1277,28 +1289,36 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
        }
 
        if (rev.pending.nr == 1) {
+               int check_head = 0;
+
                if (rev.max_count < 0 && !rev.show_root_diff) {
                        /*
                         * This is traditional behaviour of "git format-patch
                         * origin" that prepares what the origin side still
                         * does not have.
                         */
-                       unsigned char sha1[20];
-                       const char *ref;
-
                        rev.pending.objects[0].item->flags |= UNINTERESTING;
                        add_head_to_pending(&rev);
-                       ref = resolve_ref_unsafe("HEAD", sha1, 1, NULL);
-                       if (ref && !prefixcmp(ref, "refs/heads/"))
-                               branch_name = xstrdup(ref + strlen("refs/heads/"));
-                       else
-                               branch_name = xstrdup(""); /* no branch */
+                       check_head = 1;
                }
                /*
                 * Otherwise, it is "format-patch -22 HEAD", and/or
                 * "format-patch --root HEAD".  The user wants
                 * get_revision() to do the usual traversal.
                 */
+
+               if (!strcmp(rev.pending.objects[0].name, "HEAD"))
+                       check_head = 1;
+
+               if (check_head) {
+                       unsigned char sha1[20];
+                       const char *ref;
+                       ref = resolve_ref_unsafe("HEAD", sha1, 1, NULL);
+                       if (ref && !prefixcmp(ref, "refs/heads/"))
+                               branch_name = xstrdup(ref + strlen("refs/heads/"));
+                       else
+                               branch_name = xstrdup(""); /* no branch */
+               }
        }
 
        /*
@@ -1307,29 +1327,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
         */
        rev.show_root_diff = 1;
 
-       if (cover_letter) {
-               /*
-                * NEEDSWORK:randomly pick one positive commit to show
-                * diffstat; this is often the tip and the command
-                * happens to do the right thing in most cases, but a
-                * complex command like "--cover-letter a b c ^bottom"
-                * picks "c" and shows diffstat between bottom..c
-                * which may not match what the series represents at
-                * all and totally broken.
-                */
-               int i;
-               for (i = 0; i < rev.pending.nr; i++) {
-                       struct object *o = rev.pending.objects[i].item;
-                       if (!(o->flags & UNINTERESTING))
-                               head = (struct commit *)o;
-               }
-               /* There is nothing to show; it is not an error, though. */
-               if (!head)
-                       return 0;
-               if (!branch_name)
-                       branch_name = find_branch_name(&rev);
-       }
-
        if (ignore_if_in_upstream) {
                /* Don't say anything if head and upstream are the same. */
                if (rev.pending.nr == 2) {
@@ -1361,11 +1358,21 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                list = xrealloc(list, nr * sizeof(list[0]));
                list[nr - 1] = commit;
        }
+       if (nr == 0)
+               /* nothing to do */
+               return 0;
        total = nr;
        if (!keep_subject && auto_number && total > 1)
                numbered = 1;
        if (numbered)
                rev.total = total + start_number - 1;
+       if (cover_letter == -1) {
+               if (config_cover_letter == COVER_AUTO)
+                       cover_letter = (total > 1);
+               else
+                       cover_letter = (config_cover_letter == COVER_ON);
+       }
+
        if (in_reply_to || thread || cover_letter)
                rev.ref_message_ids = xcalloc(1, sizeof(struct string_list));
        if (in_reply_to) {
@@ -1378,7 +1385,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                if (thread)
                        gen_message_id(&rev, "cover");
                make_cover_letter(&rev, use_stdout,
-                                 origin, nr, list, head, branch_name, quiet);
+                                 origin, nr, list, branch_name, quiet);
                total++;
                start_number--;
        }
index bc912e399efa295615e9bfaac0de03904edff367..ed25d81b880eb830481d4e729d7e9acc3266de65 100644 (file)
@@ -155,6 +155,11 @@ static int same_entry(struct name_entry *a, struct name_entry *b)
                a->mode == b->mode;
 }
 
+static int both_empty(struct name_entry *a, struct name_entry *b)
+{
+       return !(a->sha1 || b->sha1);
+}
+
 static struct merge_list *create_entry(unsigned stage, unsigned mode, const unsigned char *sha1, const char *path)
 {
        struct merge_list *res = xcalloc(1, sizeof(*res));
@@ -297,13 +302,10 @@ static void unresolved(const struct traverse_info *info, struct name_entry n[3])
 static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, struct name_entry *entry, struct traverse_info *info)
 {
        /* Same in both? */
-       if (same_entry(entry+1, entry+2)) {
-               if (entry[0].sha1) {
-                       /* Modified identically */
-                       resolve(info, NULL, entry+1);
-                       return mask;
-               }
-               /* "Both added the same" is left unresolved */
+       if (same_entry(entry+1, entry+2) || both_empty(entry+0, entry+2)) {
+               /* Modified, added or removed identically */
+               resolve(info, NULL, entry+1);
+               return mask;
        }
 
        if (same_entry(entry+0, entry+1)) {
@@ -319,12 +321,10 @@ static int threeway_callback(int n, unsigned long mask, unsigned long dirmask, s
                 */
        }
 
-       if (same_entry(entry+0, entry+2)) {
-               if (entry[1].sha1 && !S_ISDIR(entry[1].mode)) {
-                       /* We modified, they did not touch -- take ours */
-                       resolve(info, NULL, entry+1);
-                       return mask;
-               }
+       if (same_entry(entry+0, entry+2) || both_empty(entry+0, entry+2)) {
+               /* We added, modified or removed, they did not touch -- take ours */
+               resolve(info, NULL, entry+1);
+               return mask;
        }
 
        unresolved(info, entry);
index 7c8922c8b0b44307a0dbb43329301ad7d1654a46..3e2daa37c367560450217cfae5cbb717bfb508af 100644 (file)
@@ -49,7 +49,7 @@ static const char * const builtin_merge_usage[] = {
 static int show_diffstat = 1, shortlog_len = -1, squash;
 static int option_commit = 1, allow_fast_forward = 1;
 static int fast_forward_only, option_edit = -1;
-static int allow_trivial = 1, have_message;
+static int allow_trivial = 1, have_message, verify_signatures;
 static int overwrite_ignore = 1;
 static struct strbuf merge_msg = STRBUF_INIT;
 static struct strategy **use_strategies;
@@ -199,6 +199,8 @@ static struct option builtin_merge_options[] = {
        OPT_BOOLEAN(0, "ff-only", &fast_forward_only,
                N_("abort if fast-forward is not possible")),
        OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
+       OPT_BOOL(0, "verify-signatures", &verify_signatures,
+               N_("Verify that the named commit has a valid GPG signature")),
        OPT_CALLBACK('s', "strategy", &use_strategies, N_("strategy"),
                N_("merge strategy to use"), option_parse_strategy),
        OPT_CALLBACK('X', "strategy-option", &xopts, N_("option=value"),
@@ -516,6 +518,19 @@ static void merge_name(const char *remote, struct strbuf *msg)
                strbuf_release(&line);
                goto cleanup;
        }
+
+       if (remote_head->util) {
+               struct merge_remote_desc *desc;
+               desc = merge_remote_util(remote_head);
+               if (desc && desc->obj && desc->obj->type == OBJ_TAG) {
+                       strbuf_addf(msg, "%s\t\t%s '%s'\n",
+                                   sha1_to_hex(desc->obj->sha1),
+                                   typename(desc->obj->type),
+                                   remote);
+                       goto cleanup;
+               }
+       }
+
        strbuf_addf(msg, "%s\t\tcommit '%s'\n",
                sha1_to_hex(remote_head->object.sha1), remote);
 cleanup:
@@ -1233,6 +1248,39 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                usage_with_options(builtin_merge_usage,
                        builtin_merge_options);
 
+       if (verify_signatures) {
+               for (p = remoteheads; p; p = p->next) {
+                       struct commit *commit = p->item;
+                       char hex[41];
+                       struct signature_check signature_check;
+                       memset(&signature_check, 0, sizeof(signature_check));
+
+                       check_commit_signature(commit, &signature_check);
+
+                       strcpy(hex, find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
+                       switch (signature_check.result) {
+                       case 'G':
+                               break;
+                       case 'U':
+                               die(_("Commit %s has an untrusted GPG signature, "
+                                     "allegedly by %s."), hex, signature_check.signer);
+                       case 'B':
+                               die(_("Commit %s has a bad GPG signature "
+                                     "allegedly by %s."), hex, signature_check.signer);
+                       default: /* 'N' */
+                               die(_("Commit %s does not have a GPG signature."), hex);
+                       }
+                       if (verbosity >= 0 && signature_check.result == 'G')
+                               printf(_("Commit %s has a good GPG signature by %s\n"),
+                                      hex, signature_check.signer);
+
+                       free(signature_check.gpg_output);
+                       free(signature_check.gpg_status);
+                       free(signature_check.signer);
+                       free(signature_check.key);
+               }
+       }
+
        strbuf_addstr(&buf, "merge");
        for (p = remoteheads; p; p = p->next)
                strbuf_addf(&buf, " %s", merge_remote_util(p->item)->name);
index 5e4a0e958f3649c5a5a9f317876e8afd6f6bea6f..909c34dfda984be86fba2013fedc3fdb10b5e2f1 100644 (file)
@@ -322,7 +322,7 @@ static int push_with_options(struct transport *transport, int flags)
 static int do_push(const char *repo, int flags)
 {
        int i, errs;
-       struct remote *remote = remote_get(repo);
+       struct remote *remote = pushremote_get(repo);
        const char **url;
        int url_nr;
 
index dabfcf689068804f2b352d200b35770b467a27e8..7b91d52f39004dbfcc9b0dc5b8aadf3df5c6d320 100644 (file)
@@ -110,7 +110,7 @@ static int check_local_mod(unsigned char *head, int index_only)
                ce = active_cache[pos];
 
                if (lstat(ce->name, &st) < 0) {
-                       if (errno != ENOENT)
+                       if (errno != ENOENT && errno != ENOTDIR)
                                warning("'%s': %s", ce->name, strerror(errno));
                        /* It already vanished from the working tree */
                        continue;
index d208fd6c6821c729a713edb485a20bbe8d5e2692..90fc6b1b9d2a397ae43dfc4c0aba6bc192c9823c 100644 (file)
@@ -162,29 +162,28 @@ static void name_commits(struct commit_list *list,
                        nth = 0;
                        while (parents) {
                                struct commit *p = parents->item;
-                               char newname[1000], *en;
+                               struct strbuf newname = STRBUF_INIT;
                                parents = parents->next;
                                nth++;
                                if (p->util)
                                        continue;
-                               en = newname;
                                switch (n->generation) {
                                case 0:
-                                       en += sprintf(en, "%s", n->head_name);
+                                       strbuf_addstr(&newname, n->head_name);
                                        break;
                                case 1:
-                                       en += sprintf(en, "%s^", n->head_name);
+                                       strbuf_addf(&newname, "%s^", n->head_name);
                                        break;
                                default:
-                                       en += sprintf(en, "%s~%d",
-                                               n->head_name, n->generation);
+                                       strbuf_addf(&newname, "%s~%d",
+                                                   n->head_name, n->generation);
                                        break;
                                }
                                if (nth == 1)
-                                       en += sprintf(en, "^");
+                                       strbuf_addch(&newname, '^');
                                else
-                                       en += sprintf(en, "^%d", nth);
-                               name_commit(p, xstrdup(newname), 0);
+                                       strbuf_addf(&newname, "^%d", nth);
+                               name_commit(p, strbuf_detach(&newname, NULL), 0);
                                i++;
                                name_first_parent_chain(p);
                        }
index 505e07e93468b68454c7ec906f40eacea9746551..4b0e5cd51b82f916c26d3776f81f22cdb3045fa6 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -57,7 +57,7 @@ static int parse_bundle_header(int fd, struct bundle_header *header,
                 * followed by SP and subject line.
                 */
                if (get_sha1_hex(buf.buf, sha1) ||
-                   (40 <= buf.len && !isspace(buf.buf[40])) ||
+                   (buf.len > 40 && !isspace(buf.buf[40])) ||
                    (!is_prereq && buf.len <= 40)) {
                        if (report_path)
                                error(_("unrecognized header: %s%s (%d)"),
diff --git a/cache.h b/cache.h
index ec2fd7a30431acb23f00f05e930ab441a244e18b..94ca1acf704bd2dfdc561b6b2d3d64740b975f61 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -162,6 +162,9 @@ struct cache_entry {
 #define CE_UNPACKED          (1 << 24)
 #define CE_NEW_SKIP_WORKTREE (1 << 25)
 
+/* used to temporarily mark paths matched by pathspecs */
+#define CE_MATCHED           (1 << 26)
+
 /*
  * Extended on-disk flags
  */
@@ -308,6 +311,7 @@ extern void free_name_hash(struct index_state *istate);
 #define resolve_undo_clear() resolve_undo_clear_index(&the_index)
 #define unmerge_cache_entry_at(at) unmerge_index_entry_at(&the_index, at)
 #define unmerge_cache(pathspec) unmerge_index(&the_index, pathspec)
+#define read_blob_data_from_cache(path, sz) read_blob_data_from_index(&the_index, (path), (sz))
 #endif
 
 enum object_type {
@@ -462,11 +466,13 @@ extern int remove_file_from_index(struct index_state *, const char *path);
 #define ADD_CACHE_IGNORE_ERRORS        4
 #define ADD_CACHE_IGNORE_REMOVAL 8
 #define ADD_CACHE_INTENT 16
+#define ADD_CACHE_IMPLICIT_DOT 32      /* internal to "git add -u/-A" */
 extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
 extern int add_file_to_index(struct index_state *, const char *path, int flags);
 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 index_name_is_other(const struct index_state *, const char *, int);
+extern void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);
 
 /* do stat comparison even if CE_VALID is true */
 #define CE_MATCH_IGNORE_VALID          01
@@ -716,8 +722,7 @@ enum sharedrepo {
        PERM_EVERYBODY      = 0664
 };
 int git_config_perm(const char *var, const char *value);
-int set_shared_perm(const char *path, int mode);
-#define adjust_shared_perm(path) set_shared_perm((path), 0)
+int adjust_shared_perm(const char *path);
 int safe_create_leading_directories(char *path);
 int safe_create_leading_directories_const(const char *path);
 int mkdir_in_gitdir(const char *path);
index 6288485965b5f79c1311e48e8de5c1be97730977..77d7872aafe659045e9ec228de97e87c9cea00a1 100644 (file)
@@ -74,16 +74,24 @@ static struct combine_diff_path *intersect_paths(struct combine_diff_path *curr,
 
 /* Lines lost from parent */
 struct lline {
-       struct lline *next;
+       struct lline *next, *prev;
        int len;
        unsigned long parent_map;
        char line[FLEX_ARRAY];
 };
 
+/* Lines lost from current parent (before coalescing) */
+struct plost {
+       struct lline *lost_head, *lost_tail;
+       int len;
+};
+
 /* Lines surviving in the merge result */
 struct sline {
-       struct lline *lost_head, **lost_tail;
-       struct lline *next_lost;
+       /* Accumulated and coalesced lost lines */
+       struct lline *lost;
+       int lenlost;
+       struct plost plost;
        char *bol;
        int len;
        /* bit 0 up to (N-1) are on if the parent has this line (i.e.
@@ -95,34 +103,6 @@ struct sline {
        unsigned long *p_lno;
 };
 
-static char *grab_blob(const unsigned char *sha1, unsigned int mode,
-                      unsigned long *size, struct userdiff_driver *textconv,
-                      const char *path)
-{
-       char *blob;
-       enum object_type type;
-
-       if (S_ISGITLINK(mode)) {
-               blob = xmalloc(100);
-               *size = snprintf(blob, 100,
-                                "Subproject commit %s\n", sha1_to_hex(sha1));
-       } else if (is_null_sha1(sha1)) {
-               /* deleted blob */
-               *size = 0;
-               return xcalloc(1, 1);
-       } else if (textconv) {
-               struct diff_filespec *df = alloc_filespec(path);
-               fill_filespec(df, sha1, 1, mode);
-               *size = fill_textconv(textconv, df, &blob);
-               free_filespec(df);
-       } else {
-               blob = read_sha1_file(sha1, &type, size);
-               if (type != OBJ_BLOB)
-                       die("object '%s' is not a blob!", sha1_to_hex(sha1));
-       }
-       return blob;
-}
-
 static int match_string_spaces(const char *line1, int len1,
                               const char *line2, int len2,
                               long flags)
@@ -163,36 +143,180 @@ static int match_string_spaces(const char *line1, int len1,
        return 0;
 }
 
-static void append_lost(struct sline *sline, int n, const char *line, int len, long flags)
+enum coalesce_direction { MATCH, BASE, NEW };
+
+/* Coalesce new lines into base by finding LCS */
+static struct lline *coalesce_lines(struct lline *base, int *lenbase,
+                                   struct lline *new, int lennew,
+                                   unsigned long parent, long flags)
 {
-       struct lline *lline;
-       unsigned long this_mask = (1UL<<n);
-       if (line[len-1] == '\n')
-               len--;
+       int **lcs;
+       enum coalesce_direction **directions;
+       struct lline *baseend, *newend = NULL;
+       int i, j, origbaselen = *lenbase;
 
-       /* Check to see if we can squash things */
-       if (sline->lost_head) {
-               lline = sline->next_lost;
-               while (lline) {
-                       if (match_string_spaces(lline->line, lline->len,
-                                               line, len, flags)) {
-                               lline->parent_map |= this_mask;
-                               sline->next_lost = lline->next;
-                               return;
+       if (new == NULL)
+               return base;
+
+       if (base == NULL) {
+               *lenbase = lennew;
+               return new;
+       }
+
+       /*
+        * Coalesce new lines into base by finding the LCS
+        * - Create the table to run dynamic programing
+        * - Compute the LCS
+        * - Then reverse read the direction structure:
+        *   - If we have MATCH, assign parent to base flag, and consume
+        *   both baseend and newend
+        *   - Else if we have BASE, consume baseend
+        *   - Else if we have NEW, insert newend lline into base and
+        *   consume newend
+        */
+       lcs = xcalloc(origbaselen + 1, sizeof(int*));
+       directions = xcalloc(origbaselen + 1, sizeof(enum coalesce_direction*));
+       for (i = 0; i < origbaselen + 1; i++) {
+               lcs[i] = xcalloc(lennew + 1, sizeof(int));
+               directions[i] = xcalloc(lennew + 1, sizeof(enum coalesce_direction));
+               directions[i][0] = BASE;
+       }
+       for (j = 1; j < lennew + 1; j++)
+               directions[0][j] = NEW;
+
+       for (i = 1, baseend = base; i < origbaselen + 1; i++) {
+               for (j = 1, newend = new; j < lennew + 1; j++) {
+                       if (match_string_spaces(baseend->line, baseend->len,
+                                               newend->line, newend->len, flags)) {
+                               lcs[i][j] = lcs[i - 1][j - 1] + 1;
+                               directions[i][j] = MATCH;
+                       } else if (lcs[i][j - 1] >= lcs[i - 1][j]) {
+                               lcs[i][j] = lcs[i][j - 1];
+                               directions[i][j] = NEW;
+                       } else {
+                               lcs[i][j] = lcs[i - 1][j];
+                               directions[i][j] = BASE;
+                       }
+                       if (newend->next)
+                               newend = newend->next;
+               }
+               if (baseend->next)
+                       baseend = baseend->next;
+       }
+
+       for (i = 0; i < origbaselen + 1; i++)
+               free(lcs[i]);
+       free(lcs);
+
+       /* At this point, baseend and newend point to the end of each lists */
+       i--;
+       j--;
+       while (i != 0 || j != 0) {
+               if (directions[i][j] == MATCH) {
+                       baseend->parent_map |= 1<<parent;
+                       baseend = baseend->prev;
+                       newend = newend->prev;
+                       i--;
+                       j--;
+               } else if (directions[i][j] == NEW) {
+                       struct lline *lline;
+
+                       lline = newend;
+                       /* Remove lline from new list and update newend */
+                       if (lline->prev)
+                               lline->prev->next = lline->next;
+                       else
+                               new = lline->next;
+                       if (lline->next)
+                               lline->next->prev = lline->prev;
+
+                       newend = lline->prev;
+                       j--;
+
+                       /* Add lline to base list */
+                       if (baseend) {
+                               lline->next = baseend->next;
+                               lline->prev = baseend;
+                               if (lline->prev)
+                                       lline->prev->next = lline;
                        }
-                       lline = lline->next;
+                       else {
+                               lline->next = base;
+                               base = lline;
+                       }
+                       (*lenbase)++;
+
+                       if (lline->next)
+                               lline->next->prev = lline;
+
+               } else {
+                       baseend = baseend->prev;
+                       i--;
                }
        }
 
+       newend = new;
+       while (newend) {
+               struct lline *lline = newend;
+               newend = newend->next;
+               free(lline);
+       }
+
+       for (i = 0; i < origbaselen + 1; i++)
+               free(directions[i]);
+       free(directions);
+
+       return base;
+}
+
+static char *grab_blob(const unsigned char *sha1, unsigned int mode,
+                      unsigned long *size, struct userdiff_driver *textconv,
+                      const char *path)
+{
+       char *blob;
+       enum object_type type;
+
+       if (S_ISGITLINK(mode)) {
+               blob = xmalloc(100);
+               *size = snprintf(blob, 100,
+                                "Subproject commit %s\n", sha1_to_hex(sha1));
+       } else if (is_null_sha1(sha1)) {
+               /* deleted blob */
+               *size = 0;
+               return xcalloc(1, 1);
+       } else if (textconv) {
+               struct diff_filespec *df = alloc_filespec(path);
+               fill_filespec(df, sha1, 1, mode);
+               *size = fill_textconv(textconv, df, &blob);
+               free_filespec(df);
+       } else {
+               blob = read_sha1_file(sha1, &type, size);
+               if (type != OBJ_BLOB)
+                       die("object '%s' is not a blob!", sha1_to_hex(sha1));
+       }
+       return blob;
+}
+
+static void append_lost(struct sline *sline, int n, const char *line, int len)
+{
+       struct lline *lline;
+       unsigned long this_mask = (1UL<<n);
+       if (line[len-1] == '\n')
+               len--;
+
        lline = xmalloc(sizeof(*lline) + len + 1);
        lline->len = len;
        lline->next = NULL;
+       lline->prev = sline->plost.lost_tail;
+       if (lline->prev)
+               lline->prev->next = lline;
+       else
+               sline->plost.lost_head = lline;
+       sline->plost.lost_tail = lline;
+       sline->plost.len++;
        lline->parent_map = this_mask;
        memcpy(lline->line, line, len);
        lline->line[len] = 0;
-       *sline->lost_tail = lline;
-       sline->lost_tail = &lline->next;
-       sline->next_lost = NULL;
 }
 
 struct combine_diff_state {
@@ -203,7 +327,6 @@ struct combine_diff_state {
        int n;
        struct sline *sline;
        struct sline *lost_bucket;
-       long flags;
 };
 
 static void consume_line(void *state_, char *line, unsigned long len)
@@ -236,14 +359,13 @@ static void consume_line(void *state_, char *line, unsigned long len)
                                xcalloc(state->num_parent,
                                        sizeof(unsigned long));
                state->sline[state->nb-1].p_lno[state->n] = state->ob;
-               state->lost_bucket->next_lost = state->lost_bucket->lost_head;
                return;
        }
        if (!state->lost_bucket)
                return; /* not in any hunk yet */
        switch (line[0]) {
        case '-':
-               append_lost(state->lost_bucket, state->n, line+1, len-1, state->flags);
+               append_lost(state->lost_bucket, state->n, line+1, len-1);
                break;
        case '+':
                state->sline[state->lno-1].flag |= state->nmask;
@@ -276,7 +398,6 @@ static void combine_diff(const unsigned char *parent, unsigned int mode,
        xpp.flags = flags;
        memset(&xecfg, 0, sizeof(xecfg));
        memset(&state, 0, sizeof(state));
-       state.flags = flags;
        state.nmask = nmask;
        state.sline = sline;
        state.lno = 1;
@@ -298,8 +419,18 @@ static void combine_diff(const unsigned char *parent, unsigned int mode,
                struct lline *ll;
                sline[lno].p_lno[n] = p_lno;
 
+               /* Coalesce new lines */
+               if (sline[lno].plost.lost_head) {
+                       struct sline *sl = &sline[lno];
+                       sl->lost = coalesce_lines(sl->lost, &sl->lenlost,
+                                                 sl->plost.lost_head,
+                                                 sl->plost.len, n, flags);
+                       sl->plost.lost_head = sl->plost.lost_tail = NULL;
+                       sl->plost.len = 0;
+               }
+
                /* How many lines would this sline advance the p_lno? */
-               ll = sline[lno].lost_head;
+               ll = sline[lno].lost;
                while (ll) {
                        if (ll->parent_map & nmask)
                                p_lno++; /* '-' means parent had it */
@@ -319,7 +450,7 @@ static int interesting(struct sline *sline, unsigned long all_mask)
        /* If some parents lost lines here, or if we have added to
         * some parent, it is interesting.
         */
-       return ((sline->flag & all_mask) || sline->lost_head);
+       return ((sline->flag & all_mask) || sline->lost);
 }
 
 static unsigned long adjust_hunk_tail(struct sline *sline,
@@ -502,7 +633,7 @@ static int make_hunks(struct sline *sline, unsigned long cnt,
                has_interesting = 0;
                for (j = i; j < hunk_end && !has_interesting; j++) {
                        unsigned long this_diff = sline[j].flag & all_mask;
-                       struct lline *ll = sline[j].lost_head;
+                       struct lline *ll = sline[j].lost;
                        if (this_diff) {
                                /* This has some changes.  Is it the
                                 * same as others?
@@ -656,7 +787,7 @@ static void dump_sline(struct sline *sline, const char *line_prefix,
                        int j;
                        unsigned long p_mask;
                        struct sline *sl = &sline[lno++];
-                       ll = (sl->flag & no_pre_delete) ? NULL : sl->lost_head;
+                       ll = (sl->flag & no_pre_delete) ? NULL : sl->lost;
                        while (ll) {
                                printf("%s%s", line_prefix, c_old);
                                for (j = 0; j < num_parent; j++) {
@@ -707,7 +838,7 @@ static void reuse_combine_diff(struct sline *sline, unsigned long cnt,
        jmask = (1UL<<j);
 
        for (lno = 0; lno <= cnt; lno++) {
-               struct lline *ll = sline->lost_head;
+               struct lline *ll = sline->lost;
                sline->p_lno[i] = sline->p_lno[j];
                while (ll) {
                        if (ll->parent_map & jmask)
@@ -966,10 +1097,6 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
 
        sline = xcalloc(cnt+2, sizeof(*sline));
        sline[0].bol = result;
-       for (lno = 0; lno <= cnt + 1; lno++) {
-               sline[lno].lost_tail = &sline[lno].lost_head;
-               sline[lno].flag = 0;
-       }
        for (lno = 0, cp = result; cp < result + result_size; cp++) {
                if (*cp == '\n') {
                        sline[lno].len = cp - sline[lno].bol;
@@ -1019,8 +1146,8 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
        free(result);
 
        for (lno = 0; lno < cnt; lno++) {
-               if (sline[lno].lost_head) {
-                       struct lline *ll = sline[lno].lost_head;
+               if (sline[lno].lost) {
+                       struct lline *ll = sline[lno].lost;
                        while (ll) {
                                struct lline *tmp = ll;
                                ll = ll->next;
index b4512ab0b2ebd008aa90e0dfe00fbc1aa42a5c64..888e02ae2f65ab566555465e5d88d02bbe52420f 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -841,7 +841,7 @@ struct commit_list *get_merge_bases(struct commit *one, struct commit *two,
 }
 
 /*
- * Is "commit" a decendant of one of the elements on the "with_commit" list?
+ * Is "commit" a descendant of one of the elements on the "with_commit" list?
  */
 int is_descendant_of(struct commit *commit, struct commit_list *with_commit)
 {
@@ -1041,6 +1041,76 @@ static void handle_signed_tag(struct commit *parent, struct commit_extra_header
        free(buf);
 }
 
+static struct {
+       char result;
+       const char *check;
+} sigcheck_gpg_status[] = {
+       { 'G', "\n[GNUPG:] GOODSIG " },
+       { 'B', "\n[GNUPG:] BADSIG " },
+       { 'U', "\n[GNUPG:] TRUST_NEVER" },
+       { 'U', "\n[GNUPG:] TRUST_UNDEFINED" },
+};
+
+static void parse_gpg_output(struct signature_check *sigc)
+{
+       const char *buf = sigc->gpg_status;
+       int i;
+
+       /* Iterate over all search strings */
+       for (i = 0; i < ARRAY_SIZE(sigcheck_gpg_status); i++) {
+               const char *found, *next;
+
+               if (!prefixcmp(buf, sigcheck_gpg_status[i].check + 1)) {
+                       /* At the very beginning of the buffer */
+                       found = buf + strlen(sigcheck_gpg_status[i].check + 1);
+               } else {
+                       found = strstr(buf, sigcheck_gpg_status[i].check);
+                       if (!found)
+                               continue;
+                       found += strlen(sigcheck_gpg_status[i].check);
+               }
+               sigc->result = sigcheck_gpg_status[i].result;
+               /* The trust messages are not followed by key/signer information */
+               if (sigc->result != 'U') {
+                       sigc->key = xmemdupz(found, 16);
+                       found += 17;
+                       next = strchrnul(found, '\n');
+                       sigc->signer = xmemdupz(found, next - found);
+               }
+       }
+}
+
+void check_commit_signature(const struct commit* commit, struct signature_check *sigc)
+{
+       struct strbuf payload = STRBUF_INIT;
+       struct strbuf signature = STRBUF_INIT;
+       struct strbuf gpg_output = STRBUF_INIT;
+       struct strbuf gpg_status = STRBUF_INIT;
+       int status;
+
+       sigc->result = 'N';
+
+       if (parse_signed_commit(commit->object.sha1,
+                               &payload, &signature) <= 0)
+               goto out;
+       status = verify_signed_buffer(payload.buf, payload.len,
+                                     signature.buf, signature.len,
+                                     &gpg_output, &gpg_status);
+       if (status && !gpg_output.len)
+               goto out;
+       sigc->gpg_output = strbuf_detach(&gpg_output, NULL);
+       sigc->gpg_status = strbuf_detach(&gpg_status, NULL);
+       parse_gpg_output(sigc);
+
+ out:
+       strbuf_release(&gpg_status);
+       strbuf_release(&gpg_output);
+       strbuf_release(&payload);
+       strbuf_release(&signature);
+}
+
+
+
 void append_merge_tag_headers(struct commit_list *parents,
                              struct commit_extra_header ***tail)
 {
index 2d90d9c27c8fb947e30a368cb5fb266f643b8bae..057ff8045efb2cc80f747ee15b2a308a6dead5e5 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -5,6 +5,7 @@
 #include "tree.h"
 #include "strbuf.h"
 #include "decorate.h"
+#include "gpg-interface.h"
 
 struct commit_list {
        struct commit *item;
@@ -165,7 +166,7 @@ extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *r
 extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos, int cleanup);
 extern struct commit_list *get_octopus_merge_bases(struct commit_list *in);
 
-/* largest postive number a signed 32-bit integer can contain */
+/* largest positive number a signed 32-bit integer can contain */
 #define INFINITE_DEPTH 0x7fffffff
 
 extern int register_shallow(const unsigned char *sha1);
@@ -232,4 +233,13 @@ extern void print_commit_list(struct commit_list *list,
                              const char *format_cur,
                              const char *format_last);
 
+/*
+ * Check the signature of the given commit. The result of the check is stored
+ * in sig->check_result, 'G' for a good signature, 'U' for a good signature
+ * from an untrusted signer, 'B' for a bad signature and 'N' for no signature
+ * at all.  This may allocate memory for sig->gpg_output, sig->gpg_status,
+ * sig->signer and sig->key.
+ */
+extern void check_commit_signature(const struct commit* commit, struct signature_check *sigc);
+
 #endif /* COMMIT_H */
index 5428858875a20b89411d3662e777586d9d798fab..871b41d23a7471724a0446ff3333b577a175c579 100644 (file)
@@ -1,3 +1,4 @@
+#define CYGWIN_C
 #define WIN32_LEAN_AND_MEAN
 #ifdef CYGWIN_V15_WIN32API
 #include "../git-compat-util.h"
 #endif
 #include "../cache.h" /* to read configuration */
 
+/*
+ * Return POSIX permission bits, regardless of core.ignorecygwinfstricks
+ */
+int cygwin_get_st_mode_bits(const char *path, int *mode)
+{
+       struct stat st;
+       if (lstat(path, &st) < 0)
+               return -1;
+       *mode = st.st_mode;
+       return 0;
+}
+
 static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
 {
        long long winTime = ((long long)ft->dwHighDateTime << 32) +
index a3229f5b4fbb819ba1beabcf560725e80ad51bb4..c04965a2e0e259d3bded51730f699bde5c4262e6 100644 (file)
@@ -4,6 +4,11 @@
 typedef int (*stat_fn_t)(const char*, struct stat*);
 extern stat_fn_t cygwin_stat_fn;
 extern stat_fn_t cygwin_lstat_fn;
+int cygwin_get_st_mode_bits(const char *path, int *mode);
 
+#define get_st_mode_bits(p,m) cygwin_get_st_mode_bits((p),(m))
+#ifndef CYGWIN_C
+/* cygwin.c needs the original lstat() */
 #define stat(path, buf) (*cygwin_stat_fn)(path, buf)
 #define lstat(path, buf) (*cygwin_lstat_fn)(path, buf)
+#endif
index ff7c2c4fd8642da754b1c85a9e177baf4ddc7136..1401a6727414480e181023f8de974bad76a04d24 100644 (file)
@@ -4778,7 +4778,7 @@ void* dlmalloc(size_t bytes) {
 
 void dlfree(void* mem) {
   /*
-     Consolidate freed chunks with preceeding or succeeding bordering
+     Consolidate freed chunks with preceding or succeeding bordering
      free chunks, if they exist, and then place in a bin.  Intermixed
      with special cases for top, dv, mmapped chunks, and usage errors.
   */
@@ -5680,10 +5680,10 @@ int mspace_mallopt(int param_number, int value) {
        Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
       * Use last_remainder in more cases.
       * Pack bins using idea from  colin@nyx10.cs.du.edu
-      * Use ordered bins instead of best-fit threshhold
+      * Use ordered bins instead of best-fit threshold
       * Eliminate block-local decls to simplify tracing and debugging.
       * Support another case of realloc via move into top
-      * Fix error occuring when initial sbrk_base not word-aligned.
+      * Fix error occurring when initial sbrk_base not word-aligned.
       * Rely on page size for units instead of SBRK_UNIT to
        avoid surprises about sbrk alignment conventions.
       * Add mallinfo, mallopt. Thanks to Raymond Nijssen
index d178bd67162fd2b566364ac6dff84cecdcaa9473..ceb4bdbcdd6ed583ab3b7c9cc5d9d2783128dee6 100644 (file)
@@ -128,7 +128,7 @@ extern "C" {
 
 #define __BPTR_ALIGN(B, P, A) ((B) + (((P) - (B) + (A)) & ~(A)))
 
-/* Similiar to _BPTR_ALIGN (B, P, A), except optimize the common case
+/* Similar to _BPTR_ALIGN (B, P, A), except optimize the common case
    where pointers can be converted to integers, aligned as integers,
    and converted back again.  If PTR_INT_TYPE is narrower than a
    pointer (e.g., the AS/400), play it safe and compute the alignment
index 8cf59558e1c6fcc6782b8eaf94534ea041599191..030174db515e764aa883b21afe9be8fb3ae41f2e 100644 (file)
@@ -134,7 +134,7 @@ struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)
                        if (prec_dir->ic_precompose == (iconv_t)-1) {
                                die("iconv_open(%s,%s) failed, but needed:\n"
                                                "    precomposed unicode is not supported.\n"
-                                               "    If you wnat to use decomposed unicode, run\n"
+                                               "    If you want to use decomposed unicode, run\n"
                                                "    \"git config core.precomposeunicode false\"\n",
                                                repo_encoding, path_encoding);
                        } else {
index 8c96ed942c3f7139a4b161c75c6c81e42530c085..d0025bd58d48cfcf137e5ef3bba90881dc00ec68 100644 (file)
@@ -2095,7 +2095,7 @@ peek_token_bracket (re_token_t *token, re_string_t *input, reg_syntax_t syntax)
 
 /* Entry point of the parser.
    Parse the regular expression REGEXP and return the structure tree.
-   If an error is occured, ERR is set by error code, and return NULL.
+   If an error has occurred, ERR is set by error code, and return NULL.
    This function build the following tree, from regular expression <reg_exp>:
           CAT
           / \
@@ -3715,7 +3715,7 @@ build_charclass_op (re_dfa_t *dfa, RE_TRANSLATE_TYPE trans,
 /* This is intended for the expressions like "a{1,3}".
    Fetch a number from `input', and return the number.
    Return -1, if the number field is empty like "{,1}".
-   Return -2, If an error is occured.  */
+   Return -2, if an error has occurred.  */
 
 static int
 fetch_number (re_string_t *input, re_token_t *token, reg_syntax_t syntax)
index 3dd8dfa01f2a6ab7a197ecddd481704150253c36..6aaae003274e268f274df4b76e02609d5f27e457 100644 (file)
@@ -22,7 +22,7 @@
 #include "config.h"
 #endif
 
-/* Make sure noone compiles this code with a C++ compiler.  */
+/* Make sure no one compiles this code with a C++ compiler.  */
 #ifdef __cplusplus
 # error "This is C code, use a C compiler"
 #endif
index 193854cf5b609d714b03218bd507af840d478c6e..d4121f2f4f1cfa9bf90c22b6e3c944f451225fdf 100644 (file)
@@ -1284,7 +1284,7 @@ re_node_set_merge (re_node_set *dest, const re_node_set *src)
 
 /* Insert the new element ELEM to the re_node_set* SET.
    SET should not already have ELEM.
-   return -1 if an error is occured, return 1 otherwise.  */
+   return -1 if an error has occurred, return 1 otherwise.  */
 
 static int
 internal_function
@@ -1341,7 +1341,7 @@ re_node_set_insert (re_node_set *set, int elem)
 
 /* Insert the new element ELEM to the re_node_set* SET.
    SET should not already have any element greater than or equal to ELEM.
-   Return -1 if an error is occured, return 1 otherwise.  */
+   Return -1 if an error has occurred, return 1 otherwise.  */
 
 static int
 internal_function
@@ -1416,7 +1416,7 @@ re_node_set_remove_at (re_node_set *set, int idx)
 \f
 
 /* Add the token TOKEN to dfa->nodes, and return the index of the token.
-   Or return -1, if an error will be occured.  */
+   Or return -1, if an error has occurred.  */
 
 static int
 internal_function
index 9080054f7617017a67ca0ae8414f829a01d3d546..d78fd3df5b211130ba8ff77197a3f852c32aab86 100644 (file)
@@ -507,6 +507,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
                compat/win32/dirent.o
        EXTLIBS += -lws2_32
        PTHREAD_LIBS =
+       NATIVE_CRLF = YesPlease
        X = .exe
        SPARSE_FLAGS = -Wno-one-bit-signed-bitfield
 ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
index 2ba1461422c4e6c16e6c85ed3914536e1f4aa56e..6df62c217321b4f66fd230a1b95f2b3cfe2becd2 100644 (file)
@@ -53,19 +53,6 @@ __gitdir ()
        fi
 }
 
-__gitcomp_1 ()
-{
-       local c IFS=$' \t\n'
-       for c in $1; do
-               c="$c$2"
-               case $c in
-               --*=*|*.) ;;
-               *) c="$c " ;;
-               esac
-               printf '%s\n' "$c"
-       done
-}
-
 # The following function is based on code from:
 #
 #   bash_completion - programmable completion functions for bash 3.2+
@@ -195,8 +182,18 @@ _get_comp_words_by_ref ()
 }
 fi
 
-# Generates completion reply with compgen, appending a space to possible
-# completion words, if necessary.
+__gitcompadd ()
+{
+       local i=0
+       for x in $1; do
+               if [[ "$x" == "$3"* ]]; then
+                       COMPREPLY[i++]="$2$x$4"
+               fi
+       done
+}
+
+# Generates completion reply, appending a space to possible completion words,
+# if necessary.
 # It accepts 1 to 4 arguments:
 # 1: List of possible completion words.
 # 2: A prefix to be added to each possible completion word (optional).
@@ -208,19 +205,25 @@ __gitcomp ()
 
        case "$cur_" in
        --*=)
-               COMPREPLY=()
                ;;
        *)
-               local IFS=$'\n'
-               COMPREPLY=($(compgen -P "${2-}" \
-                       -W "$(__gitcomp_1 "${1-}" "${4-}")" \
-                       -- "$cur_"))
+               local c i=0 IFS=$' \t\n'
+               for c in $1; do
+                       c="$c${4-}"
+                       if [[ $c == "$cur_"* ]]; then
+                               case $c in
+                               --*=*|*.) ;;
+                               *) c="$c " ;;
+                               esac
+                               COMPREPLY[i++]="${2-}$c"
+                       fi
+               done
                ;;
        esac
 }
 
-# Generates completion reply with compgen from newline-separated possible
-# completion words by appending a space to all of them.
+# Generates completion reply from newline-separated possible completion words
+# by appending a space to all of them.
 # It accepts 1 to 4 arguments:
 # 1: List of possible completion words, separated by a single newline.
 # 2: A prefix to be added to each possible completion word (optional).
@@ -231,7 +234,7 @@ __gitcomp ()
 __gitcomp_nl ()
 {
        local IFS=$'\n'
-       COMPREPLY=($(compgen -P "${2-}" -S "${4- }" -W "$1" -- "${3-$cur}"))
+       __gitcompadd "$1" "${2-}" "${3-$cur}" "${4- }"
 }
 
 # Generates completion reply with compgen from newline-separated possible
@@ -614,7 +617,6 @@ __git_complete_remote_or_refspec ()
                        case "$cmd" in
                        push) no_complete_refspec=1 ;;
                        fetch)
-                               COMPREPLY=()
                                return
                                ;;
                        *) ;;
@@ -630,7 +632,6 @@ __git_complete_remote_or_refspec ()
                return
        fi
        if [ $no_complete_refspec = 1 ]; then
-               COMPREPLY=()
                return
        fi
        [ "$remote" = "." ] && remote=
@@ -951,7 +952,6 @@ _git_am ()
                        "
                return
        esac
-       COMPREPLY=()
 }
 
 _git_apply ()
@@ -971,7 +971,6 @@ _git_apply ()
                        "
                return
        esac
-       COMPREPLY=()
 }
 
 _git_add ()
@@ -1031,7 +1030,6 @@ _git_bisect ()
                __gitcomp_nl "$(__git_refs)"
                ;;
        *)
-               COMPREPLY=()
                ;;
        esac
 }
@@ -1124,9 +1122,14 @@ _git_cherry ()
 
 _git_cherry_pick ()
 {
+       local dir="$(__gitdir)"
+       if [ -f "$dir"/CHERRY_PICK_HEAD ]; then
+               __gitcomp "--continue --quit --abort"
+               return
+       fi
        case "$cur" in
        --*)
-               __gitcomp "--edit --no-commit"
+               __gitcomp "--edit --no-commit --signoff --strategy= --mainline"
                ;;
        *)
                __gitcomp_nl "$(__git_refs)"
@@ -1170,7 +1173,6 @@ _git_clone ()
                return
                ;;
        esac
-       COMPREPLY=()
 }
 
 _git_commit ()
@@ -1354,7 +1356,6 @@ _git_fsck ()
                return
                ;;
        esac
-       COMPREPLY=()
 }
 
 _git_gc ()
@@ -1365,7 +1366,6 @@ _git_gc ()
                return
                ;;
        esac
-       COMPREPLY=()
 }
 
 _git_gitk ()
@@ -1442,7 +1442,6 @@ _git_init ()
                return
                ;;
        esac
-       COMPREPLY=()
 }
 
 _git_ls_files ()
@@ -1578,7 +1577,6 @@ _git_mergetool ()
                return
                ;;
        esac
-       COMPREPLY=()
 }
 
 _git_merge_base ()
@@ -1831,7 +1829,7 @@ _git_config ()
                local remote="${prev#remote.}"
                remote="${remote%.fetch}"
                if [ -z "$cur" ]; then
-                       COMPREPLY=("refs/heads/")
+                       __gitcompadd "refs/heads/" "" "" ""
                        return
                fi
                __gitcomp_nl "$(__git_refs_remotes "$remote")"
@@ -1891,7 +1889,6 @@ _git_config ()
                return
                ;;
        *.*)
-               COMPREPLY=()
                return
                ;;
        esac
@@ -2272,7 +2269,6 @@ _git_remote ()
                __gitcomp "$c"
                ;;
        *)
-               COMPREPLY=()
                ;;
        esac
 }
@@ -2388,8 +2384,6 @@ _git_stash ()
                *)
                        if [ -z "$(__git_find_on_cmdline "$save_opts")" ]; then
                                __gitcomp "$subcommands"
-                       else
-                               COMPREPLY=()
                        fi
                        ;;
                esac
@@ -2402,14 +2396,12 @@ _git_stash ()
                        __gitcomp "--index --quiet"
                        ;;
                show,--*|drop,--*|branch,--*)
-                       COMPREPLY=()
                        ;;
                show,*|apply,*|drop,*|pop,*|branch,*)
                        __gitcomp_nl "$(git --git-dir="$(__gitdir)" stash list \
                                        | sed -n -e 's/:.*//p')"
                        ;;
                *)
-                       COMPREPLY=()
                        ;;
                esac
        fi
@@ -2526,7 +2518,6 @@ _git_svn ()
                        __gitcomp "--revision= --parent"
                        ;;
                *)
-                       COMPREPLY=()
                        ;;
                esac
        fi
@@ -2551,13 +2542,10 @@ _git_tag ()
 
        case "$prev" in
        -m|-F)
-               COMPREPLY=()
                ;;
        -*|tag)
                if [ $f = 1 ]; then
                        __gitcomp_nl "$(__git_tags)"
-               else
-                       COMPREPLY=()
                fi
                ;;
        *)
index 341422a766efe70580817d98a574d95bd9ddebf9..756a9514591c7664c82c93d3a6d50d91f46857d8 100644 (file)
@@ -282,6 +282,8 @@ __git_ps1 ()
                                r="|MERGING"
                        elif [ -f "$g/CHERRY_PICK_HEAD" ]; then
                                r="|CHERRY-PICKING"
+                       elif [ -f "$g/REVERT_HEAD" ]; then
+                               r="|REVERTING"
                        elif [ -f "$g/BISECT_LOG" ]; then
                                r="|BISECTING"
                        fi
index 094129de09ca92643d98f34f20a35479089bcbcb..9c14c1f88d3a8f23df54db2adc7985eb00722c12 100755 (executable)
@@ -28,7 +28,7 @@
 use constant SLASH_REPLACEMENT => "%2F";
 
 # It's not always possible to delete pages (may require some
-# priviledges). Deleted pages are replaced with this content.
+# privileges). Deleted pages are replaced with this content.
 use constant DELETED_CONTENT => "[[Category:Deleted]]\n";
 
 # It's not possible to create empty pages. New empty files in Git are
@@ -841,7 +841,7 @@ sub mw_import_ref {
        if ($fetch_from == 1 && $n == 0) {
                print STDERR "You appear to have cloned an empty MediaWiki.\n";
                # Something has to be done remote-helper side. If nothing is done, an error is
-               # thrown saying that HEAD is refering to unknown object 0000000000000000000
+               # thrown saying that HEAD is referring to unknown object 0000000000000000000
                # and the clone fails.
        }
 }
@@ -1067,7 +1067,7 @@ sub mw_push_file {
                my $file_content;
                if ($page_deleted) {
                        # Deleting a page usually requires
-                       # special priviledges. A common
+                       # special privileges. A common
                        # convention is to replace the page
                        # with this content instead:
                        $file_content = DELETED_CONTENT;
index 4d211f5b81ae3f96938211c4bd2e20789d38fcdb..23b7ef9f6208720310d2a8d93812cbe6fb3a42ca 100644 (file)
@@ -4,4 +4,4 @@ objects from mediawiki just as one would do with a classic git
 repository thanks to remote-helpers.
 
 For more information, visit the wiki at
-https://github.com/Bibzball/Git-Mediawiki/wiki
+https://github.com/moy/Git-Mediawiki/wiki
index 96e97390cf90822e771bc8ccf600c394792f2b96..03f6ee5d72f5096e287c23e048746fe1f756f062 100644 (file)
@@ -25,7 +25,7 @@ Principles and Technical Choices
 
 The test environment makes it easy to install and manipulate one or
 several MediaWiki instances. To allow developers to run the testsuite
-easily, the environment does not require root priviledge (except to
+easily, the environment does not require root privilege (except to
 install the required packages if needed). It starts a webserver
 instance on the user's account (using lighttpd greatly helps for
 that), and does not need a separate database daemon (thanks to the use
@@ -81,7 +81,7 @@ parameters, please refer to the `test-gitmw-lib.sh` and
 
 ** `test_check_wiki_precond`:
 Check if the tests must be skipped or not. Please use this function
-at the beggining of each new test file.
+at the beginning of each new test file.
 
 ** `wiki_getpage`:
 Fetch a given page from the wiki and puts its content in the
@@ -113,7 +113,7 @@ Tests if a given page exists on the wiki.
 
 ** `wiki_reset`:
 Reset the wiki, i.e. flush the database. Use this function at the
-begining of each new test, except if the test re-uses the same wiki
+beginning of each new test, except if the test re-uses the same wiki
 (and history) as the previous test.
 
 How to write a new test
index 29f125116b59ed408339a37dbf82f2d913877d78..745e47e88173cac83c65b1c47d087cc98ec28621 100644 (file)
@@ -88,7 +88,7 @@ $wgShellLocale = "en_US.utf8";
 
 ## Set $wgCacheDirectory to a writable directory on the web server
 ## to make your wiki go slightly faster. The directory should not
-## be publically accessible from the web.
+## be publicly accessible from the web.
 #$wgCacheDirectory = "$IP/cache";
 
 # Site language code, should be one of the list in ./languages/Names.php
index b6405ce2628480240fc92ac5d69307991f2d5c69..37021e200a32d36e37f5c0ca7f6cacdca7d80187 100755 (executable)
@@ -139,7 +139,7 @@ test_expect_success 'character $ in file name (git -> mw) ' '
 '
 
 
-test_expect_failure 'capital at the begining of file names' '
+test_expect_failure 'capital at the beginning of file names' '
        wiki_reset &&
        git clone mediawiki::'"$WIKI_URL"' mw_dir_10 &&
        (
@@ -156,7 +156,7 @@ test_expect_failure 'capital at the begining of file names' '
 '
 
 
-test_expect_failure 'special character at the begining of file name from mw to git' '
+test_expect_failure 'special character at the beginning of file name from mw to git' '
        wiki_reset &&
        git clone mediawiki::'"$WIKI_URL"' mw_dir_11 &&
        wiki_editpage {char_1 "expect to be renamed {char_1" false &&
@@ -189,7 +189,7 @@ test_expect_success 'Push page with title containing ":" other than namespace se
        wiki_page_exist NotANameSpace:Page
 '
 
-test_expect_success 'test of correct formating for file name from mw to git' '
+test_expect_success 'test of correct formatting for file name from mw to git' '
        wiki_reset &&
        git clone mediawiki::'"$WIKI_URL"' mw_dir_12 &&
        wiki_editpage char_%_7b_1 "expect to be renamed char{_1" false &&
@@ -207,7 +207,7 @@ test_expect_success 'test of correct formating for file name from mw to git' '
 '
 
 
-test_expect_failure 'test of correct formating for file name begining with special character' '
+test_expect_failure 'test of correct formatting for file name beginning with special character' '
        wiki_reset &&
        git clone mediawiki::'"$WIKI_URL"' mw_dir_13 &&
        (
@@ -215,7 +215,7 @@ test_expect_failure 'test of correct formating for file name begining with speci
                echo "my new file {char_1" >\{char_1.mw &&
                echo "my new file [char_2" >\[char_2.mw &&
                git add . &&
-               git commit -am "commiting some exotic file name..." &&
+               git commit -am "committing some exotic file name..." &&
                git push &&
                git pull
        ) &&
@@ -226,7 +226,7 @@ test_expect_failure 'test of correct formating for file name begining with speci
 '
 
 
-test_expect_success 'test of correct formating for file name from git to mw' '
+test_expect_success 'test of correct formatting for file name from git to mw' '
        wiki_reset &&
        git clone mediawiki::'"$WIKI_URL"' mw_dir_14 &&
        (
@@ -234,7 +234,7 @@ test_expect_success 'test of correct formating for file name from git to mw' '
                echo "my new file char{_1" >Char\{_1.mw &&
                echo "my new file char[_2" >Char\[_2.mw &&
                git add . &&
-               git commit -m "commiting some exotic file name..." &&
+               git commit -m "committing some exotic file name..." &&
                git push
        ) &&
        wiki_getallpage ref_page_14 &&
index 9a76575f78f7c2cc6154c0a0d57f732de1e7f5d9..239161de33373d4ca97581a242cac848463fbbf3 100644 (file)
@@ -3,6 +3,7 @@ TESTS := $(wildcard test*.sh)
 export T := $(addprefix $(CURDIR)/,$(TESTS))
 export MAKE := $(MAKE) -e
 export PATH := $(CURDIR):$(PATH)
+export TEST_LINT := test-lint-executable test-lint-shell-syntax
 
 test:
        $(MAKE) -C ../../t $@
index c5822e4ac97ed3640c81cb645509346489199379..aa7bc97beecc6af7adca5b6886d8e7c61f9173b1 100755 (executable)
@@ -25,6 +25,7 @@ bzrlib.plugin.load_plugins()
 
 import bzrlib.generate_ids
 import bzrlib.transport
+import bzrlib.errors
 
 import sys
 import os
@@ -183,15 +184,24 @@ def get_filechanges(cur, prev):
 
     changes = cur.changes_from(prev)
 
+    def u(s):
+        return s.encode('utf-8')
+
     for path, fid, kind in changes.added:
-        modified[path] = fid
+        modified[u(path)] = fid
     for path, fid, kind in changes.removed:
-        removed[path] = None
+        removed[u(path)] = None
     for path, fid, kind, mod, _ in changes.modified:
-        modified[path] = fid
+        modified[u(path)] = fid
     for oldpath, newpath, fid, kind, mod, _ in changes.renamed:
-        removed[oldpath] = None
-        modified[newpath] = fid
+        removed[u(oldpath)] = None
+        if kind == 'directory':
+            lst = cur.list_files(from_dir=newpath, recursive=True)
+            for path, file_class, kind, fid, entry in lst:
+                if kind != 'directory':
+                    modified[u(newpath + '/' + path)] = fid
+        else:
+            modified[u(newpath)] = fid
 
     return modified, removed
 
@@ -239,7 +249,7 @@ def export_files(tree, files):
     return final
 
 def export_branch(branch, name):
-    global prefix, dirname
+    global prefix
 
     ref = '%s/heads/%s' % (prefix, name)
     tip = marks.get_tip(name)
@@ -260,7 +270,12 @@ def export_branch(branch, name):
         tz = rev.timezone
         committer = rev.committer.encode('utf-8')
         committer = "%s %u %s" % (fixup_user(committer), time, gittz(tz))
-        author = committer
+        authors = rev.get_apparent_authors()
+        if authors:
+            author = authors[0].encode('utf-8')
+            author = "%s %u %s" % (fixup_user(author), time, gittz(tz))
+        else:
+            author = committer
         msg = rev.message.encode('utf-8')
 
         msg += '\n'
@@ -297,10 +312,10 @@ def export_branch(branch, name):
             else:
                 print "merge :%s" % m
 
+        for f in removed:
+            print "D %s" % (f,)
         for f in modified_final:
             print "M %s :%u %s" % f
-        for f in removed:
-            print "D %s" % (f)
         print
 
         count += 1
@@ -320,13 +335,12 @@ def export_branch(branch, name):
     marks.set_tip(name, revid)
 
 def export_tag(repo, name):
-    global tags
-    try:
-        print "reset refs/tags/%s" % name
-        print "from :%u" % rev_to_mark(tags[name])
-        print
-    except KeyError:
-        warn("TODO: fetch tag '%s'" % name)
+    global tags, prefix
+
+    ref = '%s/tags/%s' % (prefix, name)
+    print "reset %s" % ref
+    print "from :%u" % rev_to_mark(tags[name])
+    print
 
 def do_import(parser):
     global dirname
@@ -501,6 +515,11 @@ class CustomTree():
     def get_symlink_target(self, file_id):
         return self.updates[file_id]['data']
 
+def c_style_unescape(string):
+    if string[0] == string[-1] == '"':
+        return string.decode('string-escape')[1:-1]
+    return string
+
 def parse_commit(parser):
     global marks, blob_marks, bmarks, parsed_refs
     global mode
@@ -540,6 +559,7 @@ def parse_commit(parser):
             f = { 'deleted' : True }
         else:
             die('Unknown file command: %s' % line)
+        path = c_style_unescape(path).decode('utf-8')
         files[path] = f
 
     repo = parser.repo
@@ -619,10 +639,9 @@ def do_export(parser):
                     peer.import_last_revision_info_and_tags(repo, revno, revid)
                 else:
                     peer.import_last_revision_info(repo.repository, revno, revid)
-                wt = peer.bzrdir.open_workingtree()
             else:
                 wt = repo.bzrdir.open_workingtree()
-            wt.update()
+                wt.update()
         print "ok %s" % ref
     print
 
@@ -632,6 +651,7 @@ def do_capabilities(parser):
     print "import"
     print "export"
     print "refspec refs/heads/*:%s/heads/*" % prefix
+    print "refspec refs/tags/*:%s/tags/*" % prefix
 
     path = os.path.join(dirname, 'marks-git')
 
@@ -641,12 +661,25 @@ def do_capabilities(parser):
 
     print
 
+def ref_is_valid(name):
+    return not True in [c in name for c in '~^: \\']
+
 def do_list(parser):
     global tags
     print "? refs/heads/%s" % 'master'
-    for tag, revid in parser.repo.tags.get_tag_dict().items():
+
+    branch = parser.repo
+    branch.lock_read()
+    for tag, revid in branch.tags.get_tag_dict().items():
+        try:
+            branch.revision_id_to_dotted_revno(revid)
+        except bzrlib.errors.NoSuchRevision:
+            continue
+        if not ref_is_valid(tag):
+            continue
         print "? refs/tags/%s" % tag
         tags[tag] = revid
+    branch.unlock()
     print "@refs/heads/%s HEAD" % 'master'
     print
 
index a5f0013c627969c1741001c3b25bc450ad073a51..548133121d23a328d76d68d058fd4fb14b60fb16 100755 (executable)
@@ -362,6 +362,8 @@ def export_ref(repo, name, kind, head):
         else:
             modified, removed = get_filechanges(repo, c, parents[0])
 
+        desc += '\n'
+
         if mode == 'hg':
             extra_msg = ''
 
@@ -385,7 +387,6 @@ def export_ref(repo, name, kind, head):
                 else:
                     extra_msg += "extra : %s : %s\n" % (key, urllib.quote(value))
 
-            desc += '\n'
             if extra_msg:
                 desc += '\n--HG--\n' + extra_msg
 
index 70aa8a010a6bc00a131860f2db509e56a7f75797..34666e1d0f60813abf65fa231dc13f2b4c080440 100755 (executable)
@@ -17,20 +17,6 @@ if ! "$PYTHON_PATH" -c 'import bzrlib'; then
        test_done
 fi
 
-cmd='
-import bzrlib
-bzrlib.initialize()
-import bzrlib.plugin
-bzrlib.plugin.load_plugins()
-import bzrlib.plugins.fastimport
-'
-
-if ! "$PYTHON_PATH" -c "$cmd"; then
-       echo "consider setting BZR_PLUGIN_PATH=$HOME/.bazaar/plugins" 1>&2
-       skip_all='skipping remote-bzr tests; bzr-fastimport not available'
-       test_done
-fi
-
 check () {
        (cd $1 &&
        git log --format='%s' -1 &&
@@ -136,7 +122,109 @@ test_expect_success 'special modes' '
   (cd gitrepo &&
   git cat-file -p HEAD:link > ../actual) &&
 
-  echo -n content > expected &&
+  printf content > expected &&
+  test_cmp expected actual
+'
+
+cat > expected <<EOF
+100644 blob 54f9d6da5c91d556e6b54340b1327573073030af   content
+100755 blob 68769579c3eaadbe555379b9c3538e6628bae1eb   executable
+120000 blob 6b584e8ece562ebffc15d38808cd6b98fc3d97ea   link
+040000 tree 35c0caa46693cef62247ac89a680f0c5ce32b37b   movedir-new
+EOF
+
+test_expect_success 'moving directory' '
+  (cd bzrrepo &&
+  mkdir movedir &&
+  echo one > movedir/one &&
+  echo two > movedir/two &&
+  bzr add movedir &&
+  bzr commit -m movedir &&
+  bzr mv movedir movedir-new &&
+  bzr commit -m movedir-new) &&
+
+  (cd gitrepo &&
+  git pull &&
+  git ls-tree HEAD > ../actual) &&
+
+  test_cmp expected actual
+'
+
+test_expect_success 'different authors' '
+  (cd bzrrepo &&
+  echo john >> content &&
+  bzr commit -m john \
+    --author "Jane Rey <jrey@example.com>" \
+    --author "John Doe <jdoe@example.com>") &&
+
+  (cd gitrepo &&
+  git pull &&
+  git show --format="%an <%ae>, %cn <%ce>" --quiet > ../actual) &&
+
+  echo "Jane Rey <jrey@example.com>, A U Thor <author@example.com>" > expected &&
+  test_cmp expected actual
+'
+
+test_expect_success 'fetch utf-8 filenames' '
+  mkdir -p tmp && cd tmp &&
+  test_when_finished "cd .. && rm -rf tmp && LC_ALL=C" &&
+
+  LC_ALL=en_US.UTF-8
+  export LC_ALL
+  (
+  bzr init bzrrepo &&
+  cd bzrrepo &&
+
+  echo test >> "ærø" &&
+  bzr add "ærø" &&
+  echo test >> "ø~?" &&
+  bzr add "ø~?" &&
+  bzr commit -m add-utf-8 &&
+  echo test >> "ærø" &&
+  bzr commit -m test-utf-8 &&
+  bzr rm "ø~?" &&
+  bzr mv "ærø" "ø~?" &&
+  bzr commit -m bzr-mv-utf-8
+  ) &&
+
+  (
+  git clone "bzr::$PWD/bzrrepo" gitrepo &&
+  cd gitrepo &&
+  git -c core.quotepath=false ls-files > ../actual
+  ) &&
+  echo "ø~?" > expected &&
+  test_cmp expected actual
+'
+
+test_expect_success 'push utf-8 filenames' '
+  mkdir -p tmp && cd tmp &&
+  test_when_finished "cd .. && rm -rf tmp && LC_ALL=C" &&
+
+  LC_ALL=en_US.UTF-8
+  export LC_ALL
+
+  (
+  bzr init bzrrepo &&
+  cd bzrrepo &&
+
+  echo one >> content &&
+  bzr add content &&
+  bzr commit -m one
+  ) &&
+
+  (
+  git clone "bzr::$PWD/bzrrepo" gitrepo &&
+  cd gitrepo &&
+
+  echo test >> "ærø" &&
+  git add "ærø" &&
+  git commit -m utf-8 &&
+
+  git push
+  ) &&
+
+  (cd bzrrepo && bzr ls > ../actual) &&
+  printf "content\nærø\n" > expected &&
   test_cmp expected actual
 '
 
index 5daad6b961faadb72eecabf5cd196ac3f0f56c96..253e65aaa8881581b971eb51d518a4ad393f4b3d 100755 (executable)
@@ -142,7 +142,6 @@ test_expect_success 'executable bit' '
                git_clone_$x hgrepo-$x gitrepo2-$x &&
                git_log gitrepo2-$x > log-$x
        done &&
-       cp -r log-* output-* /tmp/foo/ &&
 
        test_cmp output-hg output-git &&
        test_cmp log-hg log-git
index 6a1e4b1ad629c99e6c98786810c8601181cddd6d..d5b873051f5d79e277fb8ed6cfcd0db85f0d429f 100755 (executable)
@@ -115,7 +115,7 @@ test_expect_success 'update bookmark' '
   git push
   ) &&
 
-  hg -R hgrepo bookmarks | grep "devel\s\+3:"
+  hg -R hgrepo bookmarks | egrep "devel[        ]+3:"
 '
 
 author_test () {
index 80d339960bbd5f70d17472a6f39f715dd8ec9182..b0f8536fca58d910f85334727b89925651bfa8ae 100755 (executable)
@@ -419,7 +419,7 @@ test_expect_success 'add main-sub5' '
 test_expect_success 'split for main-sub5 without --onto' '
         # also test that we still can split out an entirely new subtree
         # if the parent of the first commit in the tree is not empty,
-        # then the new subtree has accidently been attached to something
+       # then the new subtree has accidentally been attached to something
         git subtree split --prefix subdir2 --branch mainsub5 &&
         check_equal ''"$(git log --pretty=format:%P -1 mainsub5)"'' ""
 '
index 3520252d3abaf49d4b7682ad083da8b7ae6be4c6..2a2e46c2012de3af673b9d8d8647ec894f07b65a 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -153,36 +153,13 @@ static void check_safe_crlf(const char *path, enum crlf_action crlf_action,
 
 static int has_cr_in_index(const char *path)
 {
-       int pos, len;
        unsigned long sz;
-       enum object_type type;
        void *data;
        int has_cr;
-       struct index_state *istate = &the_index;
 
-       len = strlen(path);
-       pos = index_name_pos(istate, path, len);
-       if (pos < 0) {
-               /*
-                * We might be in the middle of a merge, in which
-                * case we would read stage #2 (ours).
-                */
-               int i;
-               for (i = -pos - 1;
-                    (pos < 0 && i < istate->cache_nr &&
-                     !strcmp(istate->cache[i]->name, path));
-                    i++)
-                       if (ce_stage(istate->cache[i]) == 2)
-                               pos = i;
-       }
-       if (pos < 0)
+       data = read_blob_data_from_cache(path, &sz);
+       if (!data)
                return 0;
-       data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
-       if (!data || type != OBJ_BLOB) {
-               free(data);
-               return 0;
-       }
-
        has_cr = memchr(data, '\r', sz) != NULL;
        free(data);
        return has_cr;
diff --git a/diff.c b/diff.c
index db952a5bc71ac967cb045bada8c71f5fda218ca2..f0b3e7cfe34a99c0e5fea85fcd00ec54e9b578d8 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -1565,7 +1565,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
         * Binary files are displayed with "Bin XXX -> YYY bytes"
         * instead of the change count and graph. This part is treated
         * similarly to the graph part, except that it is not
-        * "scaled". If total width is too small to accomodate the
+        * "scaled". If total width is too small to accommodate the
         * guaranteed minimum width of the filename part and the
         * separators and this message, this message will "overflow"
         * making the line longer than the maximum width.
@@ -2255,6 +2255,7 @@ static void builtin_diff(const char *name_a,
                const char *del = diff_get_color_opt(o, DIFF_FILE_OLD);
                const char *add = diff_get_color_opt(o, DIFF_FILE_NEW);
                show_submodule_summary(o->file, one ? one->path : two->path,
+                               line_prefix,
                                one->sha1, two->sha1, two->dirty_submodule,
                                meta, del, add, reset);
                return;
@@ -3596,8 +3597,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF);
        else if (!strcmp(arg, "--histogram"))
                options->xdl_opts = DIFF_WITH_ALG(options, HISTOGRAM_DIFF);
-       else if (!prefixcmp(arg, "--diff-algorithm=")) {
-               long value = parse_algorithm_value(arg+17);
+       else if ((argcount = parse_long_opt("diff-algorithm", av, &optarg))) {
+               long value = parse_algorithm_value(optarg);
                if (value < 0)
                        return error("option diff-algorithm accepts \"myers\", "
                                     "\"minimal\", \"patience\" and \"histogram\"");
@@ -3605,6 +3606,7 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
                DIFF_XDL_CLR(options, NEED_MINIMAL);
                options->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK;
                options->xdl_opts |= value;
+               return argcount;
        }
 
        /* flags options */
index 44f8678d22ea466b0867591429bbcc3285cdaf91..1d9e530a84758e34d616690684c4842cd1af4cfc 100644 (file)
@@ -68,6 +68,9 @@ static int should_break(struct diff_filespec *src,
        if (max_size < MINIMUM_BREAK_SIZE)
                return 0; /* we do not break too small filepair */
 
+       if (!src->size)
+               return 0; /* we do not let empty files get renamed */
+
        if (diffcore_count_changes(src, dst,
                                   &src->cnt_data, &dst->cnt_data,
                                   0,
index b097fa766177f90e4b7983789a9286506664b2fd..63722f86dca4c00389d6f305fd8aa1af8ef8ed6c 100644 (file)
@@ -8,7 +8,12 @@
 #include "xdiff-interface.h"
 #include "kwset.h"
 
-typedef int (*pickaxe_fn)(struct diff_filepair *p, struct diff_options *o, regex_t *regexp, kwset_t kws);
+typedef int (*pickaxe_fn)(mmfile_t *one, mmfile_t *two,
+                         struct diff_options *o,
+                         regex_t *regexp, kwset_t kws);
+
+static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,
+                        regex_t *regexp, kwset_t kws, pickaxe_fn fn);
 
 static void pickaxe(struct diff_queue_struct *q, struct diff_options *o,
                    regex_t *regexp, kwset_t kws, pickaxe_fn fn)
@@ -22,7 +27,7 @@ static void pickaxe(struct diff_queue_struct *q, struct diff_options *o,
                /* Showing the whole changeset if needle exists */
                for (i = 0; i < q->nr; i++) {
                        struct diff_filepair *p = q->queue[i];
-                       if (fn(p, o, regexp, kws))
+                       if (pickaxe_match(p, o, regexp, kws, fn))
                                return; /* do not munge the queue */
                }
 
@@ -37,7 +42,7 @@ static void pickaxe(struct diff_queue_struct *q, struct diff_options *o,
                /* Showing only the filepairs that has the needle */
                for (i = 0; i < q->nr; i++) {
                        struct diff_filepair *p = q->queue[i];
-                       if (fn(p, o, regexp, kws))
+                       if (pickaxe_match(p, o, regexp, kws, fn))
                                diff_q(&outq, p);
                        else
                                diff_free_filepair(p);
@@ -74,64 +79,33 @@ static void diffgrep_consume(void *priv, char *line, unsigned long len)
        line[len] = hold;
 }
 
-static void fill_one(struct diff_filespec *one,
-                    mmfile_t *mf, struct userdiff_driver **textconv)
-{
-       if (DIFF_FILE_VALID(one)) {
-               *textconv = get_textconv(one);
-               mf->size = fill_textconv(*textconv, one, &mf->ptr);
-       } else {
-               memset(mf, 0, sizeof(*mf));
-       }
-}
-
-static int diff_grep(struct diff_filepair *p, struct diff_options *o,
+static int diff_grep(mmfile_t *one, mmfile_t *two,
+                    struct diff_options *o,
                     regex_t *regexp, kwset_t kws)
 {
        regmatch_t regmatch;
-       struct userdiff_driver *textconv_one = NULL;
-       struct userdiff_driver *textconv_two = NULL;
-       mmfile_t mf1, mf2;
-       int hit;
+       struct diffgrep_cb ecbdata;
+       xpparam_t xpp;
+       xdemitconf_t xecfg;
 
-       if (diff_unmodified_pair(p))
-               return 0;
+       if (!one)
+               return !regexec(regexp, two->ptr, 1, &regmatch, 0);
+       if (!two)
+               return !regexec(regexp, one->ptr, 1, &regmatch, 0);
 
-       fill_one(p->one, &mf1, &textconv_one);
-       fill_one(p->two, &mf2, &textconv_two);
-
-       if (!mf1.ptr) {
-               if (!mf2.ptr)
-                       return 0; /* ignore unmerged */
-               /* created "two" -- does it have what we are looking for? */
-               hit = !regexec(regexp, mf2.ptr, 1, &regmatch, 0);
-       } else if (!mf2.ptr) {
-               /* removed "one" -- did it have what we are looking for? */
-               hit = !regexec(regexp, mf1.ptr, 1, &regmatch, 0);
-       } else {
-               /*
-                * We have both sides; need to run textual diff and see if
-                * the pattern appears on added/deleted lines.
-                */
-               struct diffgrep_cb ecbdata;
-               xpparam_t xpp;
-               xdemitconf_t xecfg;
-
-               memset(&xpp, 0, sizeof(xpp));
-               memset(&xecfg, 0, sizeof(xecfg));
-               ecbdata.regexp = regexp;
-               ecbdata.hit = 0;
-               xecfg.ctxlen = o->context;
-               xecfg.interhunkctxlen = o->interhunkcontext;
-               xdi_diff_outf(&mf1, &mf2, diffgrep_consume, &ecbdata,
-                             &xpp, &xecfg);
-               hit = ecbdata.hit;
-       }
-       if (textconv_one)
-               free(mf1.ptr);
-       if (textconv_two)
-               free(mf2.ptr);
-       return hit;
+       /*
+        * We have both sides; need to run textual diff and see if
+        * the pattern appears on added/deleted lines.
+        */
+       memset(&xpp, 0, sizeof(xpp));
+       memset(&xecfg, 0, sizeof(xecfg));
+       ecbdata.regexp = regexp;
+       ecbdata.hit = 0;
+       xecfg.ctxlen = o->context;
+       xecfg.interhunkctxlen = o->interhunkcontext;
+       xdi_diff_outf(one, two, diffgrep_consume, &ecbdata,
+                     &xpp, &xecfg);
+       return ecbdata.hit;
 }
 
 static void diffcore_pickaxe_grep(struct diff_options *o)
@@ -198,17 +172,37 @@ static unsigned int contains(mmfile_t *mf, struct diff_options *o,
        return cnt;
 }
 
-static int has_changes(struct diff_filepair *p, struct diff_options *o,
+static int has_changes(mmfile_t *one, mmfile_t *two,
+                      struct diff_options *o,
                       regex_t *regexp, kwset_t kws)
 {
-       struct userdiff_driver *textconv_one = get_textconv(p->one);
-       struct userdiff_driver *textconv_two = get_textconv(p->two);
+       if (!one)
+               return contains(two, o, regexp, kws) != 0;
+       if (!two)
+               return contains(one, o, regexp, kws) != 0;
+       return contains(one, o, regexp, kws) != contains(two, o, regexp, kws);
+}
+
+static int pickaxe_match(struct diff_filepair *p, struct diff_options *o,
+                        regex_t *regexp, kwset_t kws, pickaxe_fn fn)
+{
+       struct userdiff_driver *textconv_one = NULL;
+       struct userdiff_driver *textconv_two = NULL;
        mmfile_t mf1, mf2;
        int ret;
 
        if (!o->pickaxe[0])
                return 0;
 
+       /* ignore unmerged */
+       if (!DIFF_FILE_VALID(p->one) && !DIFF_FILE_VALID(p->two))
+               return 0;
+
+       if (DIFF_OPT_TST(o, ALLOW_TEXTCONV)) {
+               textconv_one = get_textconv(p->one);
+               textconv_two = get_textconv(p->two);
+       }
+
        /*
         * If we have an unmodified pair, we know that the count will be the
         * same and don't even have to load the blobs. Unless textconv is in
@@ -219,20 +213,12 @@ static int has_changes(struct diff_filepair *p, struct diff_options *o,
        if (textconv_one == textconv_two && diff_unmodified_pair(p))
                return 0;
 
-       fill_one(p->one, &mf1, &textconv_one);
-       fill_one(p->two, &mf2, &textconv_two);
+       mf1.size = fill_textconv(textconv_one, p->one, &mf1.ptr);
+       mf2.size = fill_textconv(textconv_two, p->two, &mf2.ptr);
 
-       if (!mf1.ptr) {
-               if (!mf2.ptr)
-                       ret = 0; /* ignore unmerged */
-               /* created */
-               ret = contains(&mf2, o, regexp, kws) != 0;
-       }
-       else if (!mf2.ptr) /* removed */
-               ret = contains(&mf1, o, regexp, kws) != 0;
-       else
-               ret = contains(&mf1, o, regexp, kws) !=
-                     contains(&mf2, o, regexp, kws);
+       ret = fn(DIFF_FILE_VALID(p->one) ? &mf1 : NULL,
+                DIFF_FILE_VALID(p->two) ? &mf2 : NULL,
+                o, regexp, kws);
 
        if (textconv_one)
                free(mf1.ptr);
diff --git a/dir.c b/dir.c
index 57394e452eb0de117b27f64804e529b617a6c7e0..91cfd996711f8b9523da92ff75088292e16d316c 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -59,6 +59,35 @@ inline int git_fnmatch(const char *pattern, const char *string,
        return fnmatch(pattern, string, fnm_flags);
 }
 
+static int fnmatch_icase_mem(const char *pattern, int patternlen,
+                            const char *string, int stringlen,
+                            int flags)
+{
+       int match_status;
+       struct strbuf pat_buf = STRBUF_INIT;
+       struct strbuf str_buf = STRBUF_INIT;
+       const char *use_pat = pattern;
+       const char *use_str = string;
+
+       if (pattern[patternlen]) {
+               strbuf_add(&pat_buf, pattern, patternlen);
+               use_pat = pat_buf.buf;
+       }
+       if (string[stringlen]) {
+               strbuf_add(&str_buf, string, stringlen);
+               use_str = str_buf.buf;
+       }
+
+       if (ignore_case)
+               flags |= WM_CASEFOLD;
+       match_status = wildmatch(use_pat, use_str, flags, NULL);
+
+       strbuf_release(&pat_buf);
+       strbuf_release(&str_buf);
+
+       return match_status;
+}
+
 static size_t common_prefix_len(const char **pathspec)
 {
        const char *n, *first;
@@ -626,15 +655,20 @@ int match_basename(const char *basename, int basenamelen,
                   int flags)
 {
        if (prefix == patternlen) {
-               if (!strcmp_icase(pattern, basename))
+               if (patternlen == basenamelen &&
+                   !strncmp_icase(pattern, basename, basenamelen))
                        return 1;
        } else if (flags & EXC_FLAG_ENDSWITH) {
+               /* "*literal" matching against "fooliteral" */
                if (patternlen - 1 <= basenamelen &&
-                   !strcmp_icase(pattern + 1,
-                                 basename + basenamelen - patternlen + 1))
+                   !strncmp_icase(pattern + 1,
+                                  basename + basenamelen - (patternlen - 1),
+                                  patternlen - 1))
                        return 1;
        } else {
-               if (fnmatch_icase(pattern, basename, 0) == 0)
+               if (fnmatch_icase_mem(pattern, patternlen,
+                                     basename, basenamelen,
+                                     0) == 0)
                        return 1;
        }
        return 0;
@@ -654,6 +688,7 @@ int match_pathname(const char *pathname, int pathlen,
         */
        if (*pattern == '/') {
                pattern++;
+               patternlen--;
                prefix--;
        }
 
@@ -680,13 +715,22 @@ int match_pathname(const char *pathname, int pathlen,
                if (strncmp_icase(pattern, name, prefix))
                        return 0;
                pattern += prefix;
+               patternlen -= prefix;
                name    += prefix;
                namelen -= prefix;
+
+               /*
+                * If the whole pattern did not have a wildcard,
+                * then our prefix match is all we need; we
+                * do not need to call fnmatch at all.
+                */
+               if (!patternlen && !namelen)
+                       return 1;
        }
 
-       return wildmatch(pattern, name,
-                        WM_PATHNAME | (ignore_case ? WM_CASEFOLD : 0),
-                        NULL) == 0;
+       return fnmatch_icase_mem(pattern, patternlen,
+                                name, namelen,
+                                WM_PATHNAME) == 0;
 }
 
 /*
@@ -1603,7 +1647,7 @@ int remove_path(const char *name)
 {
        char *slash;
 
-       if (unlink(name) && errno != ENOENT)
+       if (unlink(name) && errno != ENOENT && errno != ENOTDIR)
                return -1;
 
        slash = strrchr(name, '/');
diff --git a/entry.c b/entry.c
index 63c52edf600b5fd966e24cc5758bdab7dbeaf41b..d7c131d45309a496714221616244a70569155913 100644 (file)
--- a/entry.c
+++ b/entry.c
@@ -120,16 +120,18 @@ static int streaming_write_entry(struct cache_entry *ce, char *path,
                                 const struct checkout *state, int to_tempfile,
                                 int *fstat_done, struct stat *statbuf)
 {
-       int result = -1;
+       int result = 0;
        int fd;
 
        fd = open_output_fd(path, ce, to_tempfile);
-       if (0 <= fd) {
-               result = stream_blob_to_fd(fd, ce->sha1, filter, 1);
-               *fstat_done = fstat_output(fd, state, statbuf);
-               result = close(fd);
-       }
-       if (result && 0 <= fd)
+       if (fd < 0)
+               return -1;
+
+       result |= stream_blob_to_fd(fd, ce->sha1, filter, 1);
+       *fstat_done = fstat_output(fd, state, statbuf);
+       result |= close(fd);
+
+       if (result)
                unlink(path);
        return result;
 }
index 710764abb132f16e393fd16178b845d8160e37cf..d2c4ce6e1e88f543bd06cd8347e8949fef11a381 100755 (executable)
@@ -1247,7 +1247,7 @@ sub summarize_hunk {
 
 
 # Print a one-line summary of each hunk in the array ref in
-# the first argument, starting wih the index in the 2nd.
+# the first argument, starting with the index in the 2nd.
 sub display_hunks {
        my ($hunks, $i) = @_;
        my $ctr = 0;
index 90e037203879f6ba91403ae5371f18910206b580..e955bb5e8b3101cc8c753cf541beabf5cd037b39 100644 (file)
 typedef long intptr_t;
 typedef unsigned long uintptr_t;
 #endif
+int get_st_mode_bits(const char *path, int *mode);
 #if defined(__CYGWIN__)
 #undef _XOPEN_SOURCE
 #include <grp.h>
@@ -330,6 +331,7 @@ extern void warning(const char *err, ...) __attribute__((format (printf, 1, 2)))
 
 extern void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params));
 extern void set_error_routine(void (*routine)(const char *err, va_list params));
+extern void set_die_is_recursing_routine(int (*routine)(void));
 
 extern int prefixcmp(const char *str, const char *prefix);
 extern int suffixcmp(const char *str, const char *suffix);
index f1c3f49a836a8cf7f980bd3bc99d4fe9c2d49b65..a0d796e57087e0ca5bac94520997ecacec9fd295 100755 (executable)
@@ -2911,7 +2911,7 @@ sub filenamesplit
 }
 
 # Cleanup various junk in filename (try to canonicalize it), and
-# add prependdir to accomodate running CVS client from a
+# add prependdir to accommodate running CVS client from a
 # subdirectory (so the output is relative to top directory of the project).
 sub filecleanup
 {
@@ -4583,7 +4583,7 @@ sub getmeta
     #     the numerical value of the corresponding byte plus
     #     100.
     #      - "plus 100" avoids "0"s, and also reduces the
-    #        likelyhood of a collision in the case that someone someday
+    #        likelihood of a collision in the case that someone someday
     #        writes an import tool that tries to preserve original
     #        CVS revision numbers, and the original CVS data had done
     #        lots of branches off of branches and other strangeness to
index 663640d33cb99a98135b38b95947416b4a8d49b9..67802922ccc41fa2993c1bce4ea1a3d2899c7a40 100755 (executable)
@@ -13,9 +13,9 @@
 use 5.008;
 use strict;
 use warnings;
+use Error qw(:try);
 use File::Basename qw(dirname);
 use File::Copy;
-use File::Compare;
 use File::Find;
 use File::stat;
 use File::Path qw(mkpath rmtree);
@@ -88,14 +88,45 @@ sub use_wt_file
        my ($repo, $workdir, $file, $sha1, $symlinks) = @_;
        my $null_sha1 = '0' x 40;
 
-       if ($sha1 eq $null_sha1) {
-               return 1;
-       } elsif (not $symlinks) {
+       if ($sha1 ne $null_sha1 and not $symlinks) {
                return 0;
        }
 
        my $wt_sha1 = $repo->command_oneline('hash-object', "$workdir/$file");
-       return $sha1 eq $wt_sha1;
+       my $use = ($sha1 eq $null_sha1) || ($sha1 eq $wt_sha1);
+       return ($use, $wt_sha1);
+}
+
+sub changed_files
+{
+       my ($repo_path, $index, $worktree) = @_;
+       $ENV{GIT_INDEX_FILE} = $index;
+       $ENV{GIT_WORK_TREE} = $worktree;
+       my $must_unset_git_dir = 0;
+       if (not defined($ENV{GIT_DIR})) {
+               $must_unset_git_dir = 1;
+               $ENV{GIT_DIR} = $repo_path;
+       }
+
+       my @refreshargs = qw/update-index --really-refresh -q --unmerged/;
+       my @gitargs = qw/diff-files --name-only -z/;
+       try {
+               Git::command_oneline(@refreshargs);
+       } catch Git::Error::Command with {};
+
+       my $line = Git::command_oneline(@gitargs);
+       my @files;
+       if (defined $line) {
+               @files = split('\0', $line);
+       } else {
+               @files = ();
+       }
+
+       delete($ENV{GIT_INDEX_FILE});
+       delete($ENV{GIT_WORK_TREE});
+       delete($ENV{GIT_DIR}) if ($must_unset_git_dir);
+
+       return map { $_ => 1 } @files;
 }
 
 sub setup_dir_diff
@@ -121,6 +152,7 @@ sub setup_dir_diff
        my $null_sha1 = '0' x 40;
        my $lindex = '';
        my $rindex = '';
+       my $wtindex = '';
        my %submodule;
        my %symlink;
        my @working_tree = ();
@@ -174,8 +206,12 @@ sub setup_dir_diff
                }
 
                if ($rmode ne $null_mode) {
-                       if (use_wt_file($repo, $workdir, $dst_path, $rsha1, $symlinks)) {
-                               push(@working_tree, $dst_path);
+                       my ($use, $wt_sha1) = use_wt_file($repo, $workdir,
+                                                         $dst_path, $rsha1,
+                                                         $symlinks);
+                       if ($use) {
+                               push @working_tree, $dst_path;
+                               $wtindex .= "$rmode $wt_sha1\t$dst_path\0";
                        } else {
                                $rindex .= "$rmode $rsha1\t$dst_path\0";
                        }
@@ -218,6 +254,12 @@ sub setup_dir_diff
        $rc = system('git', 'checkout-index', '--all', "--prefix=$rdir/");
        exit_cleanup($tmpdir, $rc) if $rc != 0;
 
+       $ENV{GIT_INDEX_FILE} = "$tmpdir/wtindex";
+       ($inpipe, $ctx) =
+               $repo->command_input_pipe(qw(update-index --info-only -z --index-info));
+       print($inpipe $wtindex);
+       $repo->command_close_pipe($inpipe, $ctx);
+
        # If $GIT_DIR was explicitly set just for the update/checkout
        # commands, then it should be unset before continuing.
        delete($ENV{GIT_DIR}) if ($must_unset_git_dir);
@@ -390,19 +432,34 @@ sub dir_diff
        # should be copied back to the working tree.
        # Do not copy back files when symlinks are used and the
        # external tool did not replace the original link with a file.
+       #
+       # These hashes are loaded lazily since they aren't needed
+       # in the common case of --symlinks and the difftool updating
+       # files through the symlink.
+       my %wt_modified;
+       my %tmp_modified;
+       my $indices_loaded = 0;
+
        for my $file (@worktree) {
                next if $symlinks && -l "$b/$file";
                next if ! -f "$b/$file";
 
-               my $diff = compare("$b/$file", "$workdir/$file");
-               if ($diff == 0) {
-                       next;
-               } elsif ($diff == -1) {
-                       my $errmsg = "warning: Could not compare ";
-                       $errmsg += "'$b/$file' with '$workdir/$file'\n";
+               if (!$indices_loaded) {
+                       %wt_modified = changed_files($repo->repo_path(),
+                               "$tmpdir/wtindex", "$workdir");
+                       %tmp_modified = changed_files($repo->repo_path(),
+                               "$tmpdir/wtindex", "$b");
+                       $indices_loaded = 1;
+               }
+
+               if (exists $wt_modified{$file} and exists $tmp_modified{$file}) {
+                       my $errmsg = "warning: Both files modified: ";
+                       $errmsg .= "'$workdir/$file' and '$b/$file'.\n";
+                       $errmsg .= "warning: Working tree file has been left.\n";
+                       $errmsg .= "warning:\n";
                        warn $errmsg;
                        $error = 1;
-               } elsif ($diff == 1) {
+               } elsif (exists $tmp_modified{$file}) {
                        my $mode = stat("$b/$file")->mode;
                        copy("$b/$file", "$workdir/$file") or
                        exit_cleanup($tmpdir, 1);
index 53142492afcfb92f0453359af9a00a045c51e7e9..ac2a005fdb23c48d8451188ffd7b1c8194b0295f 100755 (executable)
@@ -199,6 +199,7 @@ t)
        test -d "$tempdir" &&
                die "$tempdir already exists, please remove it"
 esac
+orig_dir=$(pwd)
 mkdir -p "$tempdir/t" &&
 tempdir="$(cd "$tempdir"; pwd)" &&
 cd "$tempdir/t" &&
@@ -206,7 +207,7 @@ workdir="$(pwd)" ||
 die ""
 
 # Remove tempdir on exit
-trap 'cd ../..; rm -rf "$tempdir"' 0
+trap 'cd "$orig_dir"; rm -rf "$tempdir"' 0
 
 ORIG_GIT_DIR="$GIT_DIR"
 ORIG_GIT_WORK_TREE="$GIT_WORK_TREE"
@@ -469,7 +470,7 @@ if [ "$filter_tag_name" ]; then
        done
 fi
 
-cd ../..
+cd "$orig_dir"
 rm -rf "$tempdir"
 
 trap - 0
index 5d97e97bd95fe25d158058af025c48e47f6d241f..638aabb7b347e2afeb9bf327902de9e3702cd9d4 100755 (executable)
@@ -39,7 +39,7 @@ test -z "$(git ls-files -u)" || die_conflict
 test -f "$GIT_DIR/MERGE_HEAD" && die_merge
 
 strategy_args= diffstat= no_commit= squash= no_ff= ff_only=
-log_arg= verbosity= progress= recurse_submodules=
+log_arg= verbosity= progress= recurse_submodules= verify_signatures=
 merge_args= edit=
 curr_branch=$(git symbolic-ref -q HEAD)
 curr_branch_short="${curr_branch#refs/heads/}"
@@ -125,6 +125,12 @@ do
        --no-recurse-submodules)
                recurse_submodules=--no-recurse-submodules
                ;;
+       --verify-signatures)
+               verify_signatures=--verify-signatures
+               ;;
+       --no-verify-signatures)
+               verify_signatures=--no-verify-signatures
+               ;;
        --d|--dr|--dry|--dry-|--dry-r|--dry-ru|--dry-run)
                dry_run=--dry-run
                ;;
@@ -283,7 +289,7 @@ true)
        eval="$eval --onto $merge_head ${oldremoteref:-$merge_head}"
        ;;
 *)
-       eval="git-merge $diffstat $no_commit $edit $squash $no_ff $ff_only"
+       eval="git-merge $diffstat $no_commit $verify_signatures $edit $squash $no_ff $ff_only"
        eval="$eval  $log_arg $strategy_args $merge_args $verbosity $progress"
        eval="$eval \"\$merge_name\" HEAD $merge_head"
        ;;
index 9a6ba2b9874e12d31adeba354d8d44436ceadaf3..8e17525dd86aa614000d9b335f9671a829678901 100755 (executable)
@@ -59,7 +59,7 @@ tmp_patch="$tmp_dir/patch"
 tmp_info="$tmp_dir/info"
 
 
-# Find the intial commit
+# Find the initial commit
 commit=$(git rev-parse HEAD)
 
 mkdir $tmp_dir || exit 2
index 97f31dc7af43bafe36d3222ba2f78da861a4e620..f84854f09a14b92790bad543cbe78c2662def9f7 100644 (file)
@@ -31,8 +31,8 @@ else
        rm -f "$GIT_DIR/rebased-patches"
 
        git format-patch -k --stdout --full-index --ignore-if-in-upstream \
-               --src-prefix=a/ --dst-prefix=b/ \
-               --no-renames $root_flag "$revisions" >"$GIT_DIR/rebased-patches"
+               --src-prefix=a/ --dst-prefix=b/ --no-renames --no-cover-letter \
+               $root_flag "$revisions" >"$GIT_DIR/rebased-patches"
        ret=$?
 
        if test 0 != $ret
index c3501d987e66d330189f156590316d335b580aaf..bd13cc812d2a0115edcdd2c3ec146665ddfc5e29 100755 (executable)
@@ -54,7 +54,7 @@ sub usage {
     --[no-]bcc              <str>  * Email Bcc:
     --subject               <str>  * Email "Subject:"
     --in-reply-to           <str>  * Email "In-Reply-To:"
-    --annotate                     * Review each patch that will be sent in an editor.
+    --[no-]annotate                * Review each patch that will be sent in an editor.
     --compose                      * Open an editor for introduction.
     --compose-encoding      <str>  * Encoding to assume for introduction.
     --8bit-encoding         <str>  * Encoding to assume 8bit mails if undeclared
@@ -212,7 +212,8 @@ sub do_edit {
     "signedoffbycc" => [\$signed_off_by_cc, undef],
     "signedoffcc" => [\$signed_off_by_cc, undef],      # Deprecated
     "validate" => [\$validate, 1],
-    "multiedit" => [\$multiedit, undef]
+    "multiedit" => [\$multiedit, undef],
+    "annotate" => [\$annotate, undef]
 );
 
 my %config_settings = (
@@ -304,7 +305,7 @@ sub signal_handler {
                    "smtp-debug:i" => \$debug_net_smtp,
                    "smtp-domain:s" => \$smtp_domain,
                    "identity=s" => \$identity,
-                   "annotate" => \$annotate,
+                   "annotate!" => \$annotate,
                    "compose" => \$compose,
                    "quiet" => \$quiet,
                    "cc-cmd=s" => \$cc_cmd,
@@ -512,8 +513,9 @@ sub split_addrs {
 
 ($sender) = expand_aliases($sender) if defined $sender;
 
-# returns 1 if the conflict must be solved using it as a format-patch argument
-sub check_file_rev_conflict($) {
+# is_format_patch_arg($f) returns 0 if $f names a patch, or 1 if
+# $f is a revision list specification to be passed to format-patch.
+sub is_format_patch_arg {
        return unless $repo;
        my $f = shift;
        try {
@@ -529,6 +531,7 @@ ($)
     * Giving --format-patch option if you mean a range.
 EOF
        } catch Git::Error::Command with {
+               # Not a valid revision.  Treat it as a filename.
                return 0;
        }
 }
@@ -540,14 +543,14 @@ ($)
        if ($f eq "--") {
                push @rev_list_opts, "--", @ARGV;
                @ARGV = ();
-       } elsif (-d $f and !check_file_rev_conflict($f)) {
+       } elsif (-d $f and !is_format_patch_arg($f)) {
                opendir my $dh, $f
                        or die "Failed to opendir $f: $!";
 
                push @files, grep { -f $_ } map { catfile($f, $_) }
                                sort readdir $dh;
                closedir $dh;
-       } elsif ((-f $f or -p $f) and !check_file_rev_conflict($f)) {
+       } elsif ((-f $f or -p $f) and !is_format_patch_arg($f)) {
                push @files, $f;
        } else {
                push @rev_list_opts, $f;
@@ -711,7 +714,7 @@ sub ask {
                        }
                }
        }
-       return undef;
+       return;
 }
 
 my %broken_encoding;
@@ -833,7 +836,7 @@ sub extract_valid_address {
        # less robust/correct than the monster regexp in Email::Valid,
        # but still does a 99% job, and one less dependency
        return $1 if $address =~ /($local_part_regexp\@$domain_regexp)/;
-       return undef;
+       return;
 }
 
 sub extract_valid_address_or_die {
@@ -1453,7 +1456,7 @@ sub recipients_cmd {
 
        my $sanitized_sender = sanitize_address($sender);
        my @addresses = ();
-       open my $fh, "$cmd \Q$file\E |"
+       open my $fh, "-|", "$cmd \Q$file\E"
            or die "($prefix) Could not execute '$cmd'";
        while (my $address = <$fh>) {
                $address =~ s/^\s*//g;
@@ -1499,7 +1502,7 @@ sub validate_patch {
                        return "$.: patch contains a line longer than 998 characters";
                }
        }
-       return undef;
+       return;
 }
 
 sub file_has_nonascii {
index 204bc78a9fdffcd11c397a85f94636bb17529b91..79bfaac9d4cb9a04e5e1fd7675d740cf9fc27e87 100755 (executable)
@@ -267,6 +267,11 @@ module_clone()
        (clear_local_git_env; cd "$sm_path" && GIT_WORK_TREE=. git config core.worktree "$rel/$b")
 }
 
+isnumber()
+{
+       n=$(($1 + 0)) 2>/dev/null && test "$n" = "$1"
+}
+
 #
 # Add a new submodule to the working tree, .gitmodules and the index
 #
@@ -601,10 +606,12 @@ cmd_deinit()
 
                        if test -z "$force"
                        then
-                               git rm -n "$sm_path" ||
+                               git rm -qn "$sm_path" ||
                                die "$(eval_gettext "Submodule work tree '\$sm_path' contains local modifications; use '-f' to discard them")"
                        fi
-                       rm -rf "$sm_path" || say "$(eval_gettext "Could not remove submodule work tree '\$sm_path'")"
+                       rm -rf "$sm_path" &&
+                       say "$(eval_gettext "Cleared directory '\$sm_path'")" ||
+                       say "$(eval_gettext "Could not remove submodule work tree '\$sm_path'")"
                fi
 
                mkdir "$sm_path" || say "$(eval_gettext "Could not create empty submodule directory '\$sm_path'")"
@@ -889,14 +896,14 @@ cmd_summary() {
                        for_status="$1"
                        ;;
                -n|--summary-limit)
-                       if summary_limit=$(($2 + 0)) 2>/dev/null && test "$summary_limit" = "$2"
-                       then
-                               :
-                       else
-                               usage
-                       fi
+                       summary_limit="$2"
+                       isnumber "$summary_limit" || usage
                        shift
                        ;;
+               --summary-limit=*)
+                       summary_limit="${1#--summary-limit=}"
+                       isnumber "$summary_limit" || usage
+                       ;;
                --)
                        shift
                        break
index 1e827264b4cab04a801804b8d066f9d2cbb85edc..9f446798d473cee7dedc82d5d2c820cb0967b375 100755 (executable)
@@ -119,8 +119,8 @@ if test -z "$browser" ; then
                browser_candidates="w3m elinks links lynx"
        fi
        # SECURITYSESSIONID indicates an OS X GUI login session
-       if test -n "$SECURITYSESSIONID" \
-               -o "$TERM_PROGRAM" = "Apple_Terminal" ; then
+       if test -n "$SECURITYSESSIONID" || test -n "$TERM_PROGRAM"
+       then
                browser_candidates="open $browser_candidates"
        fi
        # /bin/start indicates MinGW
diff --git a/git.c b/git.c
index 850d3f5527f4100f45cb5eb1a7d8772e04ae4443..1ada169d5cff3051effee33c6f9ba5b9be15b2e6 100644 (file)
--- a/git.c
+++ b/git.c
@@ -13,7 +13,9 @@ const char git_usage_string[] =
        "           <command> [<args>]";
 
 const char git_more_info_string[] =
-       N_("See 'git help <command>' for more information on a specific command.");
+       N_("'git help -a' and 'git help -g' lists available subcommands and some\n"
+          "concept guides. See 'git help <command>' or 'git help <concept>'\n"
+          "to read about a specific subcommand or concept.");
 
 static struct startup_info git_startup_info;
 static int use_pager = -1;
index 6d4540679731bdfd33af61635c59b798b19a8888..08f3dda02d43f9b2e994ee2f7a8dccaecb82733e 100644 (file)
@@ -244,7 +244,7 @@ for gitweb (in gitweb/README), and gitweb.conf(5) manpage.
   through the GITWEB_CONFIG_SYSTEM environment variable.
 
   Note that if per-instance configuration file exists, then system-wide
-  configuration is _not used at all_.  This is quite untypical and suprising
+  configuration is _not used at all_.  This is quite untypical and surprising
   behavior.  On the other hand changing current behavior would break backwards
   compatibility and can lead to unexpected changes in gitweb behavior.
   Therefore gitweb also looks for common system-wide configuration file,
index 1309196d27e675013825cdac8afd6d7328e44b1f..80950c018d54f3bbb7b700286b4923d39cbe2d00 100755 (executable)
@@ -683,7 +683,7 @@ sub evaluate_gitweb_config {
        our $GITWEB_CONFIG_SYSTEM = $ENV{'GITWEB_CONFIG_SYSTEM'} || "++GITWEB_CONFIG_SYSTEM++";
        our $GITWEB_CONFIG_COMMON = $ENV{'GITWEB_CONFIG_COMMON'} || "++GITWEB_CONFIG_COMMON++";
 
-       # Protect agains duplications of file names, to not read config twice.
+       # Protect against duplications of file names, to not read config twice.
        # Only one of $GITWEB_CONFIG and $GITWEB_CONFIG_SYSTEM is used, so
        # there possibility of duplication of filename there doesn't matter.
        $GITWEB_CONFIG = ""        if ($GITWEB_CONFIG eq $GITWEB_CONFIG_COMMON);
@@ -1136,7 +1136,7 @@ sub handle_errors_html {
 
        # to avoid infinite loop where error occurs in die_error,
        # change handler to default handler, disabling handle_errors_html
-       set_message("Error occured when inside die_error:\n$msg");
+       set_message("Error occurred when inside die_error:\n$msg");
 
        # you cannot jump out of die_error when called as error handler;
        # the subroutine set via CGI::Carp::set_message is called _after_
@@ -7485,7 +7485,7 @@ sub git_object {
                system(git_cmd(), "cat-file", '-e', $hash_base) == 0
                        or die_error(404, "Base object does not exist");
 
-               # here errors should not hapen
+               # here errors should not happen
                open my $fd, "-|", git_cmd(), "ls-tree", $hash_base, "--", $file_name
                        or die_error(500, "Open git-ls-tree failed");
                my $line = <$fd>;
index cf9902184272d20c6d5826cf9f10dcaebeb3e6e8..a85cb5bc97cdd61000b4c48c54faa656aa3cfaca 100644 (file)
@@ -1,6 +1,18 @@
 #ifndef GPG_INTERFACE_H
 #define GPG_INTERFACE_H
 
+struct signature_check {
+       char *gpg_output;
+       char *gpg_status;
+       char result; /* 0 (not checked),
+                     * N (checked but no further result),
+                     * U (untrusted good),
+                     * G (good)
+                     * B (bad) */
+       char *signer;
+       char *key;
+};
+
 extern int sign_buffer(struct strbuf *buffer, struct strbuf *signature, const char *signing_key);
 extern int verify_signed_buffer(const char *payload, size_t payload_size, const char *signature, size_t signature_size, struct strbuf *gpg_output, struct strbuf *gpg_status);
 extern int git_gpg_config(const char *, const char *, void *);
diff --git a/help.c b/help.c
index 1dfa0b05827e6e75dc463092b2838cd1c991623c..02ba043319932411e90121d4147f25395782dfb5 100644 (file)
--- a/help.c
+++ b/help.c
@@ -397,6 +397,10 @@ const char *help_unknown_cmd(const char *cmd)
 
 int cmd_version(int argc, const char **argv, const char *prefix)
 {
+       /*
+        * The format of this string should be kept stable for compatibility
+        * with external projects that rely on the output of "git version".
+        */
        printf("git version %s\n", git_version_string);
        return 0;
 }
index 8144f3ad5eb68c789fd031921e6e702170310d68..6b85ffac271596cf469984a06d27423af7df2b35 100644 (file)
@@ -361,17 +361,19 @@ static void run_service(const char **argv)
 static int show_text_ref(const char *name, const unsigned char *sha1,
        int flag, void *cb_data)
 {
+       const char *name_nons = strip_namespace(name);
        struct strbuf *buf = cb_data;
        struct object *o = parse_object(sha1);
        if (!o)
                return 0;
 
-       strbuf_addf(buf, "%s\t%s\n", sha1_to_hex(sha1), name);
+       strbuf_addf(buf, "%s\t%s\n", sha1_to_hex(sha1), name_nons);
        if (o->type == OBJ_TAG) {
                o = deref_tag(o, name, 0);
                if (!o)
                        return 0;
-               strbuf_addf(buf, "%s\t%s^{}\n", sha1_to_hex(o->sha1), name);
+               strbuf_addf(buf, "%s\t%s^{}\n", sha1_to_hex(o->sha1),
+                           name_nons);
        }
        return 0;
 }
@@ -402,12 +404,40 @@ static void get_info_refs(char *arg)
 
        } else {
                select_getanyfile();
-               for_each_ref(show_text_ref, &buf);
+               for_each_namespaced_ref(show_text_ref, &buf);
                send_strbuf("text/plain", &buf);
        }
        strbuf_release(&buf);
 }
 
+static int show_head_ref(const char *name, const unsigned char *sha1,
+       int flag, void *cb_data)
+{
+       struct strbuf *buf = cb_data;
+
+       if (flag & REF_ISSYMREF) {
+               unsigned char sha1[20];
+               const char *target = resolve_ref_unsafe(name, sha1, 1, NULL);
+               const char *target_nons = strip_namespace(target);
+
+               strbuf_addf(buf, "ref: %s\n", target_nons);
+       } else {
+               strbuf_addf(buf, "%s\n", sha1_to_hex(sha1));
+       }
+
+       return 0;
+}
+
+static void get_head(char *arg)
+{
+       struct strbuf buf = STRBUF_INIT;
+
+       select_getanyfile();
+       head_ref_namespaced(show_head_ref, &buf);
+       send_strbuf("text/plain", &buf);
+       strbuf_release(&buf);
+}
+
 static void get_info_packs(char *arg)
 {
        size_t objdirlen = strlen(get_object_directory());
@@ -520,7 +550,7 @@ static struct service_cmd {
        const char *pattern;
        void (*imp)(char *);
 } services[] = {
-       {"GET", "/HEAD$", get_text_file},
+       {"GET", "/HEAD$", get_head},
        {"GET", "/info/refs$", get_info_refs},
        {"GET", "/objects/info/alternates$", get_text_file},
        {"GET", "/objects/info/http-alternates$", get_text_file},
index bd66f6ab6edd24946d2bc84e117a2b97417b1503..395a8cfc1055fb6febc9cee559d8943bb4d9e829 100644 (file)
@@ -1551,7 +1551,7 @@ static int remote_exists(const char *path)
                ret = 0;
                break;
        case HTTP_ERROR:
-               http_error(url, HTTP_ERROR);
+               error("unable to access '%s': %s", url, curl_errorstr);
        default:
                ret = -1;
        }
diff --git a/http.c b/http.c
index 8803c70825ac8aefb619b6c56d6015573eb5d227..92aba59082a4ed9aa0c92d8522793abcd332e279 100644 (file)
--- a/http.c
+++ b/http.c
@@ -31,6 +31,7 @@ static CURL *curl_default;
 char curl_errorstr[CURL_ERROR_SIZE];
 
 static int curl_ssl_verify = -1;
+static int curl_ssl_try;
 static const char *ssl_cert;
 #if LIBCURL_VERSION_NUM >= 0x070903
 static const char *ssl_key;
@@ -163,6 +164,10 @@ static int http_options(const char *var, const char *value, void *cb)
                        ssl_cert_password_required = 1;
                return 0;
        }
+       if (!strcmp("http.ssltry", var)) {
+               curl_ssl_try = git_config_bool(var, value);
+               return 0;
+       }
        if (!strcmp("http.minsessions", var)) {
                min_curl_sessions = git_config_int(var, value);
 #ifndef USE_CURL_MULTI
@@ -282,7 +287,6 @@ static CURL *get_curl_handle(void)
 #endif
        if (ssl_cainfo != NULL)
                curl_easy_setopt(result, CURLOPT_CAINFO, ssl_cainfo);
-       curl_easy_setopt(result, CURLOPT_FAILONERROR, 1);
 
        if (curl_low_speed_limit > 0 && curl_low_speed_time > 0) {
                curl_easy_setopt(result, CURLOPT_LOW_SPEED_LIMIT,
@@ -307,6 +311,11 @@ static CURL *get_curl_handle(void)
        if (curl_ftp_no_epsv)
                curl_easy_setopt(result, CURLOPT_FTP_USE_EPSV, 0);
 
+#ifdef CURLOPT_USE_SSL
+       if (curl_ssl_try)
+               curl_easy_setopt(result, CURLOPT_USE_SSL, CURLUSESSL_TRY);
+#endif
+
        if (curl_http_proxy) {
                curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy);
                curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
@@ -506,6 +515,7 @@ struct active_request_slot *get_active_slot(void)
        curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, NULL);
        curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0);
        curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
+       curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1);
        if (http_auth.password)
                init_curl_http_auth(slot->curl);
 
@@ -761,6 +771,25 @@ char *get_remote_object_url(const char *url, const char *hex,
 
 int handle_curl_result(struct slot_results *results)
 {
+       /*
+        * If we see a failing http code with CURLE_OK, we have turned off
+        * FAILONERROR (to keep the server's custom error response), and should
+        * translate the code into failure here.
+        */
+       if (results->curl_result == CURLE_OK &&
+           results->http_code >= 400) {
+               results->curl_result = CURLE_HTTP_RETURNED_ERROR;
+               /*
+                * Normally curl will already have put the "reason phrase"
+                * from the server into curl_errorstr; unfortunately without
+                * FAILONERROR it is lost, so we can give only the numeric
+                * status code.
+                */
+               snprintf(curl_errorstr, sizeof(curl_errorstr),
+                        "The requested URL returned error: %ld",
+                        results->http_code);
+       }
+
        if (results->curl_result == CURLE_OK) {
                credential_approve(&http_auth);
                return HTTP_OK;
@@ -825,6 +854,8 @@ static int http_request(const char *url, struct strbuf *type,
        strbuf_addstr(&buf, "Pragma:");
        if (options & HTTP_NO_CACHE)
                strbuf_addstr(&buf, " no-cache");
+       if (options & HTTP_KEEP_ERROR)
+               curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 0);
 
        headers = curl_slist_append(headers, buf.buf);
 
@@ -836,7 +867,8 @@ static int http_request(const char *url, struct strbuf *type,
                run_active_slot(slot);
                ret = handle_curl_result(&results);
        } else {
-               error("Unable to start HTTP request for %s", url);
+               snprintf(curl_errorstr, sizeof(curl_errorstr),
+                        "failed to start HTTP request");
                ret = HTTP_START_FAILED;
        }
 
@@ -862,6 +894,22 @@ static int http_request_reauth(const char *url,
        int ret = http_request(url, type, result, target, options);
        if (ret != HTTP_REAUTH)
                return ret;
+
+       /*
+        * If we are using KEEP_ERROR, the previous request may have
+        * put cruft into our output stream; we should clear it out before
+        * making our next request. We only know how to do this for
+        * the strbuf case, but that is enough to satisfy current callers.
+        */
+       if (options & HTTP_KEEP_ERROR) {
+               switch (target) {
+               case HTTP_REQUEST_STRBUF:
+                       strbuf_reset(result);
+                       break;
+               default:
+                       die("BUG: HTTP_KEEP_ERROR is only supported with strbufs");
+               }
+       }
        return http_request(url, type, result, target, options);
 }
 
@@ -903,15 +951,6 @@ static int http_get_file(const char *url, const char *filename, int options)
        return ret;
 }
 
-int http_error(const char *url, int ret)
-{
-       /* http_request has already handled HTTP_START_FAILED. */
-       if (ret != HTTP_START_FAILED)
-               error("%s while accessing %s", curl_errorstr, url);
-
-       return ret;
-}
-
 int http_fetch_ref(const char *base, struct ref *ref)
 {
        char *url;
diff --git a/http.h b/http.h
index 25d19313983f0d0a11ab50dffbb623b105c8960a..d77c1b54f24d142461b9e1a0d11cf6de041bc59f 100644 (file)
--- a/http.h
+++ b/http.h
 #define NO_CURL_IOCTL
 #endif
 
+/*
+ * CURLOPT_USE_SSL was known as CURLOPT_FTP_SSL up to 7.16.4,
+ * and the constants were known as CURLFTPSSL_*
+*/
+#if !defined(CURLOPT_USE_SSL) && defined(CURLOPT_FTP_SSL)
+#define CURLOPT_USE_SSL CURLOPT_FTP_SSL
+#define CURLUSESSL_TRY CURLFTPSSL_TRY
+#endif
+
 struct slot_results {
        CURLcode curl_result;
        long http_code;
@@ -118,6 +127,7 @@ extern char *get_remote_object_url(const char *url, const char *hex,
 
 /* Options for http_request_*() */
 #define HTTP_NO_CACHE          1
+#define HTTP_KEEP_ERROR                2
 
 /* Return values for http_request_*() */
 #define HTTP_OK                        0
@@ -134,12 +144,6 @@ extern char *get_remote_object_url(const char *url, const char *hex,
  */
 int http_get_strbuf(const char *url, struct strbuf *content_type, struct strbuf *result, int options);
 
-/*
- * Prints an error message using error() containing url and curl_errorstr,
- * and returns ret.
- */
-int http_error(const char *url, int ret);
-
 extern int http_fetch_ref(const char *base, struct ref *ref);
 
 /* Helpers for fetching packs */
diff --git a/kwset.c b/kwset.c
index 51b2ab6c7e61413851a958f7a4009a0194744b68..5800999b4c16cd8f5eeb2301f72c33ec62c5ea71 100644 (file)
--- a/kwset.c
+++ b/kwset.c
@@ -26,7 +26,7 @@
    The author may be reached (Email) at the address mike@ai.mit.edu,
    or (US mail) as Mike Haertel c/o Free Software Foundation. */
 
-/* The algorithm implemented by these routines bears a startling resemblence
+/* The algorithm implemented by these routines bears a startling resemblance
    to one discovered by Beate Commentz-Walter, although it is not identical.
    See "A String Matching Algorithm Fast on the Average," Technical Report,
    IBM-Germany, Scientific Center Heidelberg, Tiergartenstrasse 15, D-6900
@@ -435,7 +435,7 @@ kwsprep (kwset_t kws)
          /* Update the delta table for the descendents of this node. */
          treedelta(curr->links, curr->depth, delta);
 
-         /* Compute the failure function for the decendents of this node. */
+         /* Compute the failure function for the descendants of this node. */
          treefails(curr->links, curr->fail, kwset->trie);
 
          /* Update the shifts at each node in the current node's chain
index 92bb2bf48e641ee6161a0e10dd87d9ce06632f7c..7cc7d598e712fab531f7c6f938be17c317161f3e 100644 (file)
@@ -709,11 +709,14 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
 {
        int showed_log;
        struct commit_list *parents;
-       unsigned const char *sha1 = commit->object.sha1;
+       unsigned const char *sha1;
 
        if (!opt->diff && !DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS))
                return 0;
 
+       parse_commit(commit);
+       sha1 = commit->tree->object.sha1;
+
        /* Root commit? */
        parents = commit->parents;
        if (!parents) {
@@ -736,7 +739,9 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
                         * parent, showing summary diff of the others
                         * we merged _in_.
                         */
-                       diff_tree_sha1(parents->item->object.sha1, sha1, "", &opt->diffopt);
+                       parse_commit(parents->item);
+                       diff_tree_sha1(parents->item->tree->object.sha1,
+                                      sha1, "", &opt->diffopt);
                        log_tree_diff_flush(opt);
                        return !opt->loginfo;
                }
@@ -749,7 +754,9 @@ static int log_tree_diff(struct rev_info *opt, struct commit *commit, struct log
        for (;;) {
                struct commit *parent = parents->item;
 
-               diff_tree_sha1(parent->object.sha1, sha1, "", &opt->diffopt);
+               parse_commit(parent);
+               diff_tree_sha1(parent->tree->object.sha1,
+                              sha1, "", &opt->diffopt);
                log_tree_diff_flush(opt);
 
                showed_log |= !opt->loginfo;
index 26f7ed143e0649b6377ea427b5c57ca7ddb663d3..2bb734d51cbe59e3eed7c82e7522c594d5efa579 100644 (file)
@@ -47,6 +47,13 @@ static int score_matches(unsigned mode1, unsigned mode2, const char *path)
        return score;
 }
 
+static int base_name_entries_compare(const struct name_entry *a,
+                                    const struct name_entry *b)
+{
+       return base_name_compare(a->path, tree_entry_len(a), a->mode,
+                                b->path, tree_entry_len(b), b->mode);
+}
+
 /*
  * Inspect two trees, and give a score that tells how similar they are.
  */
@@ -71,54 +78,35 @@ static int score_trees(const unsigned char *hash1, const unsigned char *hash2)
        if (type != OBJ_TREE)
                die("%s is not a tree", sha1_to_hex(hash2));
        init_tree_desc(&two, two_buf, size);
-       while (one.size | two.size) {
-               const unsigned char *elem1 = elem1;
-               const unsigned char *elem2 = elem2;
-               const char *path1 = path1;
-               const char *path2 = path2;
-               unsigned mode1 = mode1;
-               unsigned mode2 = mode2;
+       for (;;) {
+               struct name_entry e1, e2;
+               int got_entry_from_one = tree_entry(&one, &e1);
+               int got_entry_from_two = tree_entry(&two, &e2);
                int cmp;
 
-               if (one.size)
-                       elem1 = tree_entry_extract(&one, &path1, &mode1);
-               if (two.size)
-                       elem2 = tree_entry_extract(&two, &path2, &mode2);
-
-               if (!one.size) {
-                       /* two has more entries */
-                       score += score_missing(mode2, path2);
-                       update_tree_entry(&two);
-                       continue;
-               }
-               if (!two.size) {
+               if (got_entry_from_one && got_entry_from_two)
+                       cmp = base_name_entries_compare(&e1, &e2);
+               else if (got_entry_from_one)
                        /* two lacks this entry */
-                       score += score_missing(mode1, path1);
-                       update_tree_entry(&one);
-                       continue;
-               }
-               cmp = base_name_compare(path1, strlen(path1), mode1,
-                                       path2, strlen(path2), mode2);
-               if (cmp < 0) {
+                       cmp = -1;
+               else if (got_entry_from_two)
+                       /* two has more entries */
+                       cmp = 1;
+               else
+                       break;
+
+               if (cmp < 0)
                        /* path1 does not appear in two */
-                       score += score_missing(mode1, path1);
-                       update_tree_entry(&one);
-                       continue;
-               }
-               else if (cmp > 0) {
+                       score += score_missing(e1.mode, e1.path);
+               else if (cmp > 0)
                        /* path2 does not appear in one */
-                       score += score_missing(mode2, path2);
-                       update_tree_entry(&two);
-                       continue;
-               }
-               else if (hashcmp(elem1, elem2))
+                       score += score_missing(e2.mode, e2.path);
+               else if (hashcmp(e1.sha1, e2.sha1))
                        /* they are different */
-                       score += score_differs(mode1, mode2, path1);
+                       score += score_differs(e1.mode, e2.mode, e1.path);
                else
                        /* same subtree or blob */
-                       score += score_matches(mode1, mode2, path1);
-               update_tree_entry(&one);
-               update_tree_entry(&two);
+                       score += score_matches(e1.mode, e2.mode, e1.path);
        }
        free(one_buf);
        free(two_buf);
diff --git a/path.c b/path.c
index d3d3f8b8ad75b9817df3014296aabc34b6a4eb14..04ff1487ed31685b6b3f7923f9bfbfc7217f70a0 100644 (file)
--- a/path.c
+++ b/path.c
@@ -1,19 +1,26 @@
 /*
- * I'm tired of doing "vsnprintf()" etc just to open a
- * file, so here's a "return static buffer with printf"
- * interface for paths.
- *
- * It's obviously not thread-safe. Sue me. But it's quite
- * useful for doing things like
- *
- *   f = open(mkpath("%s/%s.git", base, name), O_RDONLY);
- *
- * which is what it's designed for.
+ * Utilities for paths and pathnames
  */
 #include "cache.h"
 #include "strbuf.h"
 #include "string-list.h"
 
+#ifndef get_st_mode_bits
+/*
+ * The replacement lstat(2) we use on Cygwin is incomplete and
+ * may return wrong permission bits. Most of the time we do not care,
+ * but the callsites of this wrapper do care.
+ */
+int get_st_mode_bits(const char *path, int *mode)
+{
+       struct stat st;
+       if (lstat(path, &st) < 0)
+               return -1;
+       *mode = st.st_mode;
+       return 0;
+}
+#endif
+
 static char bad_path[] = "/bad-path/";
 
 static char *get_pathname(void)
@@ -389,28 +396,14 @@ const char *enter_repo(const char *path, int strict)
        return NULL;
 }
 
-int set_shared_perm(const char *path, int mode)
+static int calc_shared_perm(int mode)
 {
-       struct stat st;
-       int tweak, shared, orig_mode;
+       int tweak;
 
-       if (!shared_repository) {
-               if (mode)
-                       return chmod(path, mode & ~S_IFMT);
-               return 0;
-       }
-       if (!mode) {
-               if (lstat(path, &st) < 0)
-                       return -1;
-               mode = st.st_mode;
-               orig_mode = mode;
-       } else
-               orig_mode = 0;
        if (shared_repository < 0)
-               shared = -shared_repository;
+               tweak = -shared_repository;
        else
-               shared = shared_repository;
-       tweak = shared;
+               tweak = shared_repository;
 
        if (!(mode & S_IWUSR))
                tweak &= ~0222;
@@ -422,16 +415,28 @@ int set_shared_perm(const char *path, int mode)
        else
                mode |= tweak;
 
-       if (S_ISDIR(mode)) {
+       return mode;
+}
+
+
+int adjust_shared_perm(const char *path)
+{
+       int old_mode, new_mode;
+
+       if (!shared_repository)
+               return 0;
+       if (get_st_mode_bits(path, &old_mode) < 0)
+               return -1;
+
+       new_mode = calc_shared_perm(old_mode);
+       if (S_ISDIR(old_mode)) {
                /* Copy read bits to execute bits */
-               mode |= (shared & 0444) >> 2;
-               mode |= FORCE_DIR_SET_GID;
+               new_mode |= (new_mode & 0444) >> 2;
+               new_mode |= FORCE_DIR_SET_GID;
        }
 
-       if (((shared_repository < 0
-             ? (orig_mode & (FORCE_DIR_SET_GID | 0777))
-             : (orig_mode & mode)) != mode) &&
-           chmod(path, (mode & ~S_IFMT)) < 0)
+       if (((old_mode ^ new_mode) & ~S_IFMT) &&
+                       chmod(path, (new_mode & ~S_IFMT)) < 0)
                return -2;
        return 0;
 }
index 96cac39a4c8ebc0ce4e111271429fdf68b03bf97..dc48159ccab1cf2f888a6169460c5fc60d0d1bab 100644 (file)
@@ -1180,7 +1180,7 @@ sub credential {
 
 =item temp_acquire ( NAME )
 
-Attempts to retreive the temporary file mapped to the string C<NAME>. If an
+Attempts to retrieve the temporary file mapped to the string C<NAME>. If an
 associated temp file has not been created this session or was closed, it is
 created, cached, and set for autoflush and binmode.
 
@@ -1489,12 +1489,12 @@ sub _command_common_pipe {
                if (not defined $pid) {
                        throw Error::Simple("open failed: $!");
                } elsif ($pid == 0) {
-                       if (defined $opts{STDERR}) {
-                               close STDERR;
-                       }
                        if ($opts{STDERR}) {
                                open (STDERR, '>&', $opts{STDERR})
                                        or die "dup failed: $!";
+                       } elsif (defined $opts{STDERR}) {
+                               open (STDERR, '>', '/dev/null')
+                                       or die "opening /dev/null failed: $!";
                        }
                        _cmd_exec($self, $cmd, @args);
                }
index 40dd8971912d6b387bde7c9bb04cc6896521acec..f889fd6da91d2d9b6a7469442a02e5478f094f8d 100644 (file)
@@ -68,7 +68,7 @@ =head1 SYNOPSIS
 
        print __("Welcome to Git!\n");
 
-       printf __("The following error occured: %s\n"), $error;
+       printf __("The following error occurred: %s\n"), $error;
 
 =head1 DESCRIPTION
 
index 11e9cd9a02eb3f85a9150c6fb06d1fc76abd9b09..6098135ae2b2d473729373b69e776f475cf919dd 100644 (file)
@@ -630,7 +630,7 @@ =head1 CLASS INTERFACE
 =head2 CONSTRUCTORS
 
 The C<Error> object is implemented as a HASH. This HASH is initialized
-with the arguments that are passed to it's constructor. The elements
+with the arguments that are passed to its constructor. The elements
 that are used by, or are retrievable by the C<Error> class are listed
 below, other classes may add to these.
 
@@ -763,13 +763,13 @@ =head1 PRE-DEFINED ERROR CLASSES
 
 =item Error::Simple
 
-This class can be used to hold simple error strings and values. It's
+This class can be used to hold simple error strings and values. Its
 constructor takes two arguments. The first is a text value, the second
 is a numeric value. These values are what will be returned by the
 overload methods.
 
 If the text value ends with C<at file line 1> as $@ strings do, then
-this infomation will be used to set the C<-file> and C<-line> arguments
+this information will be used to set the C<-file> and C<-line> arguments
 of the error object.
 
 This class is used internally if an eval'd block die's with an error
index c1520e8cdeaf5ab5c52d2ae057582cd8f32b7fe6..d8c9111c82a541a39d71465c9b18a626d2dea94e 100644 (file)
--- a/po/README
+++ b/po/README
@@ -232,7 +232,7 @@ Shell:
 
        # To interpolate variables:
        details="oh noes"
-       eval_gettext "An error occured: \$details"; echo
+       eval_gettext "An error occurred: \$details"; echo
 
    In addition we have wrappers for messages that end with a trailing
    newline. I.e. you could write the above as:
@@ -242,7 +242,7 @@ Shell:
 
        # To interpolate variables:
        details="oh noes"
-       eval_gettextln "An error occured: \$details"
+       eval_gettextln "An error occurred: \$details"
 
    More documentation about the interface is available in the GNU info
    page: `info '(gettext)sh'`. Looking at git-am.sh (the first shell
@@ -257,7 +257,7 @@ Perl:
 
        use Git::I18N;
        print __("Welcome to Git!\n");
-       printf __("The following error occured: %s\n"), $error;
+       printf __("The following error occurred: %s\n"), $error;
 
    Run `perldoc perl/Git/I18N.pm` for more info.
 
index 41f04e669d3b9c38f49e0853053a6ba27b97357a..d3a82d22d398ae7234f8917f4d8b0770ba4d0c47 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -766,14 +766,7 @@ struct format_commit_context {
        const struct pretty_print_context *pretty_ctx;
        unsigned commit_header_parsed:1;
        unsigned commit_message_parsed:1;
-       unsigned commit_signature_parsed:1;
-       struct {
-               char *gpg_output;
-               char *gpg_status;
-               char good_bad;
-               char *signer;
-               char *key;
-       } signature;
+       struct signature_check signature_check;
        char *message;
        size_t width, indent1, indent2;
 
@@ -956,64 +949,6 @@ static void rewrap_message_tail(struct strbuf *sb,
        c->indent2 = new_indent2;
 }
 
-static struct {
-       char result;
-       const char *check;
-} signature_check[] = {
-       { 'G', "\n[GNUPG:] GOODSIG " },
-       { 'B', "\n[GNUPG:] BADSIG " },
-};
-
-static void parse_signature_lines(struct format_commit_context *ctx)
-{
-       const char *buf = ctx->signature.gpg_status;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(signature_check); i++) {
-               const char *found = strstr(buf, signature_check[i].check);
-               const char *next;
-               if (!found)
-                       continue;
-               ctx->signature.good_bad = signature_check[i].result;
-               found += strlen(signature_check[i].check);
-               ctx->signature.key = xmemdupz(found, 16);
-               found += 17;
-               next = strchrnul(found, '\n');
-               ctx->signature.signer = xmemdupz(found, next - found);
-               break;
-       }
-}
-
-static void parse_commit_signature(struct format_commit_context *ctx)
-{
-       struct strbuf payload = STRBUF_INIT;
-       struct strbuf signature = STRBUF_INIT;
-       struct strbuf gpg_output = STRBUF_INIT;
-       struct strbuf gpg_status = STRBUF_INIT;
-       int status;
-
-       ctx->commit_signature_parsed = 1;
-
-       if (parse_signed_commit(ctx->commit->object.sha1,
-                               &payload, &signature) <= 0)
-               goto out;
-       status = verify_signed_buffer(payload.buf, payload.len,
-                                     signature.buf, signature.len,
-                                     &gpg_output, &gpg_status);
-       if (status && !gpg_output.len)
-               goto out;
-       ctx->signature.gpg_output = strbuf_detach(&gpg_output, NULL);
-       ctx->signature.gpg_status = strbuf_detach(&gpg_status, NULL);
-       parse_signature_lines(ctx);
-
- out:
-       strbuf_release(&gpg_status);
-       strbuf_release(&gpg_output);
-       strbuf_release(&payload);
-       strbuf_release(&signature);
-}
-
-
 static int format_reflog_person(struct strbuf *sb,
                                char part,
                                struct reflog_walk_info *log,
@@ -1199,27 +1134,29 @@ static size_t format_commit_one(struct strbuf *sb, const char *placeholder,
        }
 
        if (placeholder[0] == 'G') {
-               if (!c->commit_signature_parsed)
-                       parse_commit_signature(c);
+               if (!c->signature_check.result)
+                       check_commit_signature(c->commit, &(c->signature_check));
                switch (placeholder[1]) {
                case 'G':
-                       if (c->signature.gpg_output)
-                               strbuf_addstr(sb, c->signature.gpg_output);
+                       if (c->signature_check.gpg_output)
+                               strbuf_addstr(sb, c->signature_check.gpg_output);
                        break;
                case '?':
-                       switch (c->signature.good_bad) {
+                       switch (c->signature_check.result) {
                        case 'G':
                        case 'B':
-                               strbuf_addch(sb, c->signature.good_bad);
+                       case 'U':
+                       case 'N':
+                               strbuf_addch(sb, c->signature_check.result);
                        }
                        break;
                case 'S':
-                       if (c->signature.signer)
-                               strbuf_addstr(sb, c->signature.signer);
+                       if (c->signature_check.signer)
+                               strbuf_addstr(sb, c->signature_check.signer);
                        break;
                case 'K':
-                       if (c->signature.key)
-                               strbuf_addstr(sb, c->signature.key);
+                       if (c->signature_check.key)
+                               strbuf_addstr(sb, c->signature_check.key);
                        break;
                }
                return 2;
@@ -1357,8 +1294,8 @@ void format_commit_message(const struct commit *commit,
        rewrap_message_tail(sb, &context, 0, 0, 0);
 
        logmsg_free(context.message, commit);
-       free(context.signature.gpg_output);
-       free(context.signature.signer);
+       free(context.signature_check.gpg_output);
+       free(context.signature_check.signer);
 }
 
 static void pp_header(const struct pretty_print_context *pp,
index 3971f49f4ddaa774806bd1717379a1edd22ba17c..10652b174d1ccfb941b3d4122a882f1af3323084 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "git-compat-util.h"
 #include "progress.h"
+#include "strbuf.h"
 
 #define TP_IDX_MAX      8
 
@@ -112,34 +113,14 @@ static int display(struct progress *progress, unsigned n, const char *done)
        return 0;
 }
 
-static void throughput_string(struct throughput *tp, off_t total,
+static void throughput_string(struct strbuf *buf, 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) {
-               int x = total + 5243;  /* for rounding */
-               l -= snprintf(tp->display, l, ", %u.%2.2u MiB",
-                             x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20);
-       } else if (total > 1 << 10) {
-               int x = total + 5;  /* for rounding */
-               l -= snprintf(tp->display, l, ", %u.%2.2u KiB",
-                             x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10);
-       } else {
-               l -= snprintf(tp->display, l, ", %u bytes", (int)total);
-       }
-
-       if (rate > 1 << 10) {
-               int x = rate + 5;  /* for rounding */
-               snprintf(tp->display + sizeof(tp->display) - l, l,
-                        " | %u.%2.2u MiB/s",
-                        x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10);
-       } else if (rate)
-               snprintf(tp->display + sizeof(tp->display) - l, l,
-                        " | %u KiB/s", rate);
+       strbuf_addstr(buf, ", ");
+       strbuf_humanise_bytes(buf, total);
+       strbuf_addstr(buf, " | ");
+       strbuf_humanise_bytes(buf, rate * 1024);
+       strbuf_addstr(buf, "/s");
 }
 
 void display_throughput(struct progress *progress, off_t total)
@@ -183,6 +164,7 @@ void display_throughput(struct progress *progress, off_t total)
        misecs += (int)(tv.tv_usec - tp->prev_tv.tv_usec) / 977;
 
        if (misecs > 512) {
+               struct strbuf buf = STRBUF_INIT;
                unsigned int count, rate;
 
                count = total - tp->prev_total;
@@ -197,7 +179,9 @@ void display_throughput(struct progress *progress, off_t total)
                tp->last_misecs[tp->idx] = misecs;
                tp->idx = (tp->idx + 1) % TP_IDX_MAX;
 
-               throughput_string(tp, total, rate);
+               throughput_string(&buf, total, rate);
+               strncpy(tp->display, buf.buf, sizeof(tp->display));
+               strbuf_release(&buf);
                if (progress->last_value != -1 && progress_update)
                        display(progress, progress->last_value, NULL);
        }
@@ -253,9 +237,12 @@ void stop_progress_msg(struct progress **p_progress, const char *msg)
 
                bufp = (len < sizeof(buf)) ? buf : xmalloc(len + 1);
                if (tp) {
+                       struct strbuf strbuf = STRBUF_INIT;
                        unsigned int rate = !tp->avg_misecs ? 0 :
                                        tp->avg_bytes / tp->avg_misecs;
-                       throughput_string(tp, tp->curr_total, rate);
+                       throughput_string(&strbuf, tp->curr_total, rate);
+                       strncpy(tp->display, strbuf.buf, sizeof(tp->display));
+                       strbuf_release(&strbuf);
                }
                progress_update = 1;
                sprintf(bufp, ", %s.\n", msg);
index 5a9704f4e5b974a46bc5486373a26816c5b3b4bd..04ed561bfe7dd8fbf1988190f95eb1cc3530ff58 100644 (file)
@@ -1899,3 +1899,37 @@ int index_name_is_other(const struct index_state *istate, const char *name,
        }
        return 1;
 }
+
+void *read_blob_data_from_index(struct index_state *istate, const char *path, unsigned long *size)
+{
+       int pos, len;
+       unsigned long sz;
+       enum object_type type;
+       void *data;
+
+       len = strlen(path);
+       pos = index_name_pos(istate, path, len);
+       if (pos < 0) {
+               /*
+                * We might be in the middle of a merge, in which
+                * case we would read stage #2 (ours).
+                */
+               int i;
+               for (i = -pos - 1;
+                    (pos < 0 && i < istate->cache_nr &&
+                     !strcmp(istate->cache[i]->name, path));
+                    i++)
+                       if (ce_stage(istate->cache[i]) == 2)
+                               pos = i;
+       }
+       if (pos < 0)
+               return NULL;
+       data = read_sha1_file(istate->cache[pos]->sha1, &type, &sz);
+       if (!data || type != OBJ_BLOB) {
+               free(data);
+               return NULL;
+       }
+       if (size)
+               *size = sz;
+       return data;
+}
index 93a09a64c3b1689b0f29a26c6cdd601ef298b975..60eda6308197ad3d0b5957b9ae34e2dc15dfe5cc 100644 (file)
@@ -151,6 +151,33 @@ static void free_discovery(struct discovery *d)
        }
 }
 
+static int show_http_message(struct strbuf *type, struct strbuf *msg)
+{
+       const char *p, *eol;
+
+       /*
+        * We only show text/plain parts, as other types are likely
+        * to be ugly to look at on the user's terminal.
+        *
+        * TODO should handle "; charset=XXX", and re-encode into
+        * logoutputencoding
+        */
+       if (strcasecmp(type->buf, "text/plain"))
+               return -1;
+
+       strbuf_trim(msg);
+       if (!msg->len)
+               return -1;
+
+       p = msg->buf;
+       do {
+               eol = strchrnul(p, '\n');
+               fprintf(stderr, "remote: %.*s\n", (int)(eol - p), p);
+               p = eol + 1;
+       } while(*eol);
+       return 0;
+}
+
 static struct discovery* discover_refs(const char *service, int for_push)
 {
        struct strbuf exp = STRBUF_INIT;
@@ -176,18 +203,20 @@ static struct discovery* discover_refs(const char *service, int for_push)
        }
        refs_url = strbuf_detach(&buffer, NULL);
 
-       http_ret = http_get_strbuf(refs_url, &type, &buffer, HTTP_NO_CACHE);
+       http_ret = http_get_strbuf(refs_url, &type, &buffer,
+                                  HTTP_NO_CACHE | HTTP_KEEP_ERROR);
        switch (http_ret) {
        case HTTP_OK:
                break;
        case HTTP_MISSING_TARGET:
-               die("%s not found: did you run git update-server-info on the"
-                   " server?", refs_url);
+               show_http_message(&type, &buffer);
+               die("repository '%s' not found", url);
        case HTTP_NOAUTH:
-               die("Authentication failed");
+               show_http_message(&type, &buffer);
+               die("Authentication failed for '%s'", url);
        default:
-               http_error(refs_url, http_ret);
-               die("HTTP request failed");
+               show_http_message(&type, &buffer);
+               die("unable to access '%s': %s", url, curl_errorstr);
        }
 
        last= xcalloc(1, sizeof(*last_discovery));
index ca1edd901e4e64cb497b790f675537283c4ee1c0..68eb99bdf0ca3fedd02ab1bc93db7549b21b62d4 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -49,6 +49,7 @@ static int branches_nr;
 
 static struct branch *current_branch;
 static const char *default_remote_name;
+static const char *pushremote_name;
 static int explicit_default_remote_name;
 
 static struct rewrites rewrites;
@@ -357,13 +358,16 @@ static int handle_config(const char *key, const char *value, void *cb)
                        return 0;
                branch = make_branch(name, subkey - name);
                if (!strcmp(subkey, ".remote")) {
-                       if (!value)
-                               return config_error_nonbool(key);
-                       branch->remote_name = xstrdup(value);
+                       if (git_config_string(&branch->remote_name, key, value))
+                               return -1;
                        if (branch == current_branch) {
                                default_remote_name = branch->remote_name;
                                explicit_default_remote_name = 1;
                        }
+               } else if (!strcmp(subkey, ".pushremote")) {
+                       if (branch == current_branch)
+                               if (git_config_string(&pushremote_name, key, value))
+                                       return -1;
                } else if (!strcmp(subkey, ".merge")) {
                        if (!value)
                                return config_error_nonbool(key);
@@ -389,9 +393,16 @@ static int handle_config(const char *key, const char *value, void *cb)
                        add_instead_of(rewrite, xstrdup(value));
                }
        }
+
        if (prefixcmp(key,  "remote."))
                return 0;
        name = key + 7;
+
+       /* Handle remote.* variables */
+       if (!strcmp(name, "pushdefault"))
+               return git_config_string(&pushremote_name, key, value);
+
+       /* Handle remote.<name>.* variables */
        if (*name == '/') {
                warning("Config remote shorthand cannot begin with '/': %s",
                        name);
@@ -671,17 +682,21 @@ static int valid_remote_nick(const char *name)
        return !strchr(name, '/'); /* no slash */
 }
 
-struct remote *remote_get(const char *name)
+static struct remote *remote_get_1(const char *name, const char *pushremote_name)
 {
        struct remote *ret;
        int name_given = 0;
 
-       read_config();
        if (name)
                name_given = 1;
        else {
-               name = default_remote_name;
-               name_given = explicit_default_remote_name;
+               if (pushremote_name) {
+                       name = pushremote_name;
+                       name_given = 1;
+               } else {
+                       name = default_remote_name;
+                       name_given = explicit_default_remote_name;
+               }
        }
 
        ret = make_remote(name, 0);
@@ -700,6 +715,18 @@ struct remote *remote_get(const char *name)
        return ret;
 }
 
+struct remote *remote_get(const char *name)
+{
+       read_config();
+       return remote_get_1(name, NULL);
+}
+
+struct remote *pushremote_get(const char *name)
+{
+       read_config();
+       return remote_get_1(name, pushremote_name);
+}
+
 int remote_is_configured(const char *name)
 {
        int i;
index 8743d6ef9df69167c08f3ea9b79b91fbd6ab09d3..cf5672466151254b92582ba4729a2a95e670beff 100644 (file)
--- a/remote.h
+++ b/remote.h
@@ -51,6 +51,7 @@ struct remote {
 };
 
 struct remote *remote_get(const char *name);
+struct remote *pushremote_get(const char *name);
 int remote_is_configured(const char *name);
 
 typedef int each_remote_fn(struct remote *remote, void *priv);
index a6a5cd57bef4aaf204f1bad293c18b5af6f57f53..98e3e294d0dc295290b7b891a834186c0791e43a 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -284,8 +284,10 @@ static int rerere_mem_getline(struct strbuf *sb, struct rerere_io *io_)
        strbuf_release(sb);
        if (!io->input.len)
                return -1;
-       ep = strchrnul(io->input.buf, '\n');
-       if (*ep == '\n')
+       ep = memchr(io->input.buf, '\n', io->input.len);
+       if (!ep)
+               ep = io->input.buf + io->input.len;
+       else if (*ep == '\n')
                ep++;
        len = ep - io->input.buf;
        strbuf_add(sb, io->input.buf, len);
@@ -295,7 +297,7 @@ static int rerere_mem_getline(struct strbuf *sb, struct rerere_io *io_)
 
 static int handle_cache(const char *path, unsigned char *sha1, const char *output)
 {
-       mmfile_t mmfile[3];
+       mmfile_t mmfile[3] = {{NULL}};
        mmbuffer_t result = {NULL, 0};
        struct cache_entry *ce;
        int pos, len, i, hunk_no;
@@ -314,17 +316,16 @@ static int handle_cache(const char *path, unsigned char *sha1, const char *outpu
        for (i = 0; i < 3; i++) {
                enum object_type type;
                unsigned long size;
+               int j;
 
-               mmfile[i].size = 0;
-               mmfile[i].ptr = NULL;
                if (active_nr <= pos)
                        break;
                ce = active_cache[pos++];
-               if (ce_namelen(ce) != len || memcmp(ce->name, path, len)
-                   || ce_stage(ce) != i + 1)
-                       break;
-               mmfile[i].ptr = read_sha1_file(ce->sha1, &type, &size);
-               mmfile[i].size = size;
+               if (ce_namelen(ce) != len || memcmp(ce->name, path, len))
+                       continue;
+               j = ce_stage(ce) - 1;
+               mmfile[j].ptr = read_sha1_file(ce->sha1, &type, &size);
+               mmfile[j].size = size;
        }
        for (i = 0; i < 3; i++) {
                if (!mmfile[i].ptr && !mmfile[i].size)
index 72b46125b719861641a55ee8fd534e0d1f47a94f..639eb9c59f355e46bdd53cf13fd94e8a6a9537da 100644 (file)
@@ -118,7 +118,7 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)
        struct cache_entry *ce;
        struct string_list_item *item;
        struct resolve_undo_info *ru;
-       int i, err = 0;
+       int i, err = 0, matched;
 
        if (!istate->resolve_undo)
                return pos;
@@ -137,6 +137,7 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)
        ru = item->util;
        if (!ru)
                return pos;
+       matched = ce->ce_flags & CE_MATCHED;
        remove_index_entry_at(istate, pos);
        for (i = 0; i < 3; i++) {
                struct cache_entry *nce;
@@ -144,6 +145,8 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)
                        continue;
                nce = make_cache_entry(ru->mode[i], ru->sha1[i],
                                       ce->name, i + 1, 0);
+               if (matched)
+                       nce->ce_flags |= CE_MATCHED;
                if (add_index_entry(istate, nce, ADD_CACHE_OK_TO_ADD)) {
                        err = 1;
                        error("cannot unmerge '%s'", ce->name);
@@ -156,6 +159,20 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)
        return unmerge_index_entry_at(istate, pos);
 }
 
+void unmerge_marked_index(struct index_state *istate)
+{
+       int i;
+
+       if (!istate->resolve_undo)
+               return;
+
+       for (i = 0; i < istate->cache_nr; i++) {
+               struct cache_entry *ce = istate->cache[i];
+               if (ce->ce_flags & CE_MATCHED)
+                       i = unmerge_index_entry_at(istate, i);
+       }
+}
+
 void unmerge_index(struct index_state *istate, const char **pathspec)
 {
        int i;
index 845876911db978c6262dacd9aa122ce9d55bf234..7a30206aad1fdee74f7e7b6e5967f9f8d9048dbf 100644 (file)
@@ -12,5 +12,6 @@ extern struct string_list *resolve_undo_read(const char *, unsigned long);
 extern void resolve_undo_clear_index(struct index_state *);
 extern int unmerge_index_entry_at(struct index_state *, int);
 extern void unmerge_index(struct index_state *, const char **);
+extern void unmerge_marked_index(struct index_state *);
 
 #endif
index 71e62d831229773a9af2c4a81d72be5b33d3c921..56d666d69a8a961d33651c0658f7009967e0b7ab 100644 (file)
@@ -1276,7 +1276,8 @@ static void read_revisions_from_stdin(struct rev_info *revs,
                        }
                        die("options not supported in --stdin mode");
                }
-               if (handle_revision_arg(sb.buf, revs, 0, REVARG_CANNOT_BE_FILENAME))
+               if (handle_revision_arg(xstrdup(sb.buf), revs, 0,
+                                       REVARG_CANNOT_BE_FILENAME))
                        die("bad revision '%s'", sb.buf);
        }
        if (seen_dashdash)
@@ -1970,22 +1971,6 @@ static struct merge_simplify_state *locate_simplify_state(struct rev_info *revs,
        return st;
 }
 
-static void remove_treesame_parents(struct commit *commit)
-{
-       struct commit_list **pp, *p;
-
-       pp = &commit->parents;
-       while ((p = *pp) != NULL) {
-               struct commit *parent = p->item;
-               if (parent->object.flags & TREESAME) {
-                       *pp = p->next;
-                       free(p);
-                       continue;
-               }
-               pp = &p->next;
-       }
-}
-
 static struct commit_list **simplify_one(struct rev_info *revs, struct commit *commit, struct commit_list **tail)
 {
        struct commit_list *p;
@@ -2039,17 +2024,10 @@ static struct commit_list **simplify_one(struct rev_info *revs, struct commit *c
                        break;
        }
 
-       if (revs->first_parent_only) {
+       if (revs->first_parent_only)
                cnt = 1;
-       } else {
-               /*
-                * A merge with a tree-same parent is useless
-                */
-               if (commit->parents && commit->parents->next)
-                       remove_treesame_parents(commit);
-
+       else
                cnt = remove_duplicate_parents(commit);
-       }
 
        /*
         * It is possible that we are a merge and one side branch
index 765c2ce0567ad0d75270283397d63eac3674c01a..1b32a12a29b64fcc7d8b2401b00fb8a70ff81bad 100644 (file)
@@ -588,6 +588,7 @@ int run_command_v_opt_cd_env(const char **argv, int opt, const char *dir, const
 static pthread_t main_thread;
 static int main_thread_set;
 static pthread_key_t async_key;
+static pthread_key_t async_die_counter;
 
 static void *run_thread(void *data)
 {
@@ -614,6 +615,14 @@ static NORETURN void die_async(const char *err, va_list params)
 
        exit(128);
 }
+
+static int async_die_is_recursing(void)
+{
+       void *ret = pthread_getspecific(async_die_counter);
+       pthread_setspecific(async_die_counter, (void *)1);
+       return ret != NULL;
+}
+
 #endif
 
 int start_async(struct async *async)
@@ -695,7 +704,9 @@ int start_async(struct async *async)
                main_thread_set = 1;
                main_thread = pthread_self();
                pthread_key_create(&async_key, NULL);
+               pthread_key_create(&async_die_counter, NULL);
                set_die_routine(die_async);
+               set_die_is_recursing_routine(async_die_is_recursing);
        }
 
        if (proc_in >= 0)
index baa031052e4e3f77bb6d4a257a5669ca5a5d617e..cf8fbeb8d5ac2b6ca3b498f2115c02eeea22910a 100644 (file)
@@ -216,7 +216,7 @@ static void print_advice(int show_hint, struct replay_opts *opts)
        if (msg) {
                fprintf(stderr, "%s\n", msg);
                /*
-                * A conflict has occured but the porcelain
+                * A conflict has occurred but the porcelain
                 * (typically rebase --interactive) wants to take care
                 * of the commit itself so remove CHERRY_PICK_HEAD
                 */
@@ -1047,6 +1047,7 @@ int sequencer_pick_revisions(struct replay_opts *opts)
 {
        struct commit_list *todo_list = NULL;
        unsigned char sha1[20];
+       int i;
 
        if (opts->subcommand == REPLAY_NONE)
                assert(opts->revs);
@@ -1067,6 +1068,23 @@ int sequencer_pick_revisions(struct replay_opts *opts)
        if (opts->subcommand == REPLAY_CONTINUE)
                return sequencer_continue(opts);
 
+       for (i = 0; i < opts->revs->pending.nr; i++) {
+               unsigned char sha1[20];
+               const char *name = opts->revs->pending.objects[i].name;
+
+               /* This happens when using --stdin. */
+               if (!strlen(name))
+                       continue;
+
+               if (!get_sha1(name, sha1)) {
+                       enum object_type type = sha1_object_info(sha1, NULL);
+
+                       if (type > 0 && type != OBJ_COMMIT)
+                               die(_("%s: can't cherry-pick a %s"), name, typename(type));
+               } else
+                       die(_("%s: bad revision"), name);
+       }
+
        /*
         * If we were called as "git cherry-pick <commit>", just
         * cherry-pick/revert it, set CHERRY_PICK_HEAD /
index 16967d3b9a86dc481a5161f0a98220e05790ca01..64228a26d0be873040ebde37e95e62d20f5ba957 100644 (file)
@@ -124,8 +124,13 @@ int safe_create_leading_directories(char *path)
                        }
                }
                else if (mkdir(path, 0777)) {
-                       *pos = '/';
-                       return -1;
+                       if (errno == EEXIST &&
+                           !stat(path, &st) && S_ISDIR(st.st_mode)) {
+                               ; /* somebody created it since we checked */
+                       } else {
+                               *pos = '/';
+                               return -1;
+                       }
                }
                else if (adjust_shared_perm(path)) {
                        *pos = '/';
@@ -1266,6 +1271,10 @@ int check_sha1_signature(const unsigned char *sha1, void *map,
                char buf[1024 * 16];
                ssize_t readlen = read_istream(st, buf, sizeof(buf));
 
+               if (readlen < 0) {
+                       close_istream(st);
+                       return -1;
+               }
                if (!readlen)
                        break;
                git_SHA1_Update(&c, buf, readlen);
@@ -1639,50 +1648,6 @@ static off_t get_delta_base(struct packed_git *p,
        return base_offset;
 }
 
-/* forward declaration for a mutually recursive function */
-static int packed_object_info(struct packed_git *p, off_t offset,
-                             unsigned long *sizep, int *rtype);
-
-static int packed_delta_info(struct packed_git *p,
-                            struct pack_window **w_curs,
-                            off_t curpos,
-                            enum object_type type,
-                            off_t obj_offset,
-                            unsigned long *sizep)
-{
-       off_t base_offset;
-
-       base_offset = get_delta_base(p, w_curs, &curpos, type, obj_offset);
-       if (!base_offset)
-               return OBJ_BAD;
-       type = packed_object_info(p, base_offset, NULL, NULL);
-       if (type <= OBJ_NONE) {
-               struct revindex_entry *revidx;
-               const unsigned char *base_sha1;
-               revidx = find_pack_revindex(p, base_offset);
-               if (!revidx)
-                       return OBJ_BAD;
-               base_sha1 = nth_packed_object_sha1(p, revidx->nr);
-               mark_bad_packed_object(p, base_sha1);
-               type = sha1_object_info(base_sha1, NULL);
-               if (type <= OBJ_NONE)
-                       return OBJ_BAD;
-       }
-
-       /* We choose to only get the type of the base object and
-        * ignore potentially corrupt pack file that expects the delta
-        * based on a base with a wrong size.  This saves tons of
-        * inflate() calls.
-        */
-       if (sizep) {
-               *sizep = get_size_from_delta(p, w_curs, curpos);
-               if (*sizep == 0)
-                       type = OBJ_BAD;
-       }
-
-       return type;
-}
-
 int unpack_object_header(struct packed_git *p,
                         struct pack_window **w_curs,
                         off_t *curpos,
@@ -1709,6 +1674,25 @@ int unpack_object_header(struct packed_git *p,
        return type;
 }
 
+static int retry_bad_packed_offset(struct packed_git *p, off_t obj_offset)
+{
+       int type;
+       struct revindex_entry *revidx;
+       const unsigned char *sha1;
+       revidx = find_pack_revindex(p, obj_offset);
+       if (!revidx)
+               return OBJ_BAD;
+       sha1 = nth_packed_object_sha1(p, revidx->nr);
+       mark_bad_packed_object(p, sha1);
+       type = sha1_object_info(sha1, NULL);
+       if (type <= OBJ_NONE)
+               return OBJ_BAD;
+       return type;
+}
+
+
+#define POI_STACK_PREALLOC 64
+
 static int packed_object_info(struct packed_git *p, off_t obj_offset,
                              unsigned long *sizep, int *rtype)
 {
@@ -1716,31 +1700,89 @@ static int packed_object_info(struct packed_git *p, off_t obj_offset,
        unsigned long size;
        off_t curpos = obj_offset;
        enum object_type type;
+       off_t small_poi_stack[POI_STACK_PREALLOC];
+       off_t *poi_stack = small_poi_stack;
+       int poi_stack_nr = 0, poi_stack_alloc = POI_STACK_PREALLOC;
 
        type = unpack_object_header(p, &w_curs, &curpos, &size);
+
        if (rtype)
                *rtype = type; /* representation type */
 
+       if (sizep) {
+               if (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
+                       off_t tmp_pos = curpos;
+                       off_t base_offset = get_delta_base(p, &w_curs, &tmp_pos,
+                                                          type, obj_offset);
+                       if (!base_offset) {
+                               type = OBJ_BAD;
+                               goto out;
+                       }
+                       *sizep = get_size_from_delta(p, &w_curs, tmp_pos);
+                       if (*sizep == 0) {
+                               type = OBJ_BAD;
+                               goto out;
+                       }
+               } else {
+                       *sizep = size;
+               }
+       }
+
+       while (type == OBJ_OFS_DELTA || type == OBJ_REF_DELTA) {
+               off_t base_offset;
+               /* Push the object we're going to leave behind */
+               if (poi_stack_nr >= poi_stack_alloc && poi_stack == small_poi_stack) {
+                       poi_stack_alloc = alloc_nr(poi_stack_nr);
+                       poi_stack = xmalloc(sizeof(off_t)*poi_stack_alloc);
+                       memcpy(poi_stack, small_poi_stack, sizeof(off_t)*poi_stack_nr);
+               } else {
+                       ALLOC_GROW(poi_stack, poi_stack_nr+1, poi_stack_alloc);
+               }
+               poi_stack[poi_stack_nr++] = obj_offset;
+               /* If parsing the base offset fails, just unwind */
+               base_offset = get_delta_base(p, &w_curs, &curpos, type, obj_offset);
+               if (!base_offset)
+                       goto unwind;
+               curpos = obj_offset = base_offset;
+               type = unpack_object_header(p, &w_curs, &curpos, &size);
+               if (type <= OBJ_NONE) {
+                       /* If getting the base itself fails, we first
+                        * retry the base, otherwise unwind */
+                       type = retry_bad_packed_offset(p, base_offset);
+                       if (type > OBJ_NONE)
+                               goto out;
+                       goto unwind;
+               }
+       }
+
        switch (type) {
-       case OBJ_OFS_DELTA:
-       case OBJ_REF_DELTA:
-               type = packed_delta_info(p, &w_curs, curpos,
-                                        type, obj_offset, sizep);
-               break;
+       case OBJ_BAD:
        case OBJ_COMMIT:
        case OBJ_TREE:
        case OBJ_BLOB:
        case OBJ_TAG:
-               if (sizep)
-                       *sizep = size;
                break;
        default:
                error("unknown object type %i at offset %"PRIuMAX" in %s",
                      type, (uintmax_t)obj_offset, p->pack_name);
                type = OBJ_BAD;
        }
+
+out:
+       if (poi_stack != small_poi_stack)
+               free(poi_stack);
        unuse_pack(&w_curs);
        return type;
+
+unwind:
+       while (poi_stack_nr) {
+               obj_offset = poi_stack[--poi_stack_nr];
+               type = retry_bad_packed_offset(p, obj_offset);
+               if (type > OBJ_NONE)
+                       goto out;
+       }
+       type = OBJ_BAD;
+       goto out;
 }
 
 static void *unpack_compressed_entry(struct packed_git *p,
@@ -1802,32 +1844,51 @@ static unsigned long pack_entry_hash(struct packed_git *p, off_t base_offset)
        return hash % MAX_DELTA_CACHE;
 }
 
-static int in_delta_base_cache(struct packed_git *p, off_t base_offset)
+static struct delta_base_cache_entry *
+get_delta_base_cache_entry(struct packed_git *p, off_t base_offset)
 {
        unsigned long hash = pack_entry_hash(p, base_offset);
-       struct delta_base_cache_entry *ent = delta_base_cache + hash;
+       return delta_base_cache + hash;
+}
+
+static int eq_delta_base_cache_entry(struct delta_base_cache_entry *ent,
+                                    struct packed_git *p, off_t base_offset)
+{
        return (ent->data && ent->p == p && ent->base_offset == base_offset);
 }
 
+static int in_delta_base_cache(struct packed_git *p, off_t base_offset)
+{
+       struct delta_base_cache_entry *ent;
+       ent = get_delta_base_cache_entry(p, base_offset);
+       return eq_delta_base_cache_entry(ent, p, base_offset);
+}
+
+static void clear_delta_base_cache_entry(struct delta_base_cache_entry *ent)
+{
+       ent->data = NULL;
+       ent->lru.next->prev = ent->lru.prev;
+       ent->lru.prev->next = ent->lru.next;
+       delta_base_cached -= ent->size;
+}
+
 static void *cache_or_unpack_entry(struct packed_git *p, off_t base_offset,
        unsigned long *base_size, enum object_type *type, int keep_cache)
 {
+       struct delta_base_cache_entry *ent;
        void *ret;
-       unsigned long hash = pack_entry_hash(p, base_offset);
-       struct delta_base_cache_entry *ent = delta_base_cache + hash;
 
-       ret = ent->data;
-       if (!ret || ent->p != p || ent->base_offset != base_offset)
+       ent = get_delta_base_cache_entry(p, base_offset);
+
+       if (!eq_delta_base_cache_entry(ent, p, base_offset))
                return unpack_entry(p, base_offset, type, base_size);
 
-       if (!keep_cache) {
-               ent->data = NULL;
-               ent->lru.next->prev = ent->lru.prev;
-               ent->lru.prev->next = ent->lru.next;
-               delta_base_cached -= ent->size;
-       } else {
+       ret = ent->data;
+
+       if (!keep_cache)
+               clear_delta_base_cache_entry(ent);
+       else
                ret = xmemdupz(ent->data, ent->size);
-       }
        *type = ent->type;
        *base_size = ent->size;
        return ret;
@@ -1891,68 +1952,6 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
 static void *read_object(const unsigned char *sha1, enum object_type *type,
                         unsigned long *size);
 
-static void *unpack_delta_entry(struct packed_git *p,
-                               struct pack_window **w_curs,
-                               off_t curpos,
-                               unsigned long delta_size,
-                               off_t obj_offset,
-                               enum object_type *type,
-                               unsigned long *sizep)
-{
-       void *delta_data, *result, *base;
-       unsigned long base_size;
-       off_t base_offset;
-
-       base_offset = get_delta_base(p, w_curs, &curpos, *type, obj_offset);
-       if (!base_offset) {
-               error("failed to validate delta base reference "
-                     "at offset %"PRIuMAX" from %s",
-                     (uintmax_t)curpos, p->pack_name);
-               return NULL;
-       }
-       unuse_pack(w_curs);
-       base = cache_or_unpack_entry(p, base_offset, &base_size, type, 0);
-       if (!base) {
-               /*
-                * We're probably in deep shit, but let's try to fetch
-                * the required base anyway from another pack or loose.
-                * This is costly but should happen only in the presence
-                * of a corrupted pack, and is better than failing outright.
-                */
-               struct revindex_entry *revidx;
-               const unsigned char *base_sha1;
-               revidx = find_pack_revindex(p, base_offset);
-               if (!revidx)
-                       return NULL;
-               base_sha1 = nth_packed_object_sha1(p, revidx->nr);
-               error("failed to read delta base object %s"
-                     " at offset %"PRIuMAX" from %s",
-                     sha1_to_hex(base_sha1), (uintmax_t)base_offset,
-                     p->pack_name);
-               mark_bad_packed_object(p, base_sha1);
-               base = read_object(base_sha1, type, &base_size);
-               if (!base)
-                       return NULL;
-       }
-
-       delta_data = unpack_compressed_entry(p, w_curs, curpos, delta_size);
-       if (!delta_data) {
-               error("failed to unpack compressed delta "
-                     "at offset %"PRIuMAX" from %s",
-                     (uintmax_t)curpos, p->pack_name);
-               free(base);
-               return NULL;
-       }
-       result = patch_delta(base, base_size,
-                            delta_data, delta_size,
-                            sizep);
-       if (!result)
-               die("failed to apply delta");
-       free(delta_data);
-       add_delta_base_cache(p, base_offset, base, base_size, *type);
-       return result;
-}
-
 static void write_pack_access_log(struct packed_git *p, off_t obj_offset)
 {
        static FILE *log_file;
@@ -1973,48 +1972,179 @@ static void write_pack_access_log(struct packed_git *p, off_t obj_offset)
 
 int do_check_packed_object_crc;
 
+#define UNPACK_ENTRY_STACK_PREALLOC 64
+struct unpack_entry_stack_ent {
+       off_t obj_offset;
+       off_t curpos;
+       unsigned long size;
+};
+
 void *unpack_entry(struct packed_git *p, off_t obj_offset,
-                  enum object_type *type, unsigned long *sizep)
+                  enum object_type *final_type, unsigned long *final_size)
 {
        struct pack_window *w_curs = NULL;
        off_t curpos = obj_offset;
-       void *data;
+       void *data = NULL;
+       unsigned long size;
+       enum object_type type;
+       struct unpack_entry_stack_ent small_delta_stack[UNPACK_ENTRY_STACK_PREALLOC];
+       struct unpack_entry_stack_ent *delta_stack = small_delta_stack;
+       int delta_stack_nr = 0, delta_stack_alloc = UNPACK_ENTRY_STACK_PREALLOC;
+       int base_from_cache = 0;
 
        if (log_pack_access)
                write_pack_access_log(p, obj_offset);
 
-       if (do_check_packed_object_crc && p->index_version > 1) {
-               struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
-               unsigned long len = revidx[1].offset - obj_offset;
-               if (check_pack_crc(p, &w_curs, obj_offset, len, revidx->nr)) {
-                       const unsigned char *sha1 =
-                               nth_packed_object_sha1(p, revidx->nr);
-                       error("bad packed object CRC for %s",
-                             sha1_to_hex(sha1));
-                       mark_bad_packed_object(p, sha1);
-                       unuse_pack(&w_curs);
-                       return NULL;
+       /* PHASE 1: drill down to the innermost base object */
+       for (;;) {
+               off_t base_offset;
+               int i;
+               struct delta_base_cache_entry *ent;
+
+               if (do_check_packed_object_crc && p->index_version > 1) {
+                       struct revindex_entry *revidx = find_pack_revindex(p, obj_offset);
+                       unsigned long len = revidx[1].offset - obj_offset;
+                       if (check_pack_crc(p, &w_curs, obj_offset, len, revidx->nr)) {
+                               const unsigned char *sha1 =
+                                       nth_packed_object_sha1(p, revidx->nr);
+                               error("bad packed object CRC for %s",
+                                     sha1_to_hex(sha1));
+                               mark_bad_packed_object(p, sha1);
+                               unuse_pack(&w_curs);
+                               return NULL;
+                       }
+               }
+
+               ent = get_delta_base_cache_entry(p, curpos);
+               if (eq_delta_base_cache_entry(ent, p, curpos)) {
+                       type = ent->type;
+                       data = ent->data;
+                       size = ent->size;
+                       clear_delta_base_cache_entry(ent);
+                       base_from_cache = 1;
+                       break;
                }
+
+               type = unpack_object_header(p, &w_curs, &curpos, &size);
+               if (type != OBJ_OFS_DELTA && type != OBJ_REF_DELTA)
+                       break;
+
+               base_offset = get_delta_base(p, &w_curs, &curpos, type, obj_offset);
+               if (!base_offset) {
+                       error("failed to validate delta base reference "
+                             "at offset %"PRIuMAX" from %s",
+                             (uintmax_t)curpos, p->pack_name);
+                       /* bail to phase 2, in hopes of recovery */
+                       data = NULL;
+                       break;
+               }
+
+               /* push object, proceed to base */
+               if (delta_stack_nr >= delta_stack_alloc
+                   && delta_stack == small_delta_stack) {
+                       delta_stack_alloc = alloc_nr(delta_stack_nr);
+                       delta_stack = xmalloc(sizeof(*delta_stack)*delta_stack_alloc);
+                       memcpy(delta_stack, small_delta_stack,
+                              sizeof(*delta_stack)*delta_stack_nr);
+               } else {
+                       ALLOC_GROW(delta_stack, delta_stack_nr+1, delta_stack_alloc);
+               }
+               i = delta_stack_nr++;
+               delta_stack[i].obj_offset = obj_offset;
+               delta_stack[i].curpos = curpos;
+               delta_stack[i].size = size;
+
+               curpos = obj_offset = base_offset;
        }
 
-       *type = unpack_object_header(p, &w_curs, &curpos, sizep);
-       switch (*type) {
+       /* PHASE 2: handle the base */
+       switch (type) {
        case OBJ_OFS_DELTA:
        case OBJ_REF_DELTA:
-               data = unpack_delta_entry(p, &w_curs, curpos, *sizep,
-                                         obj_offset, type, sizep);
+               if (data)
+                       die("BUG in unpack_entry: left loop at a valid delta");
                break;
        case OBJ_COMMIT:
        case OBJ_TREE:
        case OBJ_BLOB:
        case OBJ_TAG:
-               data = unpack_compressed_entry(p, &w_curs, curpos, *sizep);
+               if (!base_from_cache)
+                       data = unpack_compressed_entry(p, &w_curs, curpos, size);
                break;
        default:
                data = NULL;
                error("unknown object type %i at offset %"PRIuMAX" in %s",
-                     *type, (uintmax_t)obj_offset, p->pack_name);
+                     type, (uintmax_t)obj_offset, p->pack_name);
+       }
+
+       /* PHASE 3: apply deltas in order */
+
+       /* invariants:
+        *   'data' holds the base data, or NULL if there was corruption
+        */
+       while (delta_stack_nr) {
+               void *delta_data;
+               void *base = data;
+               unsigned long delta_size, base_size = size;
+               int i;
+
+               data = NULL;
+
+               if (base)
+                       add_delta_base_cache(p, obj_offset, base, base_size, type);
+
+               if (!base) {
+                       /*
+                        * We're probably in deep shit, but let's try to fetch
+                        * the required base anyway from another pack or loose.
+                        * This is costly but should happen only in the presence
+                        * of a corrupted pack, and is better than failing outright.
+                        */
+                       struct revindex_entry *revidx;
+                       const unsigned char *base_sha1;
+                       revidx = find_pack_revindex(p, obj_offset);
+                       if (revidx) {
+                               base_sha1 = nth_packed_object_sha1(p, revidx->nr);
+                               error("failed to read delta base object %s"
+                                     " at offset %"PRIuMAX" from %s",
+                                     sha1_to_hex(base_sha1), (uintmax_t)obj_offset,
+                                     p->pack_name);
+                               mark_bad_packed_object(p, base_sha1);
+                               base = read_object(base_sha1, &type, &base_size);
+                       }
+               }
+
+               i = --delta_stack_nr;
+               obj_offset = delta_stack[i].obj_offset;
+               curpos = delta_stack[i].curpos;
+               delta_size = delta_stack[i].size;
+
+               if (!base)
+                       continue;
+
+               delta_data = unpack_compressed_entry(p, &w_curs, curpos, delta_size);
+
+               if (!delta_data) {
+                       error("failed to unpack compressed delta "
+                             "at offset %"PRIuMAX" from %s",
+                             (uintmax_t)curpos, p->pack_name);
+                       free(base);
+                       data = NULL;
+                       continue;
+               }
+
+               data = patch_delta(base, base_size,
+                                  delta_data, delta_size,
+                                  &size);
+               if (!data)
+                       die("failed to apply delta");
+
+               free (delta_data);
        }
+
+       *final_type = type;
+       *final_size = size;
+
        unuse_pack(&w_curs);
        return data;
 }
index 2fbda48e02f167d08aa19210951712b85f40b602..3820f28ae757cce54a95014629ade4f7feb56efc 100644 (file)
@@ -594,7 +594,7 @@ struct object *peel_to_type(const char *name, int namelen,
        while (1) {
                if (!o || (!o->parsed && !parse_object(o->sha1)))
                        return NULL;
-               if (o->type == expected_type)
+               if (expected_type == OBJ_ANY || o->type == expected_type)
                        return o;
                if (o->type == OBJ_TAG)
                        o = ((struct tag*) o)->tagged;
@@ -645,6 +645,8 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
                expected_type = OBJ_TREE;
        else if (!strncmp(blob_type, sp, 4) && sp[4] == '}')
                expected_type = OBJ_BLOB;
+       else if (!prefixcmp(sp, "object}"))
+               expected_type = OBJ_ANY;
        else if (sp[0] == '}')
                expected_type = OBJ_NONE;
        else if (sp[0] == '/')
@@ -654,6 +656,8 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
 
        if (expected_type == OBJ_COMMIT)
                lookup_flags = GET_SHA1_COMMITTISH;
+       else if (expected_type == OBJ_TREE)
+               lookup_flags = GET_SHA1_TREEISH;
 
        if (get_sha1_1(name, sp - name - 2, outer, lookup_flags))
                return -1;
index 48e9abb5c2069bfc02a32747004bf51799dda0f1..1170d01c4322b494cd900853279766edd030de32 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -528,6 +528,25 @@ void strbuf_addstr_urlencode(struct strbuf *sb, const char *s,
        strbuf_add_urlencode(sb, s, strlen(s), reserved);
 }
 
+void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes)
+{
+       if (bytes > 1 << 30) {
+               strbuf_addf(buf, "%u.%2.2u GiB",
+                           (int)(bytes >> 30),
+                           (int)(bytes & ((1 << 30) - 1)) / 10737419);
+       } else if (bytes > 1 << 20) {
+               int x = bytes + 5243;  /* for rounding */
+               strbuf_addf(buf, "%u.%2.2u MiB",
+                           x >> 20, ((x & ((1 << 20) - 1)) * 100) >> 20);
+       } else if (bytes > 1 << 10) {
+               int x = bytes + 5;  /* for rounding */
+               strbuf_addf(buf, "%u.%2.2u KiB",
+                           x >> 10, ((x & ((1 << 10) - 1)) * 100) >> 10);
+       } else {
+               strbuf_addf(buf, "%u bytes", (int)bytes);
+       }
+}
+
 int printf_ln(const char *fmt, ...)
 {
        int ret;
index 958822c2dd4ebf2275f294258c265884cfbf3ee8..73e80cea69b5e2965cf4ce8c36444f45aae8e19c 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
@@ -170,6 +170,7 @@ extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
 
 extern void strbuf_addstr_urlencode(struct strbuf *, const char *,
                                    int reserved);
+extern void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes);
 
 __attribute__((format (printf,1,2)))
 extern int printf_ln(const char *fmt, ...);
index 4d978e54e4fb9d84e81977539ffa083534ef2968..cabcd9d1577d89c5e944a4c12e3a8e6af901078c 100644 (file)
@@ -237,7 +237,7 @@ static read_method_decl(filtered)
                if (!fs->input_finished) {
                        fs->i_end = read_istream(fs->upstream, fs->ibuf, FILTER_BUFFER);
                        if (fs->i_end < 0)
-                               break;
+                               return -1;
                        if (fs->i_end)
                                continue;
                }
@@ -309,7 +309,7 @@ static read_method_decl(loose)
                        st->z_state = z_done;
                        break;
                }
-               if (status != Z_OK && status != Z_BUF_ERROR) {
+               if (status != Z_OK && (status != Z_BUF_ERROR || total_read < sz)) {
                        git_inflate_end(&st->z);
                        st->z_state = z_error;
                        return -1;
@@ -514,6 +514,8 @@ int stream_blob_to_fd(int fd, unsigned const char *sha1, struct stream_filter *f
                ssize_t wrote, holeto;
                ssize_t readlen = read_istream(st, buf, sizeof(buf));
 
+               if (readlen < 0)
+                       goto close_and_exit;
                if (!readlen)
                        break;
                if (can_seek && sizeof(buf) == readlen) {
index 9ba149654322840323cf2d8f4980fa09e56f4068..e728025f60dbf7f3df87b7104af6410832ddb653 100644 (file)
@@ -216,6 +216,7 @@ static int prepare_submodule_summary(struct rev_info *rev, const char *path,
 }
 
 static void print_submodule_summary(struct rev_info *rev, FILE *f,
+               const char *line_prefix,
                const char *del, const char *add, const char *reset)
 {
        static const char format[] = "  %m %s";
@@ -226,6 +227,7 @@ static void print_submodule_summary(struct rev_info *rev, FILE *f,
                struct pretty_print_context ctx = {0};
                ctx.date_mode = rev->date_mode;
                strbuf_setlen(&sb, 0);
+               strbuf_addstr(&sb, line_prefix);
                if (commit->object.flags & SYMMETRIC_LEFT) {
                        if (del)
                                strbuf_addstr(&sb, del);
@@ -256,12 +258,13 @@ int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg)
 }
 
 void show_submodule_summary(FILE *f, const char *path,
+               const char *line_prefix,
                unsigned char one[20], unsigned char two[20],
                unsigned dirty_submodule, const char *meta,
                const char *del, const char *add, const char *reset)
 {
        struct rev_info rev;
-       struct commit *left = left, *right = right;
+       struct commit *left = NULL, *right = NULL;
        const char *message = NULL;
        struct strbuf sb = STRBUF_INIT;
        int fast_forward = 0, fast_backward = 0;
@@ -275,23 +278,23 @@ void show_submodule_summary(FILE *f, const char *path,
        else if (!(left = lookup_commit_reference(one)) ||
                 !(right = lookup_commit_reference(two)))
                message = "(commits not present)";
-
-       if (!message &&
-           prepare_submodule_summary(&rev, path, left, right,
-                                       &fast_forward, &fast_backward))
+       else if (prepare_submodule_summary(&rev, path, left, right,
+                                          &fast_forward, &fast_backward))
                message = "(revision walker failed)";
 
        if (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)
-               fprintf(f, "Submodule %s contains untracked content\n", path);
+               fprintf(f, "%sSubmodule %s contains untracked content\n",
+                       line_prefix, path);
        if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
-               fprintf(f, "Submodule %s contains modified content\n", path);
+               fprintf(f, "%sSubmodule %s contains modified content\n",
+                       line_prefix, path);
 
        if (!hashcmp(one, two)) {
                strbuf_release(&sb);
                return;
        }
 
-       strbuf_addf(&sb, "%sSubmodule %s %s..", meta, path,
+       strbuf_addf(&sb, "%s%sSubmodule %s %s..", line_prefix, meta, path,
                        find_unique_abbrev(one, DEFAULT_ABBREV));
        if (!fast_backward && !fast_forward)
                strbuf_addch(&sb, '.');
@@ -302,11 +305,12 @@ void show_submodule_summary(FILE *f, const char *path,
                strbuf_addf(&sb, "%s:%s\n", fast_backward ? " (rewind)" : "", reset);
        fwrite(sb.buf, sb.len, 1, f);
 
-       if (!message) {
-               print_submodule_summary(&rev, f, del, add, reset);
+       if (!message) /* only NULL if we succeeded in setting up the walk */
+               print_submodule_summary(&rev, f, line_prefix, del, add, reset);
+       if (left)
                clear_commit_marks(left, ~0);
+       if (right)
                clear_commit_marks(right, ~0);
-       }
 
        strbuf_release(&sb);
 }
index 3dc1b3fe891eaf5c758ee0a668f9f385ea99d5ba..c7ffc7c399d23781d823954d74bab4620debb628 100644 (file)
@@ -19,6 +19,7 @@ int parse_submodule_config_option(const char *var, const char *value);
 void handle_ignore_submodules_arg(struct diff_options *diffopt, const char *);
 int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);
 void show_submodule_summary(FILE *f, const char *path,
+               const char *line_prefix,
                unsigned char one[20], unsigned char two[20],
                unsigned dirty_submodule, const char *meta,
                const char *del, const char *add, const char *reset);
index e4128e5769722473f7fd1024fdf8a5100bd8ccf6..e669bb31b9aa2513a6f71de9fd066a21a0a3bde7 100644 (file)
--- a/t/README
+++ b/t/README
@@ -86,23 +86,35 @@ appropriately before running "make".
 
 --immediate::
        This causes the test to immediately exit upon the first
-       failed test.
+       failed test. Cleanup commands requested with
+       test_when_finished are not executed if the test failed,
+       in order to keep the state for inspection by the tester
+       to diagnose the bug.
 
 --long-tests::
        This causes additional long-running tests to be run (where
        available), for more exhaustive testing.
 
---valgrind::
-       Execute all Git binaries with valgrind and exit with status
-       126 on errors (just like regular tests, this will only stop
-       the test script when running under -i).  Valgrind errors
-       go to stderr, so you might want to pass the -v option, too.
+--valgrind=<tool>::
+       Execute all Git binaries under valgrind tool <tool> and exit
+       with status 126 on errors (just like regular tests, this will
+       only stop the test script when running under -i).
 
        Since it makes no sense to run the tests with --valgrind and
        not see any output, this option implies --verbose.  For
        convenience, it also implies --tee.
 
-       Note that valgrind is run with the option --leak-check=no,
+       <tool> defaults to 'memcheck', just like valgrind itself.
+       Other particularly useful choices include 'helgrind' and
+       'drd', but you may use any tool recognized by your valgrind
+       installation.
+
+       As a special case, <tool> can be 'memcheck-fast', which uses
+       memcheck but disables --track-origins.  Use this if you are
+       running tests in bulk, to see if there are _any_ memory
+       issues.
+
+       Note that memcheck is run with the option --leak-check=no,
        as the git process is short-lived and some errors are not
        interesting. In order to run a single command under the same
        conditions manually, you should set GIT_VALGRIND to point to
@@ -610,6 +622,11 @@ use these, and "test_set_prereq" for how to define your own.
    The process retains the same pid across exec(2). See fb9a2bea for
    details.
 
+ - PIPE
+
+   The filesystem we're on supports creation of FIFOs (named pipes)
+   via mkfifo(1).
+
  - SYMLINKS
 
    The filesystem we're on supports symbolic links. E.g. a FAT
index 83855fa4e1c6c37afe550c17afa1e7971042ded5..1a3c2d487c2fda9169751a3068fa51e853a1e519 100644 (file)
Binary files a/t/lib-gpg/pubring.gpg and b/t/lib-gpg/pubring.gpg differ
index 8fed1339ed0a744e5663f4a5e6b6ac9bae3d8524..95d249f15fce980f0e8c1a8a18b085b3885708aa 100644 (file)
Binary files a/t/lib-gpg/random_seed and b/t/lib-gpg/random_seed differ
index d831cd9eb3eee613d3c0e1a71093ae01ea7347e3..82dca8f80bf170fde5705862c3eeb9d994725042 100644 (file)
Binary files a/t/lib-gpg/secring.gpg and b/t/lib-gpg/secring.gpg differ
index abace962b8bf84be688a6f27e4ebd0ee7052f210..4879ae9a84650a93a4d15bd6560c5d1b89eb4c2f 100644 (file)
Binary files a/t/lib-gpg/trustdb.gpg and b/t/lib-gpg/trustdb.gpg differ
index 938b4cf803b3b4ea07be20338425f784b80cdf0c..ad8553719a4f476bd24aa0294d4c8103d55f9d90 100644 (file)
@@ -61,6 +61,11 @@ Alias /auth/dumb/ www/auth/dumb/
        SetEnv GIT_COMMITTER_NAME "Custom User"
        SetEnv GIT_COMMITTER_EMAIL custom@example.com
 </LocationMatch>
+<LocationMatch /smart_namespace/>
+       SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
+       SetEnv GIT_HTTP_EXPORT_ALL
+       SetEnv GIT_NAMESPACE ns
+</LocationMatch>
 ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1
 ScriptAlias /broken_smart/ broken-smart-http.sh/
 <Directory ${GIT_EXEC_PATH}>
index d8b7f2ffbcc0427b1ae9d48feb4387f580e81d61..9820f70c84d93b9461ae6663e6ab5b3cd735e3d5 100755 (executable)
@@ -116,9 +116,9 @@ tree_pretty_content="100644 blob $hello_sha1        hello"
 
 run_tests 'tree' $tree_sha1 $tree_size "" "$tree_pretty_content"
 
-commit_message="Intial commit"
+commit_message="Initial commit"
 commit_sha1=$(echo_without_newline "$commit_message" | git commit-tree $tree_sha1)
-commit_size=176
+commit_size=177
 commit_content="tree $tree_sha1
 author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 0000000000 +0000
 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 0000000000 +0000
diff --git a/t/t1060-object-corruption.sh b/t/t1060-object-corruption.sh
new file mode 100755 (executable)
index 0000000..3f87051
--- /dev/null
@@ -0,0 +1,104 @@
+#!/bin/sh
+
+test_description='see how we handle various forms of corruption'
+. ./test-lib.sh
+
+# convert "1234abcd" to ".git/objects/12/34abcd"
+obj_to_file() {
+       echo "$(git rev-parse --git-dir)/objects/$(git rev-parse "$1" | sed 's,..,&/,')"
+}
+
+# Convert byte at offset "$2" of object "$1" into '\0'
+corrupt_byte() {
+       obj_file=$(obj_to_file "$1") &&
+       chmod +w "$obj_file" &&
+       printf '\0' | dd of="$obj_file" bs=1 seek="$2" conv=notrunc
+}
+
+test_expect_success 'setup corrupt repo' '
+       git init bit-error &&
+       (
+               cd bit-error &&
+               test_commit content &&
+               corrupt_byte HEAD:content.t 10
+       )
+'
+
+test_expect_success 'setup repo with missing object' '
+       git init missing &&
+       (
+               cd missing &&
+               test_commit content &&
+               rm -f "$(obj_to_file HEAD:content.t)"
+       )
+'
+
+test_expect_success 'setup repo with misnamed object' '
+       git init misnamed &&
+       (
+               cd misnamed &&
+               test_commit content &&
+               good=$(obj_to_file HEAD:content.t) &&
+               blob=$(echo corrupt | git hash-object -w --stdin) &&
+               bad=$(obj_to_file $blob) &&
+               rm -f "$good" &&
+               mv "$bad" "$good"
+       )
+'
+
+test_expect_success 'streaming a corrupt blob fails' '
+       (
+               cd bit-error &&
+               test_must_fail git cat-file blob HEAD:content.t
+       )
+'
+
+test_expect_success 'read-tree -u detects bit-errors in blobs' '
+       (
+               cd bit-error &&
+               rm -f content.t &&
+               test_must_fail git read-tree --reset -u HEAD
+       )
+'
+
+test_expect_success 'read-tree -u detects missing objects' '
+       (
+               cd missing &&
+               rm -f content.t &&
+               test_must_fail git read-tree --reset -u HEAD
+       )
+'
+
+# We use --bare to make sure that the transport detects it, not the checkout
+# phase.
+test_expect_success 'clone --no-local --bare detects corruption' '
+       test_must_fail git clone --no-local --bare bit-error corrupt-transport
+'
+
+test_expect_success 'clone --no-local --bare detects missing object' '
+       test_must_fail git clone --no-local --bare missing missing-transport
+'
+
+test_expect_success 'clone --no-local --bare detects misnamed object' '
+       test_must_fail git clone --no-local --bare misnamed misnamed-transport
+'
+
+# We do not expect --local to detect corruption at the transport layer,
+# so we are really checking the checkout() code path.
+test_expect_success 'clone --local detects corruption' '
+       test_must_fail git clone --local bit-error corrupt-checkout
+'
+
+test_expect_success 'error detected during checkout leaves repo intact' '
+       test_path_is_dir corrupt-checkout/.git
+'
+
+test_expect_success 'clone --local detects missing objects' '
+       test_must_fail git clone --local missing missing-checkout
+'
+
+test_expect_failure 'clone --local detects misnamed objects' '
+       test_must_fail git clone --local misnamed misnamed-checkout
+'
+
+test_done
index 3c96fda548709835e10f283df8cab667c280af81..c4a7d84f46fd218af1824ac1f78a1e9f4cb15cec 100755 (executable)
@@ -1087,4 +1087,39 @@ test_expect_success 'barf on incomplete string' '
        grep " line 3 " error
 '
 
+# good section hygiene
+test_expect_failure 'unsetting the last key in a section removes header' '
+       cat >.git/config <<-\EOF &&
+       # some generic comment on the configuration file itself
+       # a comment specific to this "section" section.
+       [section]
+       # some intervening lines
+       # that should also be dropped
+
+       key = value
+       # please be careful when you update the above variable
+       EOF
+
+       cat >expect <<-\EOF &&
+       # some generic comment on the configuration file itself
+       EOF
+
+       git config --unset section.key &&
+       test_cmp expect .git/config
+'
+
+test_expect_failure 'adding a key into an empty section reuses header' '
+       cat >.git/config <<-\EOF &&
+       [section]
+       EOF
+
+       q_to_tab >expect <<-\EOF &&
+       [section]
+       Qkey = value
+       EOF
+
+       git config section.key value
+       test_cmp expect .git/config
+'
+
 test_done
index 56090d2ebadcdfb127b9db005ae8d092b0255a75..8e3545d8680c5f5179977082849388b1b31c17d8 100755 (executable)
@@ -39,4 +39,26 @@ test_expect_success 'checking out paths out of a tree does not clobber unrelated
        test_cmp expect.next2 dir/next2
 '
 
+test_expect_success 'do not touch unmerged entries matching $path but not in $tree' '
+       git checkout next &&
+       git reset --hard &&
+
+       cat dir/common >expect.common &&
+       EMPTY_SHA1=$(git hash-object -w --stdin </dev/null) &&
+       git rm dir/next0 &&
+       cat >expect.next0 <<-EOF &&
+       100644 $EMPTY_SHA1 1    dir/next0
+       100644 $EMPTY_SHA1 2    dir/next0
+       EOF
+       git update-index --index-info <expect.next0 &&
+
+       git checkout master dir &&
+
+       test_cmp expect.common dir/common &&
+       test_path_is_file dir/master &&
+       git diff --exit-code master dir/master &&
+       git ls-files -s dir/next0 >actual.next0 &&
+       test_cmp expect.next0 actual.next0
+'
+
 test_done
index f2620650ce1d25252210c07db20e54f99bd515c6..309199bca272b63499ca69edbb953bcc8c770ecc 100755 (executable)
@@ -44,14 +44,21 @@ prime_resolve_undo () {
 
 test_expect_success setup '
        mkdir fi &&
+       printf "a\0a" >binary &&
+       git add binary &&
        test_commit initial fi/le first &&
        git branch side &&
        git branch another &&
+       printf "a\0b" >binary &&
+       git add binary &&
        test_commit second fi/le second &&
        git checkout side &&
        test_commit third fi/le third &&
+       git branch add-add &&
        git checkout another &&
        test_commit fourth fi/le fourth &&
+       git checkout add-add &&
+       test_commit fifth add-differently &&
        git checkout master
 '
 
@@ -167,4 +174,22 @@ test_expect_success 'rerere and rerere forget (subdirectory)' '
        test_cmp expect actual
 '
 
+test_expect_success 'rerere forget (binary)' '
+       git checkout -f side &&
+       printf "a\0c" >binary &&
+       git commit -a -m binary &&
+       test_must_fail git merge second &&
+       git rerere forget binary
+'
+
+test_expect_success 'rerere forget (add-add conflict)' '
+       git checkout -f master &&
+       echo master >add-differently &&
+       git add add-differently &&
+       git commit -m "add differently" &&
+       test_must_fail git merge fifth &&
+       git rerere forget add-differently 2>actual &&
+       test_i18ngrep "no remembered" actual
+'
+
 test_done
index b08c9f22951bf447cc769c043a165d087fa5e38d..d969f0ecd85a6907f219d141cad2c00c4b5a89f8 100755 (executable)
@@ -75,7 +75,7 @@ test_expect_success 'git branch l should work after branch l/m has been deleted'
 
 test_expect_success 'git branch -m dumps usage' '
        test_expect_code 128 git branch -m 2>err &&
-       test_i18ngrep "too many branches for a rename operation" err
+       test_i18ngrep "branch name required" err
 '
 
 test_expect_success 'git branch -m m m/m should work' '
@@ -409,6 +409,18 @@ test_expect_success '--set-upstream-to fails on detached HEAD' '
        git checkout -
 '
 
+test_expect_success '--set-upstream-to fails on a missing dst branch' '
+       test_must_fail git branch --set-upstream-to master does-not-exist
+'
+
+test_expect_success '--set-upstream-to fails on a missing src branch' '
+       test_must_fail git branch --set-upstream-to does-not-exist master
+'
+
+test_expect_success '--set-upstream-to fails on a non-ref' '
+       test_must_fail git branch --set-upstream-to HEAD^{}
+'
+
 test_expect_success 'use --set-upstream-to modify HEAD' '
        test_config branch.master.remote foo &&
        test_config branch.master.merge foo &&
index 4e7136b83775946a07678119c7c9897bb0f2b709..19c99d7ef1bc02e67a7b995206b9f66c04c1b31c 100755 (executable)
@@ -55,6 +55,12 @@ one
 two"
 '
 
+test_expect_success 'cherry-pick three one two: fails' '
+       git checkout -f master &&
+       git reset --hard first &&
+       test_must_fail git cherry-pick three one two:
+'
+
 test_expect_success 'output to keep user entertained during multi-pick' '
        cat <<-\EOF >expected &&
        [master OBJID] second
index 37bf5f13b07a632cb8e96e865a75b51f1b7844aa..0c44e9f5d04af8d038a1e78ed5fdf892ce4dd5b5 100755 (executable)
@@ -622,4 +622,69 @@ test_expect_success 'rm of a populated nested submodule with a nested .git direc
        rm -rf submod
 '
 
+test_expect_success 'rm of d/f when d has become a non-directory' '
+       rm -rf d &&
+       mkdir d &&
+       >d/f &&
+       git add d &&
+       rm -rf d &&
+       >d &&
+       git rm d/f &&
+       test_must_fail git rev-parse --verify :d/f &&
+       test_path_is_file d
+'
+
+test_expect_success SYMLINKS 'rm of d/f when d has become a dangling symlink' '
+       rm -rf d &&
+       mkdir d &&
+       >d/f &&
+       git add d &&
+       rm -rf d &&
+       ln -s nonexistent d &&
+       git rm d/f &&
+       test_must_fail git rev-parse --verify :d/f &&
+       test -h d &&
+       test_path_is_missing d
+'
+
+test_expect_success 'rm of file when it has become a directory' '
+       rm -rf d &&
+       >d &&
+       git add d &&
+       rm -f d &&
+       mkdir d &&
+       >d/f &&
+       test_must_fail git rm d &&
+       git rev-parse --verify :d &&
+       test_path_is_file d/f
+'
+
+test_expect_success SYMLINKS 'rm across a symlinked leading path (no index)' '
+       rm -rf d e &&
+       mkdir e &&
+       echo content >e/f &&
+       ln -s e d &&
+       git add -A e d &&
+       git commit -m "symlink d to e, e/f exists" &&
+       test_must_fail git rm d/f &&
+       git rev-parse --verify :d &&
+       git rev-parse --verify :e/f &&
+       test -h d &&
+       test_path_is_file e/f
+'
+
+test_expect_failure SYMLINKS 'rm across a symlinked leading path (w/ index)' '
+       rm -rf d e &&
+       mkdir d &&
+       echo content >d/f &&
+       git add -A e d &&
+       git commit -m "d/f exists" &&
+       mv d e &&
+       ln -s e d &&
+       test_must_fail git rm d/f &&
+       git rev-parse --verify :d/f &&
+       test -h d &&
+       test_path_is_file e/f
+'
+
 test_done
index 098a6ae4a086ccfeb8c658a80773eb07c9d66441..9fab25cc96b079349a3ca3caffbd8d2bc322265c 100755 (executable)
@@ -319,7 +319,7 @@ test_expect_success PERL 'split hunk "add -p (edit)"' '
        # times to get out.
        #
        # 2. Correct version applies the (not)edited version, and asks
-       #    about the next hunk, against wich we say q and program
+       #    about the next hunk, against which we say q and program
        #    exits.
        for a in s e     q n q q
        do
index b993dae64574cd2828fc636d3afc15b2c0c2e5a0..58d418098d793b284bb4a7222cf9709c45b26c90 100755 (executable)
@@ -742,21 +742,21 @@ test_expect_success 'format-patch --signature --cover-letter' '
        test 2 = $(grep "my sig" output | wc -l)
 '
 
-test_expect_success 'format.signature="" supresses signatures' '
+test_expect_success 'format.signature="" suppresses signatures' '
        git config format.signature "" &&
        git format-patch --stdout -1 >output &&
        check_patch output &&
        ! grep "^-- \$" output
 '
 
-test_expect_success 'format-patch --no-signature supresses signatures' '
+test_expect_success 'format-patch --no-signature suppresses signatures' '
        git config --unset-all format.signature &&
        git format-patch --stdout --no-signature -1 >output &&
        check_patch output &&
        ! grep "^-- \$" output
 '
 
-test_expect_success 'format-patch --signature="" supresses signatures' '
+test_expect_success 'format-patch --signature="" suppresses signatures' '
        git format-patch --stdout --signature="" -1 >output &&
        check_patch output &&
        ! grep "^-- \$" output
@@ -1284,4 +1284,37 @@ test_expect_success 'cover letter using branch description (6)' '
        grep hello actual >/dev/null
 '
 
+test_expect_success 'cover letter with nothing' '
+       git format-patch --stdout --cover-letter >actual &&
+       test_line_count = 0 actual
+'
+
+test_expect_success 'cover letter auto' '
+       mkdir -p tmp &&
+       test_when_finished "rm -rf tmp;
+               git config --unset format.coverletter" &&
+
+       git config format.coverletter auto &&
+       git format-patch -o tmp -1 >list &&
+       test_line_count = 1 list &&
+       git format-patch -o tmp -2 >list &&
+       test_line_count = 3 list
+'
+
+test_expect_success 'cover letter auto user override' '
+       mkdir -p tmp &&
+       test_when_finished "rm -rf tmp;
+               git config --unset format.coverletter" &&
+
+       git config format.coverletter auto &&
+       git format-patch -o tmp --cover-letter -1 >list &&
+       test_line_count = 2 list &&
+       git format-patch -o tmp --cover-letter -2 >list &&
+       test_line_count = 3 list &&
+       git format-patch -o tmp --no-cover-letter -1 >list &&
+       test_line_count = 1 list &&
+       git format-patch -o tmp --no-cover-letter -2 >list &&
+       test_line_count = 2 list
+'
+
 test_done
index b7e16a7840afc32d36c6a118ed2fa1dbb579476a..1261dbbdf5869b671e36cd7128bfde61fd67b8de 100755 (executable)
@@ -224,4 +224,133 @@ test_expect_success 'check combined output (ignore all spaces)' '
        compare_diff_patch expected actual
 '
 
+test_expect_success 'combine diff coalesce simple' '
+       >test &&
+       git add test &&
+       git commit -m initial &&
+       test_seq 4 >test &&
+       git commit -a -m empty1 &&
+       git branch side1 &&
+       git checkout HEAD^ &&
+       test_seq 5 >test &&
+       git commit -a -m empty2 &&
+       test_must_fail git merge side1 &&
+       >test &&
+       git commit -a -m merge &&
+       git show >actual.tmp &&
+       sed -e "1,/^@@@/d" < actual.tmp >actual &&
+       tr -d Q <<-\EOF >expected &&
+       --1
+       --2
+       --3
+       --4
+       - 5
+       EOF
+       compare_diff_patch expected actual
+'
+
+test_expect_success 'combine diff coalesce tricky' '
+       >test &&
+       git add test &&
+       git commit -m initial --allow-empty &&
+       cat <<-\EOF >test &&
+       3
+       1
+       2
+       3
+       4
+       EOF
+       git commit -a -m empty1 &&
+       git branch -f side1 &&
+       git checkout HEAD^ &&
+       cat <<-\EOF >test &&
+       1
+       3
+       5
+       4
+       EOF
+       git commit -a -m empty2 &&
+       git branch -f side2 &&
+       test_must_fail git merge side1 &&
+       >test &&
+       git commit -a -m merge &&
+       git show >actual.tmp &&
+       sed -e "1,/^@@@/d" < actual.tmp >actual &&
+       tr -d Q <<-\EOF >expected &&
+        -3
+       --1
+        -2
+       --3
+       - 5
+       --4
+       EOF
+       compare_diff_patch expected actual &&
+       git checkout -f side1 &&
+       test_must_fail git merge side2 &&
+       >test &&
+       git commit -a -m merge &&
+       git show >actual.tmp &&
+       sed -e "1,/^@@@/d" < actual.tmp >actual &&
+       tr -d Q <<-\EOF >expected &&
+       - 3
+       --1
+       - 2
+       --3
+        -5
+       --4
+       EOF
+       compare_diff_patch expected actual
+'
+
+test_expect_failure 'combine diff coalesce three parents' '
+       >test &&
+       git add test &&
+       git commit -m initial --allow-empty &&
+       cat <<-\EOF >test &&
+       3
+       1
+       2
+       3
+       4
+       EOF
+       git commit -a -m empty1 &&
+       git checkout -B side1 &&
+       git checkout HEAD^ &&
+       cat <<-\EOF >test &&
+       1
+       3
+       7
+       5
+       4
+       EOF
+       git commit -a -m empty2 &&
+       git branch -f side2 &&
+       git checkout HEAD^ &&
+       cat <<-\EOF >test &&
+       3
+       1
+       6
+       5
+       4
+       EOF
+       git commit -a -m empty3 &&
+       >test &&
+       git add test &&
+       TREE=$(git write-tree) &&
+       COMMIT=$(git commit-tree -p HEAD -p side1 -p side2 -m merge $TREE) &&
+       git show $COMMIT >actual.tmp &&
+       sed -e "1,/^@@@/d" < actual.tmp >actual &&
+       tr -d Q <<-\EOF >expected &&
+       -- 3
+       ---1
+       -  6
+        - 2
+        --3
+         -7
+       - -5
+       ---4
+       EOF
+       compare_diff_patch expected actual
+'
+
 test_done
index 6f6ee88b28bc5417035b45d87aaf4a9c974ab6c5..5d0c5983381b4072d915de0f8d75053b19172d66 100755 (executable)
@@ -47,7 +47,7 @@ test_fix () {
        # find touched lines
        $DIFF file target | sed -n -e "s/^> //p" >fixed
 
-       # the changed lines are all expeced to change
+       # the changed lines are all expected to change
        fixed_cnt=$(wc -l <fixed)
        case "$1" in
        '') expect_cnt=$fixed_cnt ;;
@@ -486,4 +486,30 @@ test_expect_success 'same, but with CR-LF line endings && cr-at-eol unset' '
        test_cmp one expect
 '
 
+test_expect_success 'whitespace=fix to expand' '
+       qz_to_tab_space >preimage <<-\EOF &&
+       QQa
+       QQb
+       QQc
+       ZZZZZZZZZZZZZZZZd
+       QQe
+       QQf
+       QQg
+       EOF
+       qz_to_tab_space >patch <<-\EOF &&
+       diff --git a/preimage b/preimage
+       --- a/preimage
+       +++ b/preimage
+       @@ -1,7 +1,6 @@
+        QQa
+        QQb
+        QQc
+       -QQd
+        QQe
+        QQf
+        QQg
+       EOF
+       git -c core.whitespace=tab-in-indent apply --whitespace=fix patch
+'
+
 test_done
index cdafd7e7c1e6c73a97c36a60f77810badff603f2..12f6b027acbccae3fe524906970ff139ddccfed0 100755 (executable)
@@ -17,7 +17,7 @@ test_expect_success 'setup: messages' '
        vero eos et accusam et justo duo dolores et ea rebum.
 
        EOF
-       q_to_tab <<-\EOF >>msg &&
+       qz_to_tab_space <<-\EOF >>msg &&
        QDuis autem vel eum iriure dolor in hendrerit in vulputate velit
        Qesse molestie consequat, vel illum dolore eu feugiat nulla facilisis
        Qat vero eros et accumsan et iusto odio dignissim qui blandit
index eed727341dca4cd16a2558644506573885baccd9..38fb80f643534a2bd724e13ef271f90167ac11a3 100755 (executable)
@@ -80,6 +80,20 @@ test_expect_success 'log -G -i (match)' '
        test_cmp expect actual
 '
 
+test_expect_success 'log -G --textconv (missing textconv tool)' '
+       echo "* diff=test" >.gitattributes &&
+       test_must_fail git -c diff.test.textconv=missing log -Gfoo &&
+       rm .gitattributes
+'
+
+test_expect_success 'log -G --no-textconv (missing textconv tool)' '
+       echo "* diff=test" >.gitattributes &&
+       git -c diff.test.textconv=missing log -Gfoo --no-textconv >actual &&
+       >expect &&
+       test_cmp expect actual &&
+       rm .gitattributes
+'
+
 test_expect_success 'log -S (nomatch)' '
        git log -Spicked --format=%H >actual &&
        >expect &&
@@ -116,4 +130,18 @@ test_expect_success 'log -S -i (nomatch)' '
        test_cmp expect actual
 '
 
+test_expect_success 'log -S --textconv (missing textconv tool)' '
+       echo "* diff=test" >.gitattributes &&
+       test_must_fail git -c diff.test.textconv=missing log -Sfoo &&
+       rm .gitattributes
+'
+
+test_expect_success 'log -S --no-textconv (missing textconv tool)' '
+       echo "* diff=test" >.gitattributes &&
+       git -c diff.test.textconv=missing log -Sfoo --no-textconv >actual &&
+       >expect &&
+       test_cmp expect actual &&
+       rm .gitattributes
+'
+
 test_done
index d0b2a457b8bf30fc7ab472ff6b2576ff319432f7..bd43b3d8ef8b3e71f6985cfa96a940dccb4a0a54 100755 (executable)
@@ -26,8 +26,6 @@ EXPECTED
 
 test_expect_success 'file add !A, B' '
        cat >expected <<\EXPECTED &&
-added in local
-  our    100644 43d5a8ed6ef6c00ff775008633f95787d088285d ONE
 EXPECTED
 
        git reset --hard initial &&
@@ -38,9 +36,6 @@ EXPECTED
 
 test_expect_success 'file add A, B (same)' '
        cat >expected <<\EXPECTED &&
-added in both
-  our    100644 43d5a8ed6ef6c00ff775008633f95787d088285d ONE
-  their  100644 43d5a8ed6ef6c00ff775008633f95787d088285d ONE
 EXPECTED
 
        git reset --hard initial &&
@@ -181,9 +176,6 @@ AAA" &&
 
 test_expect_success 'file remove A, !B' '
        cat >expected <<\EXPECTED &&
-removed in local
-  base   100644 43d5a8ed6ef6c00ff775008633f95787d088285d ONE
-  their  100644 43d5a8ed6ef6c00ff775008633f95787d088285d ONE
 EXPECTED
 
        git reset --hard initial &&
@@ -283,8 +275,6 @@ test_expect_success 'turn tree to file' '
        test_commit "make-file" "dir" "CCC" &&
        git merge-tree add-tree add-another-tree make-file >actual &&
        cat >expect <<-\EOF &&
-       added in local
-         our    100644 ba629238ca89489f2b350e196ca445e09d8bb834 dir/another
        removed in remote
          base   100644 43d5a8ed6ef6c00ff775008633f95787d088285d dir/path
          our    100644 43d5a8ed6ef6c00ff775008633f95787d088285d dir/path
index 0c847fb45482b67266dc6eb9ec62b8cc7b5a9d76..6667d159ab0950f10a3271f1cb81a63953214f17 100755 (executable)
@@ -27,6 +27,25 @@ test_expect_success 'setup' '
        echo ignored-only-if-dir/ export-ignore >>.git/info/attributes &&
        git add ignored-only-if-dir &&
 
+       mkdir -p ignored-without-slash &&
+       echo "ignored without slash" >ignored-without-slash/foo &&
+       git add ignored-without-slash/foo &&
+       echo "ignored-without-slash export-ignore" >>.git/info/attributes &&
+
+       mkdir -p wildcard-without-slash &&
+       echo "ignored without slash" >wildcard-without-slash/foo &&
+       git add wildcard-without-slash/foo &&
+       echo "wild*-without-slash export-ignore" >>.git/info/attributes &&
+
+       mkdir -p deep/and/slashless &&
+       echo "ignored without slash" >deep/and/slashless/foo &&
+       git add deep/and/slashless/foo &&
+       echo "deep/and/slashless export-ignore" >>.git/info/attributes &&
+
+       mkdir -p deep/with/wildcard &&
+       echo "ignored without slash" >deep/with/wildcard/foo &&
+       git add deep/with/wildcard/foo &&
+       echo "deep/*t*/wildcard export-ignore" >>.git/info/attributes &&
 
        mkdir -p one-level-lower/two-levels-lower/ignored-only-if-dir &&
        echo ignored by ignored dir >one-level-lower/two-levels-lower/ignored-only-if-dir/ignored-by-ignored-dir &&
@@ -49,6 +68,14 @@ test_expect_exists   archive/not-ignored-dir/ignored-only-if-dir
 test_expect_exists     archive/not-ignored-dir/
 test_expect_missing    archive/ignored-only-if-dir/
 test_expect_missing    archive/ignored-ony-if-dir/ignored-by-ignored-dir
+test_expect_missing    archive/ignored-without-slash/ &&
+test_expect_missing    archive/ignored-without-slash/foo &&
+test_expect_missing    archive/wildcard-without-slash/
+test_expect_missing    archive/wildcard-without-slash/foo &&
+test_expect_missing    archive/deep/and/slashless/ &&
+test_expect_missing    archive/deep/and/slashless/foo &&
+test_expect_missing    archive/deep/with/wildcard/ &&
+test_expect_missing    archive/deep/with/wildcard/foo &&
 test_expect_exists     archive/one-level-lower/
 test_expect_missing    archive/one-level-lower/two-levels-lower/ignored-only-if-dir/
 test_expect_missing    archive/one-level-lower/two-levels-lower/ignored-ony-if-dir/ignored-by-ignored-dir
index cdb7d7a7f9b59678e4079c61ae5104db51dc05a2..bfdb56a0694db0c6ed07aaa568c648909ac62660 100755 (executable)
@@ -28,7 +28,7 @@ check_dir() {
 }
 
 test_expect_success 'tar archive of empty tree is empty' '
-       git archive --format=tar HEAD >empty.tar &&
+       git archive --format=tar HEAD: >empty.tar &&
        make_dir extract &&
        "$TAR" xf empty.tar -C extract &&
        check_dir extract
index c24003565d635722f07333bb662c8e102d577c9e..2b8c0bac7db47ef7b37024ecea95ed0e37d5364f 100755 (executable)
@@ -36,7 +36,7 @@ test_expect_success 'prepare pushable branches' '
 '
 
 test_expect_success 'mixed-success push returns error' '
-       test_must_fail git push
+       test_must_fail git push origin :
 '
 
 test_expect_success 'check tracking branches updated correctly after push' '
index ccc55ebf4bf10d4782bf2ff32910ed6eeec040f6..6579a86724cec01b8c731ead2d4083dfe44293dd 100755 (executable)
@@ -345,7 +345,7 @@ test_expect_success 'fetch mirrors do not act as mirrors during push' '
        ) &&
        (cd mirror-fetch/child &&
         git branch -m renamed renamed2 &&
-        git push parent
+        git push parent :
        ) &&
        (cd mirror-fetch/parent &&
         git rev-parse --verify renamed &&
index 383a2eb1eaa46053fc3a91fb44921aea2f04637a..4691d51b8cde48dbb97ac5dfc1e3b75fe90f8da3 100755 (executable)
@@ -1,16 +1,28 @@
 #!/bin/sh
 
-test_description='fetching and pushing, with or without wildcard'
+test_description='Basic fetch/push functionality.
+
+This test checks the following functionality:
+
+* command-line syntax
+* refspecs
+* fast-forward detection, and overriding it
+* configuration
+* hooks
+* --porcelain output format
+* hiderefs
+'
 
 . ./test-lib.sh
 
 D=`pwd`
 
 mk_empty () {
-       rm -fr testrepo &&
-       mkdir testrepo &&
+       repo_name="$1"
+       rm -fr "$repo_name" &&
+       mkdir "$repo_name" &&
        (
-               cd testrepo &&
+               cd "$repo_name" &&
                git init &&
                git config receive.denyCurrentBranch warn &&
                mv .git/hooks .git/hooks-disabled
@@ -18,14 +30,17 @@ mk_empty () {
 }
 
 mk_test () {
-       mk_empty &&
+       repo_name="$1"
+       shift
+
+       mk_empty "$repo_name" &&
        (
                for ref in "$@"
                do
-                       git push testrepo $the_first_commit:refs/$ref ||
+                       git push "$repo_name" $the_first_commit:refs/$ref ||
                        exit
                done &&
-               cd testrepo &&
+               cd "$repo_name" &&
                for ref in "$@"
                do
                        echo "$the_first_commit" >expect &&
@@ -38,9 +53,10 @@ mk_test () {
 }
 
 mk_test_with_hooks() {
+       repo_name=$1
        mk_test "$@" &&
        (
-               cd testrepo &&
+               cd "$repo_name" &&
                mkdir .git/hooks &&
                cd .git/hooks &&
 
@@ -72,13 +88,16 @@ mk_test_with_hooks() {
 }
 
 mk_child() {
-       rm -rf "$1" &&
-       git clone testrepo "$1"
+       rm -rf "$2" &&
+       git clone "$1" "$2"
 }
 
 check_push_result () {
+       repo_name="$1"
+       shift
+
        (
-               cd testrepo &&
+               cd "$repo_name" &&
                echo "$1" >expect &&
                shift &&
                for ref in "$@"
@@ -108,7 +127,7 @@ test_expect_success setup '
 '
 
 test_expect_success 'fetch without wildcard' '
-       mk_empty &&
+       mk_empty testrepo &&
        (
                cd testrepo &&
                git fetch .. refs/heads/master:refs/remotes/origin/master &&
@@ -120,7 +139,7 @@ test_expect_success 'fetch without wildcard' '
 '
 
 test_expect_success 'fetch with wildcard' '
-       mk_empty &&
+       mk_empty testrepo &&
        (
                cd testrepo &&
                git config remote.up.url .. &&
@@ -134,7 +153,7 @@ test_expect_success 'fetch with wildcard' '
 '
 
 test_expect_success 'fetch with insteadOf' '
-       mk_empty &&
+       mk_empty testrepo &&
        (
                TRASH=$(pwd)/ &&
                cd testrepo &&
@@ -150,7 +169,7 @@ test_expect_success 'fetch with insteadOf' '
 '
 
 test_expect_success 'fetch with pushInsteadOf (should not rewrite)' '
-       mk_empty &&
+       mk_empty testrepo &&
        (
                TRASH=$(pwd)/ &&
                cd testrepo &&
@@ -166,7 +185,7 @@ test_expect_success 'fetch with pushInsteadOf (should not rewrite)' '
 '
 
 test_expect_success 'push without wildcard' '
-       mk_empty &&
+       mk_empty testrepo &&
 
        git push testrepo refs/heads/master:refs/remotes/origin/master &&
        (
@@ -178,7 +197,7 @@ test_expect_success 'push without wildcard' '
 '
 
 test_expect_success 'push with wildcard' '
-       mk_empty &&
+       mk_empty testrepo &&
 
        git push testrepo "refs/heads/*:refs/remotes/origin/*" &&
        (
@@ -190,7 +209,7 @@ test_expect_success 'push with wildcard' '
 '
 
 test_expect_success 'push with insteadOf' '
-       mk_empty &&
+       mk_empty testrepo &&
        TRASH="$(pwd)/" &&
        test_config "url.$TRASH.insteadOf" trash/ &&
        git push trash/testrepo refs/heads/master:refs/remotes/origin/master &&
@@ -203,7 +222,7 @@ test_expect_success 'push with insteadOf' '
 '
 
 test_expect_success 'push with pushInsteadOf' '
-       mk_empty &&
+       mk_empty testrepo &&
        TRASH="$(pwd)/" &&
        test_config "url.$TRASH.pushInsteadOf" trash/ &&
        git push trash/testrepo refs/heads/master:refs/remotes/origin/master &&
@@ -216,11 +235,11 @@ test_expect_success 'push with pushInsteadOf' '
 '
 
 test_expect_success 'push with pushInsteadOf and explicit pushurl (pushInsteadOf should not rewrite)' '
-       mk_empty &&
-       TRASH="$(pwd)/" &&
-       test_config "url.trash2/.pushInsteadOf" trash/ &&
+       mk_empty testrepo &&
+       test_config "url.trash2/.pushInsteadOf" testrepo/ &&
+       test_config "url.trash3/.pusnInsteadOf" trash/wrong &&
        test_config remote.r.url trash/wrong &&
-       test_config remote.r.pushurl "$TRASH/testrepo" &&
+       test_config remote.r.pushurl "testrepo/" &&
        git push r refs/heads/master:refs/remotes/origin/master &&
        (
                cd testrepo &&
@@ -232,237 +251,237 @@ test_expect_success 'push with pushInsteadOf and explicit pushurl (pushInsteadOf
 
 test_expect_success 'push with matching heads' '
 
-       mk_test heads/master &&
-       git push testrepo &&
-       check_push_result $the_commit heads/master
+       mk_test testrepo heads/master &&
+       git push testrepo &&
+       check_push_result testrepo $the_commit heads/master
 
 '
 
 test_expect_success 'push with matching heads on the command line' '
 
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        git push testrepo : &&
-       check_push_result $the_commit heads/master
+       check_push_result testrepo $the_commit heads/master
 
 '
 
 test_expect_success 'failed (non-fast-forward) push with matching heads' '
 
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        git push testrepo : &&
        git commit --amend -massaged &&
        test_must_fail git push testrepo &&
-       check_push_result $the_commit heads/master &&
+       check_push_result testrepo $the_commit heads/master &&
        git reset --hard $the_commit
 
 '
 
 test_expect_success 'push --force with matching heads' '
 
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        git push testrepo : &&
        git commit --amend -massaged &&
-       git push --force testrepo &&
-       ! check_push_result $the_commit heads/master &&
+       git push --force testrepo &&
+       ! check_push_result testrepo $the_commit heads/master &&
        git reset --hard $the_commit
 
 '
 
 test_expect_success 'push with matching heads and forced update' '
 
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        git push testrepo : &&
        git commit --amend -massaged &&
        git push testrepo +: &&
-       ! check_push_result $the_commit heads/master &&
+       ! check_push_result testrepo $the_commit heads/master &&
        git reset --hard $the_commit
 
 '
 
 test_expect_success 'push with no ambiguity (1)' '
 
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        git push testrepo master:master &&
-       check_push_result $the_commit heads/master
+       check_push_result testrepo $the_commit heads/master
 
 '
 
 test_expect_success 'push with no ambiguity (2)' '
 
-       mk_test remotes/origin/master &&
+       mk_test testrepo remotes/origin/master &&
        git push testrepo master:origin/master &&
-       check_push_result $the_commit remotes/origin/master
+       check_push_result testrepo $the_commit remotes/origin/master
 
 '
 
 test_expect_success 'push with colon-less refspec, no ambiguity' '
 
-       mk_test heads/master heads/t/master &&
+       mk_test testrepo heads/master heads/t/master &&
        git branch -f t/master master &&
        git push testrepo master &&
-       check_push_result $the_commit heads/master &&
-       check_push_result $the_first_commit heads/t/master
+       check_push_result testrepo $the_commit heads/master &&
+       check_push_result testrepo $the_first_commit heads/t/master
 
 '
 
 test_expect_success 'push with weak ambiguity (1)' '
 
-       mk_test heads/master remotes/origin/master &&
+       mk_test testrepo heads/master remotes/origin/master &&
        git push testrepo master:master &&
-       check_push_result $the_commit heads/master &&
-       check_push_result $the_first_commit remotes/origin/master
+       check_push_result testrepo $the_commit heads/master &&
+       check_push_result testrepo $the_first_commit remotes/origin/master
 
 '
 
 test_expect_success 'push with weak ambiguity (2)' '
 
-       mk_test heads/master remotes/origin/master remotes/another/master &&
+       mk_test testrepo heads/master remotes/origin/master remotes/another/master &&
        git push testrepo master:master &&
-       check_push_result $the_commit heads/master &&
-       check_push_result $the_first_commit remotes/origin/master remotes/another/master
+       check_push_result testrepo $the_commit heads/master &&
+       check_push_result testrepo $the_first_commit remotes/origin/master remotes/another/master
 
 '
 
 test_expect_success 'push with ambiguity' '
 
-       mk_test heads/frotz tags/frotz &&
+       mk_test testrepo heads/frotz tags/frotz &&
        test_must_fail git push testrepo master:frotz &&
-       check_push_result $the_first_commit heads/frotz tags/frotz
+       check_push_result testrepo $the_first_commit heads/frotz tags/frotz
 
 '
 
 test_expect_success 'push with colon-less refspec (1)' '
 
-       mk_test heads/frotz tags/frotz &&
+       mk_test testrepo heads/frotz tags/frotz &&
        git branch -f frotz master &&
        git push testrepo frotz &&
-       check_push_result $the_commit heads/frotz &&
-       check_push_result $the_first_commit tags/frotz
+       check_push_result testrepo $the_commit heads/frotz &&
+       check_push_result testrepo $the_first_commit tags/frotz
 
 '
 
 test_expect_success 'push with colon-less refspec (2)' '
 
-       mk_test heads/frotz tags/frotz &&
+       mk_test testrepo heads/frotz tags/frotz &&
        if git show-ref --verify -q refs/heads/frotz
        then
                git branch -D frotz
        fi &&
        git tag -f frotz &&
        git push -f testrepo frotz &&
-       check_push_result $the_commit tags/frotz &&
-       check_push_result $the_first_commit heads/frotz
+       check_push_result testrepo $the_commit tags/frotz &&
+       check_push_result testrepo $the_first_commit heads/frotz
 
 '
 
 test_expect_success 'push with colon-less refspec (3)' '
 
-       mk_test &&
+       mk_test testrepo &&
        if git show-ref --verify -q refs/tags/frotz
        then
                git tag -d frotz
        fi &&
        git branch -f frotz master &&
        git push testrepo frotz &&
-       check_push_result $the_commit heads/frotz &&
+       check_push_result testrepo $the_commit heads/frotz &&
        test 1 = $( cd testrepo && git show-ref | wc -l )
 '
 
 test_expect_success 'push with colon-less refspec (4)' '
 
-       mk_test &&
+       mk_test testrepo &&
        if git show-ref --verify -q refs/heads/frotz
        then
                git branch -D frotz
        fi &&
        git tag -f frotz &&
        git push testrepo frotz &&
-       check_push_result $the_commit tags/frotz &&
+       check_push_result testrepo $the_commit tags/frotz &&
        test 1 = $( cd testrepo && git show-ref | wc -l )
 
 '
 
 test_expect_success 'push head with non-existent, incomplete dest' '
 
-       mk_test &&
+       mk_test testrepo &&
        git push testrepo master:branch &&
-       check_push_result $the_commit heads/branch
+       check_push_result testrepo $the_commit heads/branch
 
 '
 
 test_expect_success 'push tag with non-existent, incomplete dest' '
 
-       mk_test &&
+       mk_test testrepo &&
        git tag -f v1.0 &&
        git push testrepo v1.0:tag &&
-       check_push_result $the_commit tags/tag
+       check_push_result testrepo $the_commit tags/tag
 
 '
 
 test_expect_success 'push sha1 with non-existent, incomplete dest' '
 
-       mk_test &&
+       mk_test testrepo &&
        test_must_fail git push testrepo `git rev-parse master`:foo
 
 '
 
 test_expect_success 'push ref expression with non-existent, incomplete dest' '
 
-       mk_test &&
+       mk_test testrepo &&
        test_must_fail git push testrepo master^:branch
 
 '
 
 test_expect_success 'push with HEAD' '
 
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        git checkout master &&
        git push testrepo HEAD &&
-       check_push_result $the_commit heads/master
+       check_push_result testrepo $the_commit heads/master
 
 '
 
 test_expect_success 'push with HEAD nonexisting at remote' '
 
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        git checkout -b local master &&
        git push testrepo HEAD &&
-       check_push_result $the_commit heads/local
+       check_push_result testrepo $the_commit heads/local
 '
 
 test_expect_success 'push with +HEAD' '
 
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        git checkout master &&
        git branch -D local &&
        git checkout -b local &&
        git push testrepo master local &&
-       check_push_result $the_commit heads/master &&
-       check_push_result $the_commit heads/local &&
+       check_push_result testrepo $the_commit heads/master &&
+       check_push_result testrepo $the_commit heads/local &&
 
        # Without force rewinding should fail
        git reset --hard HEAD^ &&
        test_must_fail git push testrepo HEAD &&
-       check_push_result $the_commit heads/local &&
+       check_push_result testrepo $the_commit heads/local &&
 
        # With force rewinding should succeed
        git push testrepo +HEAD &&
-       check_push_result $the_first_commit heads/local
+       check_push_result testrepo $the_first_commit heads/local
 
 '
 
 test_expect_success 'push HEAD with non-existent, incomplete dest' '
 
-       mk_test &&
+       mk_test testrepo &&
        git checkout master &&
        git push testrepo HEAD:branch &&
-       check_push_result $the_commit heads/branch
+       check_push_result testrepo $the_commit heads/branch
 
 '
 
 test_expect_success 'push with config remote.*.push = HEAD' '
 
-       mk_test heads/local &&
+       mk_test testrepo heads/local &&
        git checkout master &&
        git branch -f local $the_commit &&
        (
@@ -474,35 +493,64 @@ test_expect_success 'push with config remote.*.push = HEAD' '
        test_config remote.there.push HEAD &&
        test_config branch.master.remote there &&
        git push &&
-       check_push_result $the_commit heads/master &&
-       check_push_result $the_first_commit heads/local
+       check_push_result testrepo $the_commit heads/master &&
+       check_push_result testrepo $the_first_commit heads/local
+'
+
+test_expect_success 'push with remote.pushdefault' '
+       mk_test up_repo heads/master &&
+       mk_test down_repo heads/master &&
+       test_config remote.up.url up_repo &&
+       test_config remote.down.url down_repo &&
+       test_config branch.master.remote up &&
+       test_config remote.pushdefault down &&
+       test_config push.default matching &&
+       git push &&
+       check_push_result up_repo $the_first_commit heads/master &&
+       check_push_result down_repo $the_commit heads/master
 '
 
 test_expect_success 'push with config remote.*.pushurl' '
 
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        git checkout master &&
        test_config remote.there.url test2repo &&
        test_config remote.there.pushurl testrepo &&
-       git push there &&
-       check_push_result $the_commit heads/master
+       git push there : &&
+       check_push_result testrepo $the_commit heads/master
+'
+
+test_expect_success 'push with config branch.*.pushremote' '
+       mk_test up_repo heads/master &&
+       mk_test side_repo heads/master &&
+       mk_test down_repo heads/master &&
+       test_config remote.up.url up_repo &&
+       test_config remote.pushdefault side_repo &&
+       test_config remote.down.url down_repo &&
+       test_config branch.master.remote up &&
+       test_config branch.master.pushremote down &&
+       test_config push.default matching &&
+       git push &&
+       check_push_result up_repo $the_first_commit heads/master &&
+       check_push_result side_repo $the_first_commit heads/master &&
+       check_push_result down_repo $the_commit heads/master
 '
 
 test_expect_success 'push with dry-run' '
 
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        (
                cd testrepo &&
                old_commit=$(git show-ref -s --verify refs/heads/master)
        ) &&
-       git push --dry-run testrepo &&
-       check_push_result $old_commit heads/master
+       git push --dry-run testrepo &&
+       check_push_result testrepo $old_commit heads/master
 '
 
 test_expect_success 'push updates local refs' '
 
-       mk_test heads/master &&
-       mk_child child &&
+       mk_test testrepo heads/master &&
+       mk_child testrepo child &&
        (
                cd child &&
                git pull .. master &&
@@ -515,9 +563,9 @@ test_expect_success 'push updates local refs' '
 
 test_expect_success 'push updates up-to-date local refs' '
 
-       mk_test heads/master &&
-       mk_child child1 &&
-       mk_child child2 &&
+       mk_test testrepo heads/master &&
+       mk_child testrepo child1 &&
+       mk_child testrepo child2 &&
        (cd child1 && git pull .. master && git push) &&
        (
                cd child2 &&
@@ -531,8 +579,8 @@ test_expect_success 'push updates up-to-date local refs' '
 
 test_expect_success 'push preserves up-to-date packed refs' '
 
-       mk_test heads/master &&
-       mk_child child &&
+       mk_test testrepo heads/master &&
+       mk_child testrepo child &&
        (
                cd child &&
                git push &&
@@ -543,8 +591,8 @@ test_expect_success 'push preserves up-to-date packed refs' '
 
 test_expect_success 'push does not update local refs on failure' '
 
-       mk_test heads/master &&
-       mk_child child &&
+       mk_test testrepo heads/master &&
+       mk_child testrepo child &&
        mkdir testrepo/.git/hooks &&
        echo "#!/no/frobnication/today" >testrepo/.git/hooks/pre-receive &&
        chmod +x testrepo/.git/hooks/pre-receive &&
@@ -560,7 +608,7 @@ test_expect_success 'push does not update local refs on failure' '
 
 test_expect_success 'allow deleting an invalid remote ref' '
 
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        rm -f testrepo/.git/objects/??/* &&
        git push testrepo :refs/heads/master &&
        (cd testrepo && test_must_fail git rev-parse --verify refs/heads/master)
@@ -568,7 +616,7 @@ test_expect_success 'allow deleting an invalid remote ref' '
 '
 
 test_expect_success 'pushing valid refs triggers post-receive and post-update hooks' '
-       mk_test_with_hooks heads/master heads/next &&
+       mk_test_with_hooks testrepo heads/master heads/next &&
        orgmaster=$(cd testrepo && git show-ref -s --verify refs/heads/master) &&
        newmaster=$(git show-ref -s --verify refs/heads/master) &&
        orgnext=$(cd testrepo && git show-ref -s --verify refs/heads/next) &&
@@ -604,7 +652,7 @@ test_expect_success 'pushing valid refs triggers post-receive and post-update ho
 '
 
 test_expect_success 'deleting dangling ref triggers hooks with correct args' '
-       mk_test_with_hooks heads/master &&
+       mk_test_with_hooks testrepo heads/master &&
        rm -f testrepo/.git/objects/??/* &&
        git push testrepo :refs/heads/master &&
        (
@@ -633,7 +681,7 @@ test_expect_success 'deleting dangling ref triggers hooks with correct args' '
 '
 
 test_expect_success 'deletion of a non-existent ref is not fed to post-receive and post-update hooks' '
-       mk_test_with_hooks heads/master &&
+       mk_test_with_hooks testrepo heads/master &&
        orgmaster=$(cd testrepo && git show-ref -s --verify refs/heads/master) &&
        newmaster=$(git show-ref -s --verify refs/heads/master) &&
        git push testrepo master :refs/heads/nonexistent &&
@@ -665,7 +713,7 @@ test_expect_success 'deletion of a non-existent ref is not fed to post-receive a
 '
 
 test_expect_success 'deletion of a non-existent ref alone does trigger post-receive and post-update hooks' '
-       mk_test_with_hooks heads/master &&
+       mk_test_with_hooks testrepo heads/master &&
        git push testrepo :refs/heads/nonexistent &&
        (
                cd testrepo/.git &&
@@ -685,7 +733,7 @@ test_expect_success 'deletion of a non-existent ref alone does trigger post-rece
 '
 
 test_expect_success 'mixed ref updates, deletes, invalid deletes trigger hooks with correct input' '
-       mk_test_with_hooks heads/master heads/next heads/pu &&
+       mk_test_with_hooks testrepo heads/master heads/next heads/pu &&
        orgmaster=$(cd testrepo && git show-ref -s --verify refs/heads/master) &&
        newmaster=$(git show-ref -s --verify refs/heads/master) &&
        orgnext=$(cd testrepo && git show-ref -s --verify refs/heads/next) &&
@@ -731,14 +779,14 @@ test_expect_success 'mixed ref updates, deletes, invalid deletes trigger hooks w
 '
 
 test_expect_success 'allow deleting a ref using --delete' '
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        (cd testrepo && git config receive.denyDeleteCurrent warn) &&
        git push testrepo --delete master &&
        (cd testrepo && test_must_fail git rev-parse --verify refs/heads/master)
 '
 
 test_expect_success 'allow deleting a tag using --delete' '
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        git tag -a -m dummy_message deltag heads/master &&
        git push testrepo --tags &&
        (cd testrepo && git rev-parse --verify -q refs/tags/deltag) &&
@@ -747,17 +795,17 @@ test_expect_success 'allow deleting a tag using --delete' '
 '
 
 test_expect_success 'push --delete without args aborts' '
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        test_must_fail git push testrepo --delete
 '
 
 test_expect_success 'push --delete refuses src:dest refspecs' '
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        test_must_fail git push testrepo --delete master:foo
 '
 
 test_expect_success 'warn on push to HEAD of non-bare repository' '
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        (
                cd testrepo &&
                git checkout master &&
@@ -768,7 +816,7 @@ test_expect_success 'warn on push to HEAD of non-bare repository' '
 '
 
 test_expect_success 'deny push to HEAD of non-bare repository' '
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        (
                cd testrepo &&
                git checkout master &&
@@ -778,7 +826,7 @@ test_expect_success 'deny push to HEAD of non-bare repository' '
 '
 
 test_expect_success 'allow push to HEAD of bare repository (bare)' '
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        (
                cd testrepo &&
                git checkout master &&
@@ -790,7 +838,7 @@ test_expect_success 'allow push to HEAD of bare repository (bare)' '
 '
 
 test_expect_success 'allow push to HEAD of non-bare repository (config)' '
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        (
                cd testrepo &&
                git checkout master &&
@@ -801,7 +849,7 @@ test_expect_success 'allow push to HEAD of non-bare repository (config)' '
 '
 
 test_expect_success 'fetch with branches' '
-       mk_empty &&
+       mk_empty testrepo &&
        git branch second $the_first_commit &&
        git checkout second &&
        echo ".." > testrepo/.git/branches/branch1 &&
@@ -816,7 +864,7 @@ test_expect_success 'fetch with branches' '
 '
 
 test_expect_success 'fetch with branches containing #' '
-       mk_empty &&
+       mk_empty testrepo &&
        echo "..#second" > testrepo/.git/branches/branch2 &&
        (
                cd testrepo &&
@@ -829,7 +877,7 @@ test_expect_success 'fetch with branches containing #' '
 '
 
 test_expect_success 'push with branches' '
-       mk_empty &&
+       mk_empty testrepo &&
        git checkout second &&
        echo "testrepo" > .git/branches/branch1 &&
        git push branch1 &&
@@ -842,7 +890,7 @@ test_expect_success 'push with branches' '
 '
 
 test_expect_success 'push with branches containing #' '
-       mk_empty &&
+       mk_empty testrepo &&
        echo "testrepo#branch3" > .git/branches/branch2 &&
        git push branch2 &&
        (
@@ -855,9 +903,9 @@ test_expect_success 'push with branches containing #' '
 '
 
 test_expect_success 'push into aliased refs (consistent)' '
-       mk_test heads/master &&
-       mk_child child1 &&
-       mk_child child2 &&
+       mk_test testrepo heads/master &&
+       mk_child testrepo child1 &&
+       mk_child testrepo child2 &&
        (
                cd child1 &&
                git branch foo &&
@@ -877,9 +925,9 @@ test_expect_success 'push into aliased refs (consistent)' '
 '
 
 test_expect_success 'push into aliased refs (inconsistent)' '
-       mk_test heads/master &&
-       mk_child child1 &&
-       mk_child child2 &&
+       mk_test testrepo heads/master &&
+       mk_child testrepo child1 &&
+       mk_child testrepo child2 &&
        (
                cd child1 &&
                git branch foo &&
@@ -904,9 +952,9 @@ test_expect_success 'push into aliased refs (inconsistent)' '
 '
 
 test_expect_success 'push requires --force to update lightweight tag' '
-       mk_test heads/master &&
-       mk_child child1 &&
-       mk_child child2 &&
+       mk_test testrepo heads/master &&
+       mk_child testrepo child1 &&
+       mk_child testrepo child2 &&
        (
                cd child1 &&
                git tag Tag &&
@@ -925,7 +973,7 @@ test_expect_success 'push requires --force to update lightweight tag' '
 '
 
 test_expect_success 'push --porcelain' '
-       mk_empty &&
+       mk_empty testrepo &&
        echo >.git/foo  "To testrepo" &&
        echo >>.git/foo "*      refs/heads/master:refs/remotes/origin/master    [new branch]"  &&
        echo >>.git/foo "Done" &&
@@ -940,13 +988,13 @@ test_expect_success 'push --porcelain' '
 '
 
 test_expect_success 'push --porcelain bad url' '
-       mk_empty &&
+       mk_empty testrepo &&
        test_must_fail git push >.git/bar --porcelain asdfasdfasd refs/heads/master:refs/remotes/origin/master &&
        test_must_fail grep -q Done .git/bar
 '
 
 test_expect_success 'push --porcelain rejected' '
-       mk_empty &&
+       mk_empty testrepo &&
        git push testrepo refs/heads/master:refs/remotes/origin/master &&
        (cd testrepo &&
                git reset --hard origin/master^
@@ -960,7 +1008,7 @@ test_expect_success 'push --porcelain rejected' '
 '
 
 test_expect_success 'push --porcelain --dry-run rejected' '
-       mk_empty &&
+       mk_empty testrepo &&
        git push testrepo refs/heads/master:refs/remotes/origin/master &&
        (cd testrepo &&
                git reset --hard origin/master
@@ -975,25 +1023,25 @@ test_expect_success 'push --porcelain --dry-run rejected' '
 '
 
 test_expect_success 'push --prune' '
-       mk_test heads/master heads/second heads/foo heads/bar &&
-       git push --prune testrepo &&
-       check_push_result $the_commit heads/master &&
-       check_push_result $the_first_commit heads/second &&
-       ! check_push_result $the_first_commit heads/foo heads/bar
+       mk_test testrepo heads/master heads/second heads/foo heads/bar &&
+       git push --prune testrepo &&
+       check_push_result testrepo $the_commit heads/master &&
+       check_push_result testrepo $the_first_commit heads/second &&
+       ! check_push_result testrepo $the_first_commit heads/foo heads/bar
 '
 
 test_expect_success 'push --prune refspec' '
-       mk_test tmp/master tmp/second tmp/foo tmp/bar &&
+       mk_test testrepo tmp/master tmp/second tmp/foo tmp/bar &&
        git push --prune testrepo "refs/heads/*:refs/tmp/*" &&
-       check_push_result $the_commit tmp/master &&
-       check_push_result $the_first_commit tmp/second &&
-       ! check_push_result $the_first_commit tmp/foo tmp/bar
+       check_push_result testrepo $the_commit tmp/master &&
+       check_push_result testrepo $the_first_commit tmp/second &&
+       ! check_push_result testrepo $the_first_commit tmp/foo tmp/bar
 '
 
 for configsection in transfer receive
 do
        test_expect_success "push to update a ref hidden by $configsection.hiderefs" '
-               mk_test heads/master hidden/one hidden/two hidden/three &&
+               mk_test testrepo heads/master hidden/one hidden/two hidden/three &&
                (
                        cd testrepo &&
                        git config $configsection.hiderefs refs/hidden
@@ -1001,32 +1049,32 @@ do
 
                # push to unhidden ref succeeds normally
                git push testrepo master:refs/heads/master &&
-               check_push_result $the_commit heads/master &&
+               check_push_result testrepo $the_commit heads/master &&
 
                # push to update a hidden ref should fail
                test_must_fail git push testrepo master:refs/hidden/one &&
-               check_push_result $the_first_commit hidden/one &&
+               check_push_result testrepo $the_first_commit hidden/one &&
 
                # push to delete a hidden ref should fail
                test_must_fail git push testrepo :refs/hidden/two &&
-               check_push_result $the_first_commit hidden/two &&
+               check_push_result testrepo $the_first_commit hidden/two &&
 
                # idempotent push to update a hidden ref should fail
                test_must_fail git push testrepo $the_first_commit:refs/hidden/three &&
-               check_push_result $the_first_commit hidden/three
+               check_push_result testrepo $the_first_commit hidden/three
        '
 done
 
 test_expect_success 'fetch exact SHA1' '
-       mk_test heads/master hidden/one &&
+       mk_test testrepo heads/master hidden/one &&
        git push testrepo master:refs/hidden/one &&
        (
                cd testrepo &&
                git config transfer.hiderefs refs/hidden
        ) &&
-       check_push_result $the_commit hidden/one &&
+       check_push_result testrepo $the_commit hidden/one &&
 
-       mk_child child &&
+       mk_child testrepo child &&
        (
                cd child &&
 
@@ -1052,7 +1100,7 @@ test_expect_success 'fetch exact SHA1' '
 '
 
 test_expect_success 'fetch follows tags by default' '
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        rm -fr src dst &&
        git init src &&
        (
@@ -1079,7 +1127,7 @@ test_expect_success 'fetch follows tags by default' '
 '
 
 test_expect_success 'push does not follow tags by default' '
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        rm -fr src dst &&
        git init src &&
        git init --bare dst &&
@@ -1102,7 +1150,7 @@ test_expect_success 'push does not follow tags by default' '
 '
 
 test_expect_success 'push --follow-tag only pushes relevant tags' '
-       mk_test heads/master &&
+       mk_test testrepo heads/master &&
        rm -fr src dst &&
        git init src &&
        git init --bare dst &&
index e2ad2605084194868fc23e23fec1636af622b47f..12a5dfb17e0a0bd4d0d9636ff13bf44999f78e36 100755 (executable)
@@ -256,7 +256,7 @@ test_expect_success 'remote.foo.mirror=no has no effect' '
                git branch keep master &&
                git push --mirror up &&
                git branch -D keep &&
-               git push up
+               git push up :
        ) &&
        (
                cd mirror &&
index c00c9b071d696038f63e8d613e11beab68eb547e..11fcd37700f372117145258f209e6c56ae04a1fc 100755 (executable)
@@ -40,7 +40,7 @@ test_expect_success 'alice works and pushes' '
                cd alice-work &&
                echo more >file &&
                git commit -a -m second &&
-               git push ../alice-pub
+               git push ../alice-pub :
        )
 '
 
@@ -57,7 +57,7 @@ test_expect_success 'bob fetches from alice, works and pushes' '
                git pull ../alice-pub master &&
                echo more bob >file &&
                git commit -a -m third &&
-               git push ../bob-pub
+               git push ../bob-pub :
        ) &&
 
        # Check that the second commit by Alice is not sent
@@ -86,7 +86,7 @@ test_expect_success 'alice works and pushes again' '
                cd alice-work &&
                echo more alice >file &&
                git commit -a -m fourth &&
-               git push ../alice-pub
+               git push ../alice-pub :
        )
 '
 
@@ -99,7 +99,7 @@ test_expect_success 'bob works and pushes' '
                cd bob-work &&
                echo yet more bob >file &&
                git commit -a -m fifth &&
-               git push ../bob-pub
+               git push ../bob-pub :
        )
 '
 
@@ -115,7 +115,7 @@ test_expect_success 'alice works and pushes yet again' '
                git commit -a -m sixth.2 &&
                echo more and more alice >>file &&
                git commit -a -m sixth.3 &&
-               git push ../alice-pub
+               git push ../alice-pub :
        )
 '
 
@@ -136,7 +136,7 @@ test_expect_success 'bob works and pushes again' '
                git hash-object -t commit -w commit &&
                echo even more bob >file &&
                git commit -a -m seventh &&
-               git push ../bob-pub
+               git push ../bob-pub :
        )
 '
 
index 1947c28c6466d46c79c7b1b093488c1620324172..8c16e045a0c585957a0be4e31b5628d1d5b6cb23 100755 (executable)
@@ -16,6 +16,7 @@ test_expect_success setup '
                (
                        cd gar/bage &&
                        git init &&
+                       git config push.default matching &&
                        >junk &&
                        git add junk &&
                        git commit -m "Initial junk"
index 80d20c876bbac0b00d388d511da555a29e827dbc..f7d0f146f0f69775dd3fa3ea06895e2bb1a74d55 100755 (executable)
@@ -13,6 +13,7 @@ LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5550'}
 start_httpd
 
 test_expect_success 'setup repository' '
+       git config push.default matching &&
        echo content1 >file &&
        git add file &&
        git commit -m one
index 47eb76921ddd53acb63573f9af75e41ab5067f5c..b23efbbfd9586670f1eeee114a1335b9dad4d97f 100755 (executable)
@@ -13,6 +13,7 @@ LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5551'}
 start_httpd
 
 test_expect_success 'setup repository' '
+       git config push.default matching &&
        echo content >file &&
        git add file &&
        git commit -m one
@@ -162,6 +163,30 @@ test_expect_success 'invalid Content-Type rejected' '
        grep "not valid:" actual
 '
 
+test_expect_success 'create namespaced refs' '
+       test_commit namespaced &&
+       git push public HEAD:refs/namespaces/ns/refs/heads/master &&
+       git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
+               symbolic-ref refs/namespaces/ns/HEAD refs/namespaces/ns/refs/heads/master
+'
+
+test_expect_success 'smart clone respects namespace' '
+       git clone "$HTTPD_URL/smart_namespace/repo.git" ns-smart &&
+       echo namespaced >expect &&
+       git --git-dir=ns-smart/.git log -1 --format=%s >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'dumb clone via http-backend respects namespace' '
+       git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
+               config http.getanyfile true &&
+       GIT_SMART_HTTP=0 git clone \
+               "$HTTPD_URL/smart_namespace/repo.git" ns-dumb &&
+       echo namespaced >expect &&
+       git --git-dir=ns-dumb/.git log -1 --format=%s >actual &&
+       test_cmp expect actual
+'
+
 test -n "$GIT_TEST_LONG" && test_set_prereq EXPENSIVE
 
 test_expect_success EXPENSIVE 'create 50,000 tags in the repo' '
index a3a4e47e1d25379e981373e67124c9efe5c76213..f01edffa3c0babf76593fbd211f6606ff2036c74 100755 (executable)
@@ -8,6 +8,7 @@ LIB_GIT_DAEMON_PORT=${LIB_GIT_DAEMON_PORT-5570}
 start_git_daemon
 
 test_expect_success 'setup repository' '
+       git config push.default matching &&
        echo content >file &&
        git add file &&
        git commit -m one
index 9e43731fe504c46737c5294e4d508b5c20bbb663..a45c31692e17218988e6619742c366043e426039 100755 (executable)
@@ -58,4 +58,14 @@ test_expect_success 'ridiculously long subject in boundary' '
        grep "^-[0-9a-f]\\{40\\} " boundary
 '
 
+test_expect_success 'prerequisites with an empty commit message' '
+       : >file1 &&
+       git add file1 &&
+       test_tick &&
+       git commit --allow-empty-message -m "" &&
+       test_commit file2 &&
+       git bundle create bundle HEAD^.. &&
+       git bundle verify bundle
+'
+
 test_done
index aa045295dec5af9dedc25495668d4afd6022d2cd..8956c21617410863660bff0bc22ec8e81903e81a 100755 (executable)
@@ -58,13 +58,7 @@ test_expect_success 'creating too deep nesting' \
 git clone -l -s D E &&
 git clone -l -s E F &&
 git clone -l -s F G &&
-git clone -l -s G H'
-
-test_expect_success 'invalidity of deepest repository' \
-'cd H && {
-       test_valid_repo
-       test $? -ne 0
-}'
+test_must_fail git clone --bare -l -s G H'
 
 cd "$base_dir"
 
index 8e2ff13423ba01095404ec49232760bc66c68978..dd6dc844e787549ab7622fb4fbec4f89b52e22ab 100755 (executable)
@@ -77,14 +77,16 @@ test_expect_success setup '
 
 FMT='tformat:%P        %H | %s'
 
-check_result () {
+check_outcome () {
+       outcome=$1
+       shift
        for c in $1
        do
                echo "$c"
        done >expect &&
        shift &&
        param="$*" &&
-       test_expect_success "log $param" '
+       test_expect_$outcome "log $param" '
                git log --pretty="$FMT" --parents $param |
                unnote >actual &&
                sed -e "s/^.*   \([^ ]*\) .*/\1/" >check <actual &&
@@ -95,11 +97,15 @@ check_result () {
        '
 }
 
+check_result () {
+       check_outcome success "$@"
+}
+
 check_result 'L K J I H G F E D C B A' --full-history
 check_result 'K I H E C B A' --full-history -- file
 check_result 'K I H E C B A' --full-history --topo-order -- file
 check_result 'K I H E C B A' --full-history --date-order -- file
-check_result 'I E C B A' --simplify-merges -- file
+check_outcome failure 'I E C B A' --simplify-merges -- file
 check_result 'I B A' -- file
 check_result 'I B A' --topo-order -- file
 check_result 'H' --first-parent -- another-file
index 2fce99a0754481a36b3644d01f8577310e19d763..8bf53de3ef6bc7cc5de14b70e93ffe42b9b3f094 100755 (executable)
@@ -190,7 +190,7 @@ test_expect_success 'bisect start: no ".git/BISECT_START" if checkout error' '
 # $HASH1 is good, $HASH4 is bad, we skip $HASH3
 # but $HASH2 is bad,
 # so we should find $HASH2 as the first bad commit
-test_expect_success 'bisect skip: successfull result' '
+test_expect_success 'bisect skip: successful result' '
        git bisect reset &&
        git bisect start $HASH4 $HASH1 &&
        git bisect skip &&
index 992c2a04674d474a8875da955935512ec99f335a..54b5744cc526e172acb79bb204af1800fdceb315 100755 (executable)
@@ -112,8 +112,8 @@ test_expect_success '[merge] summary/log configuration' '
          Common #1
        EOF
 
-       git config merge.log true &&
-       test_might_fail git config --unset-all merge.summary &&
+       test_config merge.log true &&
+       test_unconfig merge.summary &&
 
        git checkout master &&
        test_tick &&
@@ -121,8 +121,8 @@ test_expect_success '[merge] summary/log configuration' '
 
        git fmt-merge-msg <.git/FETCH_HEAD >actual1 &&
 
-       test_might_fail git config --unset-all merge.log &&
-       git config merge.summary true &&
+       test_unconfig merge.log &&
+       test_config merge.summary true &&
 
        git checkout master &&
        test_tick &&
@@ -134,11 +134,6 @@ test_expect_success '[merge] summary/log configuration' '
        test_cmp expected actual2
 '
 
-test_expect_success 'setup: clear [merge] configuration' '
-       test_might_fail git config --unset-all merge.log &&
-       test_might_fail git config --unset-all merge.summary
-'
-
 test_expect_success 'setup FETCH_HEAD' '
        git checkout master &&
        test_tick &&
@@ -180,6 +175,24 @@ test_expect_success 'merge.log=5 shows all 5 commits' '
        test_cmp expected actual
 '
 
+test_expect_success '--log=5 with custom comment character' '
+       cat >expected <<-EOF &&
+       Merge branch ${apos}left${apos}
+
+       x By Another Author (3) and A U Thor (2)
+       x Via Another Committer
+       * left:
+         Left #5
+         Left #4
+         Left #3
+         Common #2
+         Common #1
+       EOF
+
+       git -c core.commentchar="x" fmt-merge-msg --log=5 <.git/FETCH_HEAD >actual &&
+       test_cmp expected actual
+'
+
 test_expect_success 'merge.log=0 disables shortlog' '
        echo "Merge branch ${apos}left${apos}" >expected
        git -c merge.log=0 fmt-merge-msg <.git/FETCH_HEAD >actual &&
@@ -248,14 +261,14 @@ test_expect_success 'fmt-merge-msg -m' '
          Common #1
        EOF
 
-       test_might_fail git config --unset merge.log &&
-       test_might_fail git config --unset merge.summary &&
+       test_unconfig merge.log &&
+       test_unconfig merge.summary &&
        git checkout master &&
        git fetch "$(pwd)" left &&
        git fmt-merge-msg -m "Sync with left" <.git/FETCH_HEAD >actual &&
        git fmt-merge-msg --log -m "Sync with left" \
                                        <.git/FETCH_HEAD >actual.log &&
-       git config merge.log true &&
+       test_config merge.log true &&
        git fmt-merge-msg -m "Sync with left" \
                                        <.git/FETCH_HEAD >actual.log-config &&
        git fmt-merge-msg --no-log -m "Sync with left" \
@@ -290,29 +303,29 @@ test_expect_success 'setup: expected shortlog for two branches' '
 '
 
 test_expect_success 'shortlog for two branches' '
-       git config merge.log true &&
-       test_might_fail git config --unset-all merge.summary &&
+       test_config merge.log true &&
+       test_unconfig merge.summary &&
        git checkout master &&
        test_tick &&
        git fetch . left right &&
        git fmt-merge-msg <.git/FETCH_HEAD >actual1 &&
 
-       test_might_fail git config --unset-all merge.log &&
-       git config merge.summary true &&
+       test_unconfig merge.log &&
+       test_config merge.summary true &&
        git checkout master &&
        test_tick &&
        git fetch . left right &&
        git fmt-merge-msg <.git/FETCH_HEAD >actual2 &&
 
-       git config merge.log yes &&
-       test_might_fail git config --unset-all merge.summary &&
+       test_config merge.log yes &&
+       test_unconfig merge.summary &&
        git checkout master &&
        test_tick &&
        git fetch . left right &&
        git fmt-merge-msg <.git/FETCH_HEAD >actual3 &&
 
-       test_might_fail git config --unset-all merge.log &&
-       git config merge.summary yes &&
+       test_unconfig merge.log &&
+       test_config merge.summary yes &&
        git checkout master &&
        test_tick &&
        git fetch . left right &&
@@ -325,8 +338,8 @@ test_expect_success 'shortlog for two branches' '
 '
 
 test_expect_success 'merge-msg -F' '
-       test_might_fail git config --unset-all merge.log &&
-       git config merge.summary yes &&
+       test_unconfig merge.log &&
+       test_config merge.summary yes &&
        git checkout master &&
        test_tick &&
        git fetch . left right &&
@@ -335,8 +348,8 @@ test_expect_success 'merge-msg -F' '
 '
 
 test_expect_success 'merge-msg -F in subdirectory' '
-       test_might_fail git config --unset-all merge.log &&
-       git config merge.summary yes &&
+       test_unconfig merge.log &&
+       test_config merge.summary yes &&
        git checkout master &&
        test_tick &&
        git fetch . left right &&
@@ -350,8 +363,8 @@ test_expect_success 'merge-msg -F in subdirectory' '
 '
 
 test_expect_success 'merge-msg with nothing to merge' '
-       test_might_fail git config --unset-all merge.log &&
-       git config merge.summary yes &&
+       test_unconfig merge.log &&
+       test_config merge.summary yes &&
 
        >empty &&
 
@@ -376,8 +389,8 @@ test_expect_success 'merge-msg tag' '
          Common #1
        EOF
 
-       test_might_fail git config --unset-all merge.log &&
-       git config merge.summary yes &&
+       test_unconfig merge.log &&
+       test_config merge.summary yes &&
 
        git checkout master &&
        test_tick &&
@@ -406,8 +419,8 @@ test_expect_success 'merge-msg two tags' '
          Common #1
        EOF
 
-       test_might_fail git config --unset-all merge.log &&
-       git config merge.summary yes &&
+       test_unconfig merge.log &&
+       test_config merge.summary yes &&
 
        git checkout master &&
        test_tick &&
@@ -436,8 +449,8 @@ test_expect_success 'merge-msg tag and branch' '
          Common #1
        EOF
 
-       test_might_fail git config --unset-all merge.log &&
-       git config merge.summary yes &&
+       test_unconfig merge.log &&
+       test_config merge.summary yes &&
 
        git checkout master &&
        test_tick &&
@@ -464,6 +477,8 @@ test_expect_success 'merge-msg lots of commits' '
                echo "  ..."
        } >expected &&
 
+       test_config merge.summary yes &&
+
        git checkout master &&
        test_tick &&
        git fetch . long &&
@@ -472,4 +487,43 @@ test_expect_success 'merge-msg lots of commits' '
        test_cmp expected actual
 '
 
+test_expect_success 'merge-msg with "merging" an annotated tag' '
+       test_config merge.log true &&
+
+       git checkout master^0 &&
+       git commit --allow-empty -m "One step ahead" &&
+       git tag -a -m "An annotated one" annote HEAD &&
+
+       git checkout master &&
+       git fetch . annote &&
+
+       git fmt-merge-msg <.git/FETCH_HEAD >actual &&
+       {
+               cat <<-\EOF
+               Merge tag '\''annote'\''
+
+               An annotated one
+
+               * tag '\''annote'\'':
+                 One step ahead
+               EOF
+       } >expected &&
+       test_cmp expected actual &&
+
+       test_when_finished "git reset --hard" &&
+       annote=$(git rev-parse annote) &&
+       git merge --no-commit $annote &&
+       {
+               cat <<-EOF
+               Merge tag '\''$annote'\''
+
+               An annotated one
+
+               * tag '\''$annote'\'':
+                 One step ahead
+               EOF
+       } >expected &&
+       test_cmp expected .git/MERGE_MSG
+'
+
 test_done
index 1e7a209efa715bc52d14d7f653ecfc13ffb5301f..9496736a89eb6b0b1ece64052cd2726c516c952b 100755 (executable)
@@ -64,6 +64,20 @@ test_expect_success 'correct GIT_DIR while using -d' '
        grep drepo "$TRASHDIR/backup-refs"
 '
 
+test_expect_success 'tree-filter works with -d' '
+       git init drepo-tree &&
+       (
+               cd drepo-tree &&
+               test_commit one &&
+               git filter-branch -d "$TRASHDIR/dfoo" \
+                       --tree-filter "echo changed >one.t" &&
+               echo changed >expect &&
+               git cat-file blob HEAD:one.t >actual &&
+               test_cmp expect actual &&
+               test_cmp one.t actual
+       )
+'
+
 test_expect_success 'Fail if commit filter fails' '
        test_must_fail git filter-branch -f --commit-filter "exit 1" HEAD
 '
index 5030f1f1bcc2442482ca923d03454fbc69f1a7ca..ff265353a375d02bb578fed29ea00f07dc08a6fc 100755 (executable)
@@ -777,18 +777,22 @@ test_expect_success 'submodule deinit . deinits all initialized submodules' '
        git config submodule.example.foo bar &&
        git config submodule.example2.frotz nitfol &&
        test_must_fail git submodule deinit &&
-       git submodule deinit . &&
+       git submodule deinit . >actual &&
        test -z "$(git config --get-regexp "submodule\.example\.")" &&
        test -z "$(git config --get-regexp "submodule\.example2\.")" &&
+       test_i18ngrep "Cleared directory .init" actual &&
+       test_i18ngrep "Cleared directory .example2" actual &&
        rmdir init example2
 '
 
 test_expect_success 'submodule deinit deinits a submodule when its work tree is missing or empty' '
        git submodule update --init &&
        rm -rf init example2/* example2/.git &&
-       git submodule deinit init example2 &&
+       git submodule deinit init example2 >actual &&
        test -z "$(git config --get-regexp "submodule\.example\.")" &&
        test -z "$(git config --get-regexp "submodule\.example2\.")" &&
+       test_i18ngrep ! "Cleared directory .init" actual &&
+       test_i18ngrep "Cleared directory .example2" actual &&
        rmdir init
 '
 
@@ -798,8 +802,9 @@ test_expect_success 'submodule deinit fails when the submodule contains modifica
        test_must_fail git submodule deinit init &&
        test -n "$(git config --get-regexp "submodule\.example\.")" &&
        test -f example2/.git &&
-       git submodule deinit -f init &&
+       git submodule deinit -f init >actual &&
        test -z "$(git config --get-regexp "submodule\.example\.")" &&
+       test_i18ngrep "Cleared directory .init" actual &&
        rmdir init
 '
 
@@ -809,8 +814,9 @@ test_expect_success 'submodule deinit fails when the submodule contains untracke
        test_must_fail git submodule deinit init &&
        test -n "$(git config --get-regexp "submodule\.example\.")" &&
        test -f example2/.git &&
-       git submodule deinit -f init &&
+       git submodule deinit -f init >actual &&
        test -z "$(git config --get-regexp "submodule\.example\.")" &&
+       test_i18ngrep "Cleared directory .init" actual &&
        rmdir init
 '
 
@@ -823,8 +829,9 @@ test_expect_success 'submodule deinit fails when the submodule HEAD does not mat
        test_must_fail git submodule deinit init &&
        test -n "$(git config --get-regexp "submodule\.example\.")" &&
        test -f example2/.git &&
-       git submodule deinit -f init &&
+       git submodule deinit -f init >actual &&
        test -z "$(git config --get-regexp "submodule\.example\.")" &&
+       test_i18ngrep "Cleared directory .init" actual &&
        rmdir init
 '
 
@@ -832,14 +839,18 @@ test_expect_success 'submodule deinit is silent when used on an uninitialized su
        git submodule update --init &&
        git submodule deinit init >actual &&
        test_i18ngrep "Submodule .example. (.*) unregistered for path .init" actual &&
+       test_i18ngrep "Cleared directory .init" actual &&
        git submodule deinit init >actual &&
        test_i18ngrep ! "Submodule .example. (.*) unregistered for path .init" actual &&
+       test_i18ngrep "Cleared directory .init" actual &&
        git submodule deinit . >actual &&
        test_i18ngrep ! "Submodule .example. (.*) unregistered for path .init" actual &&
        test_i18ngrep "Submodule .example2. (.*) unregistered for path .example2" actual &&
+       test_i18ngrep "Cleared directory .init" actual &&
        git submodule deinit . >actual &&
        test_i18ngrep ! "Submodule .example. (.*) unregistered for path .init" actual &&
        test_i18ngrep ! "Submodule .example2. (.*) unregistered for path .example2" actual &&
+       test_i18ngrep "Cleared directory .init" actual &&
        rmdir init example2
 '
 
index 2a0cfaac329c6c0974f205c81c45a0304a04897d..a4ffea0dbe743a1bbe4c5512037a6b1ffde1c313 100755 (executable)
@@ -596,14 +596,14 @@ test_expect_success 'submodule add places git-dir in superprojects git-dir recur
           git log > ../../../expected
          ) &&
          git commit -m "added subsubmodule" &&
-         git push
+         git push origin :
         ) &&
         (cd .git/modules/deeper/submodule/modules/subsubmodule &&
          git log > ../../../../../actual
         ) &&
         git add deeper/submodule &&
         git commit -m "update submodule" &&
-        git push &&
+        git push origin : &&
         test_cmp actual expected
        )
 '
index 06749a6aa07e40a5e5081c8912264d9c15b385ef..bf08d4e098f1bdc3adc5ec3df37b90d90b0e5c8f 100755 (executable)
@@ -678,4 +678,62 @@ test_expect_success 'status showing detached from a tag' '
        test_i18ncmp expected actual
 '
 
+test_expect_success 'status while reverting commit (conflicts)' '
+       git checkout master &&
+       echo before >to-revert.txt &&
+       test_commit before to-revert.txt &&
+       echo old >to-revert.txt &&
+       test_commit old to-revert.txt &&
+       echo new >to-revert.txt &&
+       test_commit new to-revert.txt &&
+       TO_REVERT=$(git rev-parse --short HEAD^) &&
+       test_must_fail git revert $TO_REVERT &&
+       cat >expected <<-EOF
+       # On branch master
+       # You are currently reverting commit $TO_REVERT.
+       #   (fix conflicts and run "git revert --continue")
+       #   (use "git revert --abort" to cancel the revert operation)
+       #
+       # Unmerged paths:
+       #   (use "git reset HEAD <file>..." to unstage)
+       #   (use "git add <file>..." to mark resolution)
+       #
+       #       both modified:      to-revert.txt
+       #
+       no changes added to commit (use "git add" and/or "git commit -a")
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+test_expect_success 'status while reverting commit (conflicts resolved)' '
+       echo reverted >to-revert.txt &&
+       git add to-revert.txt &&
+       cat >expected <<-EOF
+       # On branch master
+       # You are currently reverting commit $TO_REVERT.
+       #   (all conflicts fixed: run "git revert --continue")
+       #   (use "git revert --abort" to cancel the revert operation)
+       #
+       # Changes to be committed:
+       #   (use "git reset HEAD <file>..." to unstage)
+       #
+       #       modified:   to-revert.txt
+       #
+       # Untracked files not listed (use -u option to show untracked files)
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
+test_expect_success 'status after reverting commit' '
+       git revert --continue &&
+       cat >expected <<-\EOF
+       # On branch master
+       nothing to commit (use -u to show untracked files)
+       EOF
+       git status --untracked-files=no >actual &&
+       test_i18ncmp expected actual
+'
+
 test_done
index b44b29395049308b30e61b00a55e2eb39f4355a1..25dac798894f6a3cb4b62c8b9ba944bfc1d82d9f 100755 (executable)
@@ -109,7 +109,7 @@ test_expect_success 'setup conflicted merge' '
 '
 
 # First do the merge with resolve and recursive then verify that
-# recusive is choosen.
+# recusive is chosen.
 
 test_expect_success 'merge picks up the best result' '
        git config --unset-all pull.twohead &&
index bc38737b2a5ebd9b7ba20fcb92ac87c48b9496c8..d526b1d96a2e98bc304f4d36eaaa60858080e63d 100755 (executable)
@@ -237,7 +237,7 @@ test_expect_success 'mergetool takes partial path' '
     git submodule update -N &&
     test_must_fail git merge master &&
 
-    #shouldnt need these lines
+    #should not need these lines
     #( yes "d" | git mergetool file11 >/dev/null 2>&1 ) &&
     #( yes "d" | git mergetool file12 >/dev/null 2>&1 ) &&
     #( yes "l" | git mergetool submod >/dev/null 2>&1 ) &&
diff --git a/t/t7612-merge-verify-signatures.sh b/t/t7612-merge-verify-signatures.sh
new file mode 100755 (executable)
index 0000000..21a0bf8
--- /dev/null
@@ -0,0 +1,61 @@
+#!/bin/sh
+
+test_description='merge signature verification tests'
+. ./test-lib.sh
+. "$TEST_DIRECTORY/lib-gpg.sh"
+
+test_expect_success GPG 'create signed commits' '
+       echo 1 >file && git add file &&
+       test_tick && git commit -m initial &&
+       git tag initial &&
+
+       git checkout -b side-signed &&
+       echo 3 >elif && git add elif &&
+       test_tick && git commit -S -m "signed on side" &&
+       git checkout initial &&
+
+       git checkout -b side-unsigned &&
+       echo 3 >foo && git add foo &&
+       test_tick && git commit -m "unsigned on side" &&
+       git checkout initial &&
+
+       git checkout -b side-bad &&
+       echo 3 >bar && git add bar &&
+       test_tick && git commit -S -m "bad on side" &&
+       git cat-file commit side-bad >raw &&
+       sed -e "s/bad/forged bad/" raw >forged &&
+       git hash-object -w -t commit forged >forged.commit &&
+       git checkout initial &&
+
+       git checkout -b side-untrusted &&
+       echo 3 >baz && git add baz &&
+       test_tick && git commit -SB7227189 -m "untrusted on side"
+
+       git checkout master
+'
+
+test_expect_success GPG 'merge unsigned commit with verification' '
+       test_must_fail git merge --ff-only --verify-signatures side-unsigned 2>mergeerror &&
+       test_i18ngrep "does not have a GPG signature" mergeerror
+'
+
+test_expect_success GPG 'merge commit with bad signature with verification' '
+       test_must_fail git merge --ff-only --verify-signatures $(cat forged.commit) 2>mergeerror &&
+       test_i18ngrep "has a bad GPG signature" mergeerror
+'
+
+test_expect_success GPG 'merge commit with untrusted signature with verification' '
+       test_must_fail git merge --ff-only --verify-signatures side-untrusted 2>mergeerror &&
+       test_i18ngrep "has an untrusted GPG signature" mergeerror
+'
+
+test_expect_success GPG 'merge signed commit with verification' '
+       git merge --verbose --ff-only --verify-signatures side-signed >mergeoutput &&
+       test_i18ngrep "has a good GPG signature" mergeoutput
+'
+
+test_expect_success GPG 'merge commit with bad signature without verification' '
+       git merge $(cat forged.commit)
+'
+
+test_done
index c6d6b1c99fe98b7dc692eaf3828a08696bfb5e10..a6bd99eaf51943a899aa5e5801479b0a84b6b692 100755 (executable)
@@ -23,16 +23,6 @@ prompt_given ()
        test "$prompt" = "Launch 'test-tool' [Y/n]: branch"
 }
 
-stdin_contains ()
-{
-       grep >/dev/null "$1"
-}
-
-stdin_doesnot_contain ()
-{
-       ! stdin_contains "$1"
-}
-
 # Create a file on master and change it on branch
 test_expect_success PERL 'setup' '
        echo master >file &&
@@ -296,24 +286,24 @@ test_expect_success PERL 'setup with 2 files different' '
 test_expect_success PERL 'say no to the first file' '
        (echo n && echo) >input &&
        git difftool -x cat branch <input >output &&
-       stdin_contains m2 <output &&
-       stdin_contains br2 <output &&
-       stdin_doesnot_contain master <output &&
-       stdin_doesnot_contain branch <output
+       grep m2 output &&
+       grep br2 output &&
+       ! grep master output &&
+       ! grep branch output
 '
 
 test_expect_success PERL 'say no to the second file' '
        (echo && echo n) >input &&
        git difftool -x cat branch <input >output &&
-       stdin_contains master <output &&
-       stdin_contains branch  <output &&
-       stdin_doesnot_contain m2 <output &&
-       stdin_doesnot_contain br2 <output
+       grep master output &&
+       grep branch output &&
+       ! grep m2 output &&
+       ! grep br2 output
 '
 
 test_expect_success PERL 'difftool --tool-help' '
        git difftool --tool-help >output &&
-       stdin_contains tool <output
+       grep tool output
 '
 
 test_expect_success PERL 'setup change in subdirectory' '
@@ -324,20 +314,46 @@ test_expect_success PERL 'setup change in subdirectory' '
        git commit -m "added sub/sub" &&
        echo test >>file &&
        echo test >>sub/sub &&
-       git add . &&
+       git add file sub/sub &&
        git commit -m "modified both"
 '
 
-test_expect_success PERL 'difftool -d' '
-       git difftool -d --extcmd ls branch >output &&
-       stdin_contains sub <output &&
-       stdin_contains file <output
+run_dir_diff_test () {
+       test_expect_success PERL "$1 --no-symlinks" "
+               symlinks=--no-symlinks &&
+               $2
+       "
+       test_expect_success PERL,SYMLINKS "$1 --symlinks" "
+               symlinks=--symlinks &&
+               $2
+       "
+}
+
+run_dir_diff_test 'difftool -d' '
+       git difftool -d $symlinks --extcmd ls branch >output &&
+       grep sub output &&
+       grep file output
+'
+
+run_dir_diff_test 'difftool --dir-diff' '
+       git difftool --dir-diff $symlinks --extcmd ls branch >output &&
+       grep sub output &&
+       grep file output
 '
 
-test_expect_success PERL 'difftool --dir-diff' '
-       git difftool --dir-diff --extcmd ls branch >output &&
-       stdin_contains sub <output &&
-       stdin_contains file <output
+run_dir_diff_test 'difftool --dir-diff ignores --prompt' '
+       git difftool --dir-diff $symlinks --prompt --extcmd ls branch >output &&
+       grep sub output &&
+       grep file output
+'
+
+run_dir_diff_test 'difftool --dir-diff from subdirectory' '
+       (
+               cd sub &&
+               git difftool --dir-diff $symlinks --extcmd ls branch >output &&
+               grep sub output &&
+               grep file output
+       )
 '
 
 write_script .git/CHECK_SYMLINKS <<\EOF
@@ -362,18 +378,33 @@ test_expect_success PERL,SYMLINKS 'difftool --dir-diff --symlink without unstage
        test_cmp actual expect
 '
 
-test_expect_success PERL 'difftool --dir-diff ignores --prompt' '
-       git difftool --dir-diff --prompt --extcmd ls branch >output &&
-       stdin_contains sub <output &&
-       stdin_contains file <output
+write_script modify-file <<\EOF
+echo "new content" >file
+EOF
+
+test_expect_success PERL 'difftool --no-symlinks does not overwrite working tree file ' '
+       echo "orig content" >file &&
+       git difftool --dir-diff --no-symlinks --extcmd "$(pwd)/modify-file" branch &&
+       echo "new content" >expect &&
+       test_cmp expect file
 '
 
-test_expect_success PERL 'difftool --dir-diff from subdirectory' '
+write_script modify-both-files <<\EOF
+echo "wt content" >file &&
+echo "tmp content" >"$2/file" &&
+echo "$2" >tmpdir
+EOF
+
+test_expect_success PERL 'difftool --no-symlinks detects conflict ' '
        (
-               cd sub &&
-               git difftool --dir-diff --extcmd ls branch >output &&
-               stdin_contains sub <output &&
-               stdin_contains file <output
+               TMPDIR=$TRASH_DIRECTORY &&
+               export TMPDIR &&
+               echo "orig content" >file &&
+               test_must_fail git difftool --dir-diff --no-symlinks --extcmd "$(pwd)/modify-both-files" branch &&
+               echo "wt content" >expect &&
+               test_cmp expect file &&
+               echo "tmp content" >expect &&
+               test_cmp expect "$(cat tmpdir)/file"
        )
 '
 
index 97d6f4c7de57c54adfd5fed6401dbd168b5f3064..ebd5c5db45c8816f39b2d8c60775f455ab9c48aa 100755 (executable)
@@ -101,7 +101,7 @@ test_expect_success $PREREQ \
 
 test_expect_success $PREREQ 'Send patches with --envelope-sender' '
     clean_fake_sendmail &&
-     git send-email --envelope-sender="Patch Contributer <patch@example.com>" --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
+     git send-email --envelope-sender="Patch Contributor <patch@example.com>" --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
 '
 
 test_expect_success $PREREQ 'setup expect' '
@@ -787,7 +787,7 @@ test_expect_success $PREREQ 'confirm detects EOF (auto causes failure)' '
        test $ret = "0"
 '
 
-test_expect_success $PREREQ 'confirm doesnt loop forever' '
+test_expect_success $PREREQ 'confirm does not loop forever' '
        CONFIRM=$(git config --get sendemail.confirm) &&
        git config sendemail.confirm auto &&
        GIT_SEND_EMAIL_NOTTY=1 &&
index b7eed2489fa169aa1c6e5c98f59a0349ba8118fa..6dafe7e99ab4bd0006ed4f7204062fca31750689 100755 (executable)
@@ -54,14 +54,6 @@ text_no_props () {
 
 >empty
 
-test_expect_success 'setup: have pipes?' '
-       rm -f frob &&
-       if mkfifo frob
-       then
-               test_set_prereq PIPE
-       fi
-'
-
 test_expect_success PIPE 'empty dump' '
        reinit_git &&
        echo "SVN-fs-dump-format-version: 2" >input &&
index 2fcf2694696fedb5e7e3d57c869f7dbbbf23dbec..ac6f3b6af25c67ae3a2c0748c34f99b4cd0d4b32 100755 (executable)
@@ -49,14 +49,6 @@ echo "$@"'
 
 >empty
 
-test_expect_success 'setup: have pipes?' '
-       rm -f frob &&
-       if mkfifo frob
-       then
-               test_set_prereq PIPE
-       fi
-'
-
 ###
 ### series A
 ###
index 9502f2438aeeb47c0881b80326a4152002fc23ad..043138631b8ba7fa21899e634383925feb6737e8 100755 (executable)
@@ -36,6 +36,7 @@ export CVSROOT CVS_SERVER
 
 rm -rf "$CVSWORK" "$SERVERDIR"
 test_expect_success 'setup' '
+  git config push.default matching &&
   echo >empty &&
   git add empty &&
   git commit -q -m "First Commit" &&
index 1c5bc84fa72492a820638e4e197b89ba13bc27f1..8c3db763013ff736e173a405de70f68cbdddaf9f 100755 (executable)
@@ -84,6 +84,7 @@ export CVSROOT CVS_SERVER
 
 rm -rf "$CVSWORK" "$SERVERDIR"
 test_expect_success 'setup' '
+    git config push.default matching &&
     echo "Simple text file" >textfile.c &&
     echo "File with embedded NUL: Q <- there" | q_to_nul > binfile.bin &&
     mkdir subdir &&
index 0d4e366232c29bdde0e1059d431ae96afc259112..1140767b50706f03b0da5b2c8befdae6898e4136 100755 (executable)
@@ -45,7 +45,8 @@ BEGIN
 # Failure cases for config:
 # Save and restore STDERR; we will probably extract this into a
 # "dies_ok" method and possibly move the STDERR handling to Git.pm.
-open our $tmpstderr, ">&STDERR" or die "cannot save STDERR"; close STDERR;
+open our $tmpstderr, ">&STDERR" or die "cannot save STDERR";
+open STDERR, ">", "/dev/null" or die "cannot redirect STDERR to /dev/null";
 is($r->config("test.dupstring"), "value2", "config: multivar");
 eval { $r->config_bool("test.boolother") };
 ok($@, "config_bool: non-boolean values fail");
index adc1372b3c334b4305761f6c3922493c85a0822a..6d9d1418a041bd8b3dddb598ac5479c999047a06 100755 (executable)
@@ -69,6 +69,7 @@ run_completion ()
        local -a COMPREPLY _words
        local _cword
        _words=( $1 )
+       test "${1: -1}" == ' ' && _words+=('')
        (( _cword = ${#_words[@]} - 1 ))
        __git_wrap__git_main && print_comp
 }
@@ -104,6 +105,23 @@ test_gitcomp ()
        test_cmp expected out
 }
 
+# Test __gitcomp_nl
+# Arguments are:
+# 1: current word (cur)
+# -: the rest are passed to __gitcomp_nl
+test_gitcomp_nl ()
+{
+       local -a COMPREPLY &&
+       sed -e 's/Z$//' >expected &&
+       cur="$1" &&
+       shift &&
+       __gitcomp_nl "$@" &&
+       print_comp &&
+       test_cmp expected out
+}
+
+invalid_variable_name='${foo.bar}'
+
 test_expect_success '__gitcomp - trailing space - options' '
        test_gitcomp "--re" "--dry-run --reuse-message= --reedit-message=
                --reset-author" <<-EOF
@@ -147,8 +165,51 @@ test_expect_success '__gitcomp - suffix' '
        EOF
 '
 
+test_expect_success '__gitcomp - doesnt fail because of invalid variable name' '
+       __gitcomp "$invalid_variable_name"
+'
+
+read -r -d "" refs <<-\EOF
+maint
+master
+next
+pu
+EOF
+
+test_expect_success '__gitcomp_nl - trailing space' '
+       test_gitcomp_nl "m" "$refs" <<-EOF
+       maint Z
+       master Z
+       EOF
+'
+
+test_expect_success '__gitcomp_nl - prefix' '
+       test_gitcomp_nl "--fixup=m" "$refs" "--fixup=" "m" <<-EOF
+       --fixup=maint Z
+       --fixup=master Z
+       EOF
+'
+
+test_expect_success '__gitcomp_nl - suffix' '
+       test_gitcomp_nl "branch.ma" "$refs" "branch." "ma" "." <<-\EOF
+       branch.maint.Z
+       branch.master.Z
+       EOF
+'
+
+test_expect_success '__gitcomp_nl - no suffix' '
+       test_gitcomp_nl "ma" "$refs" "" "ma" "" <<-\EOF
+       maintZ
+       masterZ
+       EOF
+'
+
+test_expect_success '__gitcomp_nl - doesnt fail because of invalid variable name' '
+       __gitcomp_nl "$invalid_variable_name"
+'
+
 test_expect_success 'basic' '
-       run_completion "git \"\"" &&
+       run_completion "git " &&
        # built-in
        grep -q "^add \$" out &&
        # script
@@ -271,7 +332,7 @@ test_expect_success 'complete tree filename with spaces' '
        EOF
 '
 
-test_expect_failure 'complete tree filename with metacharacters' '
+test_expect_success 'complete tree filename with metacharacters' '
        echo content >"name with \${meta}" &&
        git add . &&
        git commit -m meta &&
index 2101d914f2d34d28b05ce17982a24c0b008809af..e147a8d277af7948cf165ea93899e9020a961d7a 100755 (executable)
@@ -59,7 +59,7 @@ test_expect_success 'gitdir - .git directory in cwd' '
 '
 
 test_expect_success 'gitdir - .git directory in parent' '
-       echo "$TRASH_DIRECTORY/.git" > expected &&
+       echo "$(pwd -P)/.git" > expected &&
        (
                cd subdir/subsubdir &&
                __gitdir > "$actual"
@@ -77,7 +77,7 @@ test_expect_success 'gitdir - cwd is a .git directory' '
 '
 
 test_expect_success 'gitdir - parent is a .git directory' '
-       echo "$TRASH_DIRECTORY/.git" > expected &&
+       echo "$(pwd -P)/.git" > expected &&
        (
                cd .git/refs/heads &&
                __gitdir > "$actual"
@@ -115,7 +115,7 @@ test_expect_success 'gitdir - non-existing $GIT_DIR' '
 '
 
 test_expect_success 'gitdir - gitfile in cwd' '
-       echo "$TRASH_DIRECTORY/otherrepo/.git" > expected &&
+       echo "$(pwd -P)/otherrepo/.git" > expected &&
        echo "gitdir: $TRASH_DIRECTORY/otherrepo/.git" > subdir/.git &&
        test_when_finished "rm -f subdir/.git" &&
        (
@@ -126,7 +126,7 @@ test_expect_success 'gitdir - gitfile in cwd' '
 '
 
 test_expect_success 'gitdir - gitfile in parent' '
-       echo "$TRASH_DIRECTORY/otherrepo/.git" > expected &&
+       echo "$(pwd -P)/otherrepo/.git" > expected &&
        echo "gitdir: $TRASH_DIRECTORY/otherrepo/.git" > subdir/.git &&
        test_when_finished "rm -f subdir/.git" &&
        (
@@ -137,7 +137,7 @@ test_expect_success 'gitdir - gitfile in parent' '
 '
 
 test_expect_success SYMLINKS 'gitdir - resulting path avoids symlinks' '
-       echo "$TRASH_DIRECTORY/otherrepo/.git" > expected &&
+       echo "$(pwd -P)/otherrepo/.git" > expected &&
        mkdir otherrepo/dir &&
        test_when_finished "rm -rf otherrepo/dir" &&
        ln -s otherrepo/dir link &&
index 61d0804435d3e8aed2f3b2c0308bc1a9143f1f5a..52510094add59b508e1581ffebfa555e7249561c 100644 (file)
@@ -91,6 +91,10 @@ q_to_tab () {
        tr Q '\011'
 }
 
+qz_to_tab_space () {
+       tr QZ '\011\040'
+}
+
 append_cr () {
        sed -e 's/$/Q/' | tr Q '\015'
 }
@@ -536,6 +540,9 @@ test_must_fail () {
        elif test $exit_code = 127; then
                echo >&2 "test_must_fail: command not found: $*"
                return 1
+       elif test $exit_code = 126; then
+               echo >&2 "test_must_fail: valgrind error: $*"
+               return 1
        fi
        return 0
 }
index 1f510252ad7cb7a5afae67731bc37fccf941b654..ca6bdef63d2ee9389729e5118f22461c887dc5ed 100644 (file)
@@ -193,7 +193,11 @@ do
        --no-color)
                color=; shift ;;
        --va|--val|--valg|--valgr|--valgri|--valgrin|--valgrind)
-               valgrind=t; verbose=t; shift ;;
+               valgrind=memcheck
+               shift ;;
+       --valgrind=*)
+               valgrind=$(expr "z$1" : 'z[^=]*=\(.*\)')
+               shift ;;
        --tee)
                shift ;; # was handled already
        --root=*)
@@ -204,6 +208,8 @@ do
        esac
 done
 
+test -n "$valgrind" && verbose=t
+
 if test -n "$color"
 then
        say_color () {
@@ -530,6 +536,8 @@ then
        PATH=$GIT_VALGRIND/bin:$PATH
        GIT_EXEC_PATH=$GIT_VALGRIND/bin
        export GIT_VALGRIND
+       GIT_VALGRIND_MODE="$valgrind"
+       export GIT_VALGRIND_MODE
 elif test -n "$GIT_TEST_INSTALLED"
 then
        GIT_EXEC_PATH=$($GIT_TEST_INSTALLED/git --exec-path)  ||
@@ -592,14 +600,14 @@ then
 fi
 
 # Test repository
-test="trash directory.$(basename "$0" .sh)"
-test -n "$root" && test="$root/$test"
-case "$test" in
-/*) TRASH_DIRECTORY="$test" ;;
- *) TRASH_DIRECTORY="$TEST_OUTPUT_DIRECTORY/$test" ;;
+TRASH_DIRECTORY="trash directory.$(basename "$0" .sh)"
+test -n "$root" && TRASH_DIRECTORY="$root/$TRASH_DIRECTORY"
+case "$TRASH_DIRECTORY" in
+/*) ;; # absolute path is good
+ *) TRASH_DIRECTORY="$TEST_OUTPUT_DIRECTORY/$TRASH_DIRECTORY" ;;
 esac
 test ! -z "$debug" || remove_trash=$TRASH_DIRECTORY
-rm -fr "$test" || {
+rm -fr "$TRASH_DIRECTORY" || {
        GIT_EXIT_OK=t
        echo >&5 "FATAL: Cannot prepare test area"
        exit 1
@@ -610,13 +618,13 @@ export HOME
 
 if test -z "$TEST_NO_CREATE_REPO"
 then
-       test_create_repo "$test"
+       test_create_repo "$TRASH_DIRECTORY"
 else
-       mkdir -p "$test"
+       mkdir -p "$TRASH_DIRECTORY"
 fi
 # Use -P to resolve symlinks in our working directory so that the cwd
 # in subprocesses like git equals our $PWD (for pathname comparisons).
-cd -P "$test" || exit 1
+cd -P "$TRASH_DIRECTORY" || exit 1
 
 this_test=${0##*/}
 this_test=${this_test%%-*}
@@ -727,6 +735,11 @@ test_i18ngrep () {
        fi
 }
 
+test_lazy_prereq PIPE '
+       # test whether the filesystem supports FIFOs
+       rm -f testfifo && mkfifo testfifo
+'
+
 test_lazy_prereq SYMLINKS '
        # test whether the filesystem supports symbolic links
        ln -s x y && test -h y
index 582b4dca9497363c7bfd6ae5ecc2c98d28d5ac0a..6b87c91b60cde4b19d6644227548f1ba6b226545 100755 (executable)
@@ -2,20 +2,27 @@
 
 base=$(basename "$0")
 
-TRACK_ORIGINS=
+TOOL_OPTIONS='--leak-check=no'
 
-VALGRIND_VERSION=$(valgrind --version)
-VALGRIND_MAJOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*\([0-9]*\)')
-VALGRIND_MINOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*[0-9]*\.\([0-9]*\)')
-test 3 -gt "$VALGRIND_MAJOR" ||
-test 3 -eq "$VALGRIND_MAJOR" -a 4 -gt "$VALGRIND_MINOR" ||
-TRACK_ORIGINS=--track-origins=yes
+case "$GIT_VALGRIND_MODE" in
+memcheck-fast)
+       ;;
+memcheck)
+       VALGRIND_VERSION=$(valgrind --version)
+       VALGRIND_MAJOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*\([0-9]*\)')
+       VALGRIND_MINOR=$(expr "$VALGRIND_VERSION" : '[^0-9]*[0-9]*\.\([0-9]*\)')
+       test 3 -gt "$VALGRIND_MAJOR" ||
+       test 3 -eq "$VALGRIND_MAJOR" -a 4 -gt "$VALGRIND_MINOR" ||
+       TOOL_OPTIONS="$TOOL_OPTIONS --track-origins=yes"
+       ;;
+*)
+       TOOL_OPTIONS="--tool=$GIT_VALGRIND_MODE"
+esac
 
 exec valgrind -q --error-exitcode=126 \
-       --leak-check=no \
-       --suppressions="$GIT_VALGRIND/default.supp" \
        --gen-suppressions=all \
-       $TRACK_ORIGINS \
+       --suppressions="$GIT_VALGRIND/default.supp" \
+       $TOOL_OPTIONS \
        --log-fd=4 \
        --input-fd=4 \
        $GIT_VALGRIND_OPTIONS \
index cb3ef7d38e475480a5d81ce6077c4c87ea09a318..dcd8d97411dd15e01ba1480a44b2a998043b424a 100644 (file)
@@ -991,7 +991,7 @@ struct unidirectional_transfer {
        int src_is_sock;
        /* Is destination socket? */
        int dest_is_sock;
-       /* Transfer state (TRANSFERING/FLUSHING/FINISHED) */
+       /* Transfer state (TRANSFERRING/FLUSHING/FINISHED) */
        int state;
        /* Buffer. */
        char buf[BUFFERSIZE];
index 93544627087bdaed1373efb2205fc6f94b89527c..fcb1d25d96a750c171c4341a9c5f08992915fb6b 100644 (file)
@@ -74,7 +74,7 @@ struct transport {
                       const char *executable, int fd[2]);
 
        /** get_refs_list(), fetch(), and push_refs() can keep
-        * resources (such as a connection) reserved for futher
+        * resources (such as a connection) reserved for further
         * use. disconnect() releases these resources.
         **/
        int (*disconnect)(struct transport *connection);
diff --git a/usage.c b/usage.c
index 40b3de51c7dfa3fdaaeb44e1c64a2208560414c5..ed146453cabeb9e82bef0c5610cda47d1b2a0b1c 100644 (file)
--- a/usage.c
+++ b/usage.c
@@ -6,8 +6,6 @@
 #include "git-compat-util.h"
 #include "cache.h"
 
-static int dying;
-
 void vreportf(const char *prefix, const char *err, va_list params)
 {
        char msg[4096];
@@ -49,12 +47,19 @@ static void warn_builtin(const char *warn, va_list params)
        vreportf("warning: ", warn, params);
 }
 
+static int die_is_recursing_builtin(void)
+{
+       static int dying;
+       return dying++;
+}
+
 /* If we are in a dlopen()ed .so write to a global variable would segfault
  * (ugh), so keep things static. */
 static NORETURN_PTR void (*usage_routine)(const char *err, va_list params) = usage_builtin;
 static NORETURN_PTR void (*die_routine)(const char *err, va_list params) = die_builtin;
 static void (*error_routine)(const char *err, va_list params) = error_builtin;
 static void (*warn_routine)(const char *err, va_list params) = warn_builtin;
+static int (*die_is_recursing)(void) = die_is_recursing_builtin;
 
 void set_die_routine(NORETURN_PTR void (*routine)(const char *err, va_list params))
 {
@@ -66,6 +71,11 @@ void set_error_routine(void (*routine)(const char *err, va_list params))
        error_routine = routine;
 }
 
+void set_die_is_recursing_routine(int (*routine)(void))
+{
+       die_is_recursing = routine;
+}
+
 void NORETURN usagef(const char *err, ...)
 {
        va_list params;
@@ -84,11 +94,10 @@ void NORETURN die(const char *err, ...)
 {
        va_list params;
 
-       if (dying) {
+       if (die_is_recursing()) {
                fputs("fatal: recursion detected in die handler\n", stderr);
                exit(128);
        }
-       dying = 1;
 
        va_start(params, err);
        die_routine(err, params);
@@ -102,12 +111,11 @@ void NORETURN die_errno(const char *fmt, ...)
        char str_error[256], *err;
        int i, j;
 
-       if (dying) {
+       if (die_is_recursing()) {
                fputs("fatal: recursion detected in die_errno handler\n",
                        stderr);
                exit(128);
        }
-       dying = 1;
 
        err = strerror(errno);
        for (i = j = 0; err[i] && j < sizeof(str_error) - 1; ) {
index cea8e55d8bc1d9117a6104c4181be9ff875c3ffa..ec5f27c5992e5fec5fb54384a04ffacf1745ce4a 100644 (file)
@@ -965,6 +965,25 @@ static void show_cherry_pick_in_progress(struct wt_status *s,
        wt_status_print_trailer(s);
 }
 
+static void show_revert_in_progress(struct wt_status *s,
+                                       struct wt_status_state *state,
+                                       const char *color)
+{
+       status_printf_ln(s, color, _("You are currently reverting commit %s."),
+                        find_unique_abbrev(state->revert_head_sha1, DEFAULT_ABBREV));
+       if (advice_status_hints) {
+               if (has_unmerged(s))
+                       status_printf_ln(s, color,
+                               _("  (fix conflicts and run \"git revert --continue\")"));
+               else
+                       status_printf_ln(s, color,
+                               _("  (all conflicts fixed: run \"git revert --continue\")"));
+               status_printf_ln(s, color,
+                       _("  (use \"git revert --abort\" to cancel the revert operation)"));
+       }
+       wt_status_print_trailer(s);
+}
+
 static void show_bisect_in_progress(struct wt_status *s,
                                struct wt_status_state *state,
                                const char *color)
@@ -1086,6 +1105,7 @@ void wt_status_get_state(struct wt_status_state *state,
                         int get_detached_from)
 {
        struct stat st;
+       unsigned char sha1[20];
 
        if (!stat(git_path("MERGE_HEAD"), &st)) {
                state->merge_in_progress = 1;
@@ -1113,6 +1133,11 @@ void wt_status_get_state(struct wt_status_state *state,
                state->bisect_in_progress = 1;
                state->branch = read_and_strip_branch("BISECT_START");
        }
+       if (!stat(git_path("REVERT_HEAD"), &st) &&
+           !get_sha1("REVERT_HEAD", sha1)) {
+               state->revert_in_progress = 1;
+               hashcpy(state->revert_head_sha1, sha1);
+       }
 
        if (get_detached_from)
                wt_status_get_detached_from(state);
@@ -1130,6 +1155,8 @@ static void wt_status_print_state(struct wt_status *s,
                show_rebase_in_progress(s, state, state_color);
        else if (state->cherry_pick_in_progress)
                show_cherry_pick_in_progress(s, state, state_color);
+       else if (state->revert_in_progress)
+               show_revert_in_progress(s, state, state_color);
        if (state->bisect_in_progress)
                show_bisect_in_progress(s, state, state_color);
 }
@@ -1198,14 +1225,10 @@ void wt_status_print(struct wt_status *s)
                if (advice_status_u_option && 2000 < s->untracked_in_ms) {
                        status_printf_ln(s, GIT_COLOR_NORMAL, "");
                        status_printf_ln(s, GIT_COLOR_NORMAL,
-                                _("It took %.2f seconds to enumerate untracked files."
-                                  "  'status -uno'"),
-                                s->untracked_in_ms / 1000.0);
-                       status_printf_ln(s, GIT_COLOR_NORMAL,
-                                _("may speed it up, but you have to be careful not"
-                                  " to forget to add"));
-                       status_printf_ln(s, GIT_COLOR_NORMAL,
-                                _("new files yourself (see 'git help status')."));
+                                        _("It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
+                                          "may speed it up, but you have to be careful not to forget to add\n"
+                                          "new files yourself (see 'git help status')."),
+                                        s->untracked_in_ms / 1000.0);
                }
        } else if (s->commitable)
                status_printf_ln(s, GIT_COLOR_NORMAL, _("Untracked files not listed%s"),
index be7a016173487780fdd4d37e24b4a47fcb766454..4121bc208db2fbe5e4eb00af10056a9d8c0bab40 100644 (file)
@@ -80,10 +80,12 @@ struct wt_status_state {
        int rebase_interactive_in_progress;
        int cherry_pick_in_progress;
        int bisect_in_progress;
+       int revert_in_progress;
        char *branch;
        char *onto;
        char *detached_from;
        unsigned char detached_sha1[20];
+       unsigned char revert_head_sha1[20];
 };
 
 void wt_status_prepare(struct wt_status *s);
index 1b7012a119ad3ea7e2ebe0aad80891529d4936da..b2eb6db2c851aea7eb08b17d802155876bef211c 100644 (file)
@@ -490,7 +490,7 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) {
 
                /*
                 * Try to move back the possibly merged group of changes, to match
-                * the recorded postion in the other file.
+                * the recorded position in the other file.
                 */
                while (ixref < ix) {
                        rchg[--ixs] = 1;
index bf99787c3e4c791426311495dda9d4da81cbb571..73210cb6f3fb5d1cb90b1c5959a5a90e058ea1f2 100644 (file)
@@ -55,7 +55,7 @@ struct histindex {
        struct record {
                unsigned int ptr, cnt;
                struct record *next;
-       } **records, /* an ocurrence */
+       } **records, /* an occurrence */
          **line_map; /* map of line to record chain */
        chastore_t rcha;
        unsigned int *next_ptrs;