Merge branch 'jc/mailinfo-RE' into maint
authorJunio C Hamano <gitster@pobox.com>
Thu, 20 Sep 2012 22:55:03 +0000 (15:55 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 20 Sep 2012 22:55:03 +0000 (15:55 -0700)
* jc/mailinfo-RE:
mailinfo: strip "RE: " prefix

127 files changed:
.gitignore
Documentation/Makefile
Documentation/RelNotes/1.7.11.6.txt
Documentation/RelNotes/1.7.11.7.txt [new file with mode: 0644]
Documentation/RelNotes/1.7.12.1.txt [new file with mode: 0644]
Documentation/asciidoc.conf
Documentation/config.txt
Documentation/git-checkout.txt
Documentation/git-config.txt
Documentation/git-credential-cache--daemon.txt
Documentation/git-credential-cache.txt
Documentation/git-credential-store.txt
Documentation/git-fast-import.txt
Documentation/git-filter-branch.txt
Documentation/git-log.txt
Documentation/git-ls-remote.txt
Documentation/git-remote.txt
Documentation/git-submodule.txt
Documentation/git.txt
Documentation/gitcli.txt
Documentation/pretty-formats.txt
Documentation/pretty-options.txt
Documentation/rev-list-options.txt
Documentation/revisions.txt
Documentation/technical/pack-protocol.txt
Documentation/user-manual.conf
GIT-VERSION-GEN
Makefile
RelNotes
attr.c
builtin.h
builtin/apply.c
builtin/blame.c
builtin/cat-file.c
builtin/check-attr.c
builtin/checkout.c
builtin/commit.c
builtin/config.c
builtin/diff.c
builtin/fetch-pack.c
builtin/for-each-ref.c
builtin/log.c
builtin/ls-remote.c
builtin/merge.c
builtin/prune.c
builtin/receive-pack.c
builtin/remote.c
builtin/rev-parse.c
builtin/revert.c
builtin/send-pack.c
cache.h
combine-diff.c
command-list.txt
compat/precompose_utf8.c
config.c
connect.c
contrib/completion/git-completion.bash
contrib/git-jump/git-jump
diff-lib.c
diff-no-index.c
diff.c
diff.h
diffcore-rename.c
diffcore.h
dir.c
fsck.c
git-compat-util.h
git-mergetool.sh
git-rebase--interactive.sh
git-send-email.perl
git-sh-setup.sh
git-stash.sh
git-submodule.sh
gitk-git/gitk
gitweb/gitweb.perl
http.c
http.h
ident.c
merge-recursive.c
notes-merge.c
patch-ids.c
read-cache.c
remote-curl.c
revision.c
revision.h
run-command.c
sequencer.c
setup.c
sha1_file.c
submodule.c
t/README
t/lib-httpd.sh
t/lib-httpd/apache.conf
t/perf/.gitignore
t/t0003-attributes.sh
t/t0050-filesystem.sh
t/t0070-fundamental.sh
t/t1450-fsck.sh
t/t1506-rev-parse-diagnosis.sh
t/t2107-update-index-basic.sh
t/t3401-rebase-partial.sh
t/t3508-cherry-pick-many-commits.sh
t/t3910-mac-os-precompose.sh
t/t4022-diff-rewrite.sh
t/t4054-diff-bogus-tree.sh [new file with mode: 0755]
t/t4103-apply-binary.sh
t/t4202-log.sh
t/t5400-send-pack.sh
t/t5505-remote.sh
t/t5540-http-push.sh
t/t5541-http-push.sh
t/t5550-http-fetch.sh
t/t5551-http-fetch.sh
t/t6300-for-each-ref.sh
t/t7007-show.sh
t/t7400-submodule-basic.sh
t/t7406-submodule-update.sh
t/t7610-mergetool.sh
t/t9001-send-email.sh
t/test-lib-functions.sh
t/test-lib.sh
test-regex.c [new file with mode: 0644]
tree-diff.c
upload-pack.c
version.c
version.h
wrapper.c
index bb5c91e712349686ccd008d9ccfd5fa8c2320834..68fe464090606b95b40b8b99e2454edb52862abe 100644 (file)
 /test-mktemp
 /test-parse-options
 /test-path-utils
+/test-regex
 /test-revision-walking
 /test-run-command
 /test-sha1
index 063fa696c9eff617e4fc6ad37f0b6e49d32d58f9..cf5916fe8b79e39eb57f97b36e82697694f41d7a 100644 (file)
@@ -344,4 +344,7 @@ require-htmlrepo::
 quick-install-html: require-htmlrepo
        '$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REPO) $(DESTDIR)$(htmldir)
 
+print-man1:
+       @for i in $(MAN1_TXT); do echo $$i; done
+
 .PHONY: FORCE
index e548a5982478771acca2c2d1872bf27dcd08f413..ba7d3c396653f8b6493e628dc87b5dcb2e655f97 100644 (file)
@@ -4,31 +4,81 @@ Git v1.7.11.6 Release Notes
 Fixes since v1.7.11.5
 ---------------------
 
-This is primarily documentation and low-impact code clarification.
-
- - "ciabot" script (in contrib/) has been updated with extensive
+ * "ciabot" script (in contrib/) has been updated with extensive
    documentation.
 
- - The "--rebase" option to "git pull" can be abbreviated to "-r",
-   but we didn't document it.
+ * "git foo" errored out with "Not a directory" when the user had a
+   non-directory on $PATH, and worse yet it masked an alias "foo" from
+   running.
 
- - It was generally understood that "--long-option"s to many of our
-   subcommands can be abbreviated to the unique prefix, but it was not
-   easy to find it described for new readers of the documentation set.
+ * When the user exports a non-default IFS without HT, scripts that
+   rely on being able to parse "ls-files -s | while read a b c..."
+   started to fail.  Protect them from such a misconfiguration.
 
- - The "--topo-order", "--date-order" (and the lack of either means
-   the default order) options to "rev-list" and "log" family of
-   commands were poorly described in the documentation.
+ * When the user gives an argument that can be taken as both a
+   revision name and a pathname without disambiguating with "--", we
+   used to give a help message "Use '--' to separate".  The message
+   has been clarified to show where that '--' goes on the command
+   line.
+
+ * Documentation for the configuration file format had a confusing
+   example.
 
- Older parts of the documentation described as if having a regular
* Older parts of the documentation described as if having a regular
    file in .git/refs/ hierarchy were the only way to have branches and
    tags, which is not true for quite some time.
 
- - A utility shell function test_seq has been added as a replacement
-   for the 'seq' utility found on some platforms.
+ * It was generally understood that "--long-option"s to many of our
+   subcommands can be abbreviated to the unique prefix, but it was not
+   easy to find it described for new readers of the documentation set.
 
- - Fallback 'getpass' implementation made unportable use of stdio API.
+ * The "--topo-order", "--date-order" (and the lack of either means
+   the default order) options to "rev-list" and "log" family of
+   commands were poorly described in the documentation.
 
- "git commit --amend" let the user edit the log message and then
* "git commit --amend" let the user edit the log message and then
    died when the human-readable committer name was given
    insufficiently by getpwent(3).
+
+ * The exit status code from "git config" was way overspecified while
+   being incorrect.  The implementation has been updated to give the
+   documented status for a case that was documented, and introduce a
+   new code for "all other errors".
+
+ * The output from "git diff -B" for a file that ends with an
+   incomplete line did not put "\ No newline..." on a line of its own.
+
+ * "git diff" had a confusion between taking data from a path in the
+   working tree and taking data from an object that happens to have
+   name 0{40} recorded in a tree.
+
+ * The "--rebase" option to "git pull" can be abbreviated to "-r",
+   but we didn't document it.
+
+ * When "git push" triggered the automatic gc on the receiving end, a
+   message from "git prune" that said it was removing cruft leaked to
+   the standard output, breaking the communication protocol.
+
+ * The reflog entries left by "git rebase" and "git rebase -i" were
+   inconsistent (the interactive one gave an abbreviated object name).
+
+ * "git send-email" did not unquote encoded words that appear on the
+   header correctly, and lost "_" from strings.
+
+ * "git stash apply/pop" did not trigger "rerere" upon conflicts
+   unlike other mergy operations.
+
+ * "git submodule <cmd> path" did not error out when the path to the
+   submodule was misspelt.
+
+ * "git submodule update -f" did not update paths in the working tree
+   that has local changes.
+   (merge 01d4721 sz/submodule-force-update later to maint).
+
+ * "gitweb" when used with PATH_INFO failed to notice directories with
+   SP (and other characters that need URL-style quoting) in them.
+
+ * Fallback 'getpass' implementation made unportable use of stdio API.
+
+ * A utility shell function test_seq has been added as a replacement
+   for the 'seq' utility found on some platforms.
diff --git a/Documentation/RelNotes/1.7.11.7.txt b/Documentation/RelNotes/1.7.11.7.txt
new file mode 100644 (file)
index 0000000..e7e79d9
--- /dev/null
@@ -0,0 +1,46 @@
+Git v1.7.11.7 Release Notes
+===========================
+
+Fixes since v1.7.11.6
+---------------------
+
+ * The synopsis said "checkout [-B branch]" to make it clear the
+   branch name is a parameter to the option, but the heading for the
+   option description was "-B::", not "-B branch::", making the
+   documentation misleading.
+
+ * Git ships with a fall-back regexp implementation for platforms with
+   buggy regexp library, but it was easy for people to keep using their
+   platform regexp.  A new test has been added to check this.
+
+ * "git apply -p0" did not parse pathnames on "diff --git" line
+   correctly.  This caused patches that had pathnames in no other
+   places to be mistakenly rejected (most notably, binary patch that
+   does not rename nor change mode).  Textual patches, renames or mode
+   changes have preimage and postimage pathnames in different places
+   in a form that can be parsed unambiguously and did not suffer from
+   this problem.
+
+ * After "gitk" showed the contents of a tag, neither "Reread
+   references" nor "Reload" did not update what is shown as the
+   contents of it, when the user overwrote the tag with "git tag -f".
+
+ * "git for-each-ref" did not currectly support more than one --sort
+   option.
+
+ * "git log .." errored out saying it is both rev range and a path
+   when there is no disambiguating "--" is on the command line.
+   Update the command line parser to interpret ".." as a path in such
+   a case.
+
+ * Pushing to smart HTTP server with recent Git fails without having
+   the username in the URL to force authentication, if the server is
+   configured to allow GET anonymously, while requiring authentication
+   for POST.
+
+ * "git show --format='%ci'" did not give timestamp correctly for
+   commits created without human readable name on "committer" line.
+   (merge e27ddb6 jc/maint-ident-missing-human-name later to maint).
+
+ * "git show --quiet" ought to be a synonym for "git show -s", but
+   wasn't.
diff --git a/Documentation/RelNotes/1.7.12.1.txt b/Documentation/RelNotes/1.7.12.1.txt
new file mode 100644 (file)
index 0000000..b8f04af
--- /dev/null
@@ -0,0 +1,134 @@
+Git 1.7.12.1 Release Notes
+==========================
+
+Fixes since v1.7.12
+-------------------
+
+ * "git apply -p0" did not parse pathnames on "diff --git" line
+   correctly.  This caused patches that had pathnames in no other
+   places to be mistakenly rejected (most notably, binary patch that
+   does not rename nor change mode).  Textual patches, renames or mode
+   changes have preimage and postimage pathnames in different places
+   in a form that can be parsed unambiguously and did not suffer from
+   this problem.
+
+ * "git cherry-pick A C B" used to replay changes in A and then B and
+   then C if these three commits had committer timestamps in that
+   order, which is not what the user who said "A C B" naturally
+   expects.
+
+ * "git commit --amend" let the user edit the log message and then
+   died when the human-readable committer name was given
+   insufficiently by getpwent(3).
+
+ * Some capabilities were asked by fetch-pack even when upload-pack
+   did not advertise that they are available.  fetch-pack has been
+   fixed not to do so.
+
+ * "git diff" had a confusion between taking data from a path in the
+   working tree and taking data from an object that happens to have
+   name 0{40} recorded in a tree.
+
+ * "git for-each-ref" did not correctly support more than one --sort
+   option.
+
+ * "git log .." errored out saying it is both rev range and a path
+   when there is no disambiguating "--" is on the command line.
+   Update the command line parser to interpret ".." as a path in such
+   a case.
+
+ * The "--topo-order", "--date-order" (and the lack of either means
+   the default order) options to "rev-list" and "log" family of
+   commands were poorly described in the documentation.
+
+ * "git prune" without "-v" used to warn about leftover temporary
+   files (which is an indication of an earlier aborted operation).
+
+ * Pushing to smart HTTP server with recent Git fails without having
+   the username in the URL to force authentication, if the server is
+   configured to allow GET anonymously, while requiring authentication
+   for POST.
+
+ * The reflog entries left by "git rebase" and "git rebase -i" were
+   inconsistent (the interactive one gave an abbreviated object name).
+
+ * When "git push" triggered the automatic gc on the receiving end, a
+   message from "git prune" that said it was removing cruft leaked to
+   the standard output, breaking the communication protocol.
+
+ * "git show --quiet" ought to be a synonym for "git show -s", but
+   wasn't.
+
+ * "git show --format='%ci'" did not give timestamp correctly for
+   commits created without human readable name on "committer" line.
+
+ * "git send-email" did not unquote encoded words that appear on the
+   header correctly, and lost "_" from strings.
+
+ * The interactive prompt "git send-email" gives was error prone. It
+   asked "What e-mail address do you want to use?" with the address it
+   guessed (correctly) the user would want to use in its prompt,
+   tempting the user to say "y". But the response was taken as "No,
+   please use 'y' as the e-mail address instead", which is most
+   certainly not what the user meant.
+
+ * "gitweb" when used with PATH_INFO failed to notice directories with
+   SP (and other characters that need URL-style quoting) in them.
+
+ * When the user gives an argument that can be taken as both a
+   revision name and a pathname without disambiguating with "--", we
+   used to give a help message "Use '--' to separate".  The message
+   has been clarified to show where that '--' goes on the command
+   line.
+
+ * When the user exports a non-default IFS without HT, scripts that
+   rely on being able to parse "ls-files -s | while read a b c..."
+   started to fail.  Protect them from such a misconfiguration.
+
+ * The attribute system may be asked for a path that itself or its
+   leading directories no longer exists in the working tree, and it is
+   fine if we cannot open .gitattribute file in such a case.  Failure
+   to open per-directory .gitattributes with error status other than
+   ENOENT and ENOTDIR should be diagnosed, but it wasn't.
+
+ * After "gitk" showed the contents of a tag, neither "Reread
+   references" nor "Reload" did not update what is shown as the
+   contents of it, when the user overwrote the tag with "git tag -f".
+
+ * "ciabot" script (in contrib/) has been updated with extensive
+   documentation.
+
+ * "git-jump" script (in contrib/) did not work well when
+   diff.noprefix or diff.mnemonicprefix is in effect.
+
+ * Older parts of the documentation described as if having a regular
+   file in .git/refs/ hierarchy were the only way to have branches and
+   tags, which is not true for quite some time.
+
+ * A utility shell function test_seq has been added as a replacement
+   for the 'seq' utility found on some platforms.
+
+ * Compatibility wrapper to learn the maximum number of file
+   descriptors we can open around sysconf(_SC_OPEN_MAX) and
+   getrlimit(RLIMIT_NO_FILE) has been introduced for portability.
+
+ * We used curl_easy_strerror() without checking version of cURL,
+   breaking the build for versions before curl 7.12.0.
+
+ * Code to work around MacOS X UTF-8 gotcha has been cleaned up.
+
+ * Fallback 'getpass' implementation made unportable use of stdio API.
+
+ * The "--rebase" option to "git pull" can be abbreviated to "-r",
+   but we didn't document it.
+
+ * It was generally understood that "--long-option"s to many of our
+   subcommands can be abbreviated to the unique prefix, but it was not
+   easy to find it described for new readers of the documentation set.
+
+ * The synopsis said "checkout [-B branch]" to make it clear the
+   branch name is a parameter to the option, but the heading for the
+   option description was "-B::", not "-B branch::", making the
+   documentation misleading.
+
+Also contains numerous documentation updates.
index a26d245ab46551b75ed3360a1d9fe33992a9cbd0..1273a85c8a45c225a24574937c35565774e87196 100644 (file)
@@ -36,7 +36,7 @@ ifndef::git-asciidoc-no-roff[]
 # v1.72 breaks with this because it replaces dots not in roff requests.
 [listingblock]
 <example><title>{title}</title>
-<literallayout>
+<literallayout class="monospaced">
 ifdef::doctype-manpage[]
 &#10;.ft C&#10;
 endif::doctype-manpage[]
@@ -53,7 +53,7 @@ ifdef::doctype-manpage[]
 # The following two small workarounds insert a simple paragraph after screen
 [listingblock]
 <example><title>{title}</title>
-<literallayout>
+<literallayout class="monospaced">
 |
 </literallayout><simpara></simpara>
 {title#}</example>
index a95e5a4ac9a7e35623ada63d7919b193d7f86a6e..122e3c49962481f46239950789a77da5f43a3a0f 100644 (file)
@@ -559,8 +559,9 @@ core.whitespace::
 * `space-before-tab` treats a space character that appears immediately
   before a tab character in the initial indent part of the line as an
   error (enabled by default).
-* `indent-with-non-tab` treats a line that is indented with 8 or more
-  space characters as an error (not enabled by default).
+* `indent-with-non-tab` treats a line that is indented with space
+  characters instead of the equivalent tabs as an error (not enabled by
+  default).
 * `tab-in-indent` treats a tab character in the initial indent part of
   the line as an error (not enabled by default).
 * `blank-at-eof` treats blank lines added at the end of file as an error
index 63a251612ab9a25b798c8cdbb3a69e8a76241e36..7958a4700642270ad3f801e314cf870331cf4512 100644 (file)
@@ -84,11 +84,11 @@ entries; instead, unmerged entries are ignored.
        When checking out paths from the index, check out stage #2
        ('ours') or #3 ('theirs') for unmerged paths.
 
--b::
+-b <new_branch>::
        Create a new branch named <new_branch> and start it at
        <start_point>; see linkgit:git-branch[1] for details.
 
--B::
+-B <new_branch>::
        Creates the branch <new_branch> and start it at <start_point>;
        if it already exists, then reset it to <start_point>. This is
        equivalent to running "git branch" with "-f"; see
@@ -124,7 +124,7 @@ explicitly give a name with '-b' in such a case.
        <commit> is not a branch name.  See the "DETACHED HEAD" section
        below for details.
 
---orphan::
+--orphan <new_branch>::
        Create a new 'orphan' branch, named <new_branch>, started from
        <start_point> and switch to it.  The first commit made on this
        new branch will have no parents and it will be the root of a new
@@ -367,6 +367,18 @@ $ git checkout hello.c            <3>
 <2> take a file out of another commit
 <3> restore hello.c from the index
 +
+If you want to check out _all_ C source files out of the index,
+you can say
++
+------------
+$ git checkout -- '*.c'
+------------
++
+Note the quotes around `*.c`.  The file `hello.c` will also be
+checked out, even though it is no longer in the working tree,
+because the file globbing is used to match entries in the index
+(not in the working tree by the shell).
++
 If you have an unfortunate branch that is named `hello.c`, this
 step would be confused as an instruction to switch to that branch.
 You should instead write:
index 2d6ef32a087f3f7355251a84a7d0d294f18479a5..eaea0791657386469e448def614b949c0a1f45e9 100644 (file)
@@ -54,16 +54,16 @@ configuration file by default, and options '--system', '--global',
 '--file <filename>' can be used to tell the command to write to
 that location (you can say '--local' but that is the default).
 
-This command will fail (with exit code ret) if:
+This command will fail with non-zero status upon error.  Some exit
+codes are:
 
 . The config file is invalid (ret=3),
 . can not write to the config file (ret=4),
 . no section or name was provided (ret=2),
 . the section or key is invalid (ret=1),
 . you try to unset an option which does not exist (ret=5),
-. you try to unset/set an option for which multiple lines match (ret=5),
-. you try to use an invalid regexp (ret=6), or
-. you use '--global' option without $HOME being properly set (ret=128).
+. you try to unset/set an option for which multiple lines match (ret=5), or
+. you try to use an invalid regexp (ret=6).
 
 On success, the command returns the exit code 0.
 
@@ -267,7 +267,7 @@ Given a .git/config like this:
 
        ; Proxy settings
        [core]
-               gitproxy="proxy-command" for kernel.org
+               gitproxy=proxy-command for kernel.org
                gitproxy=default-proxy ; for all the rest
 
 you can set the filemode to true with
@@ -342,7 +342,7 @@ To actually match only values with an exclamation mark, you have to
 To add a new proxy, without altering any of the existing ones, use
 
 ------------
-% git config core.gitproxy '"proxy-command" for example.com'
+% git config --add core.gitproxy '"proxy-command" for example.com'
 ------------
 
 An example to use customized color from the configuration in your
index 11edc5a173e89e80952a5663c3c197dee4c6329c..d15db42d43b9e94628246a30e7c12df41b45b935 100644 (file)
@@ -3,7 +3,7 @@ git-credential-cache--daemon(1)
 
 NAME
 ----
-git-credential-cache--daemon - temporarily store user credentials in memory
+git-credential-cache--daemon - Temporarily store user credentials in memory
 
 SYNOPSIS
 --------
index f3d09c5d51bc49d05c423de81504d68f18f99ede..eeff5fa9891fd7e3f1afac7cac6b9e5b17112449 100644 (file)
@@ -3,7 +3,7 @@ git-credential-cache(1)
 
 NAME
 ----
-git-credential-cache - helper to temporarily store passwords in memory
+git-credential-cache - Helper to temporarily store passwords in memory
 
 SYNOPSIS
 --------
index 31093467d1bc0af0f8229cd335ad0a56c4911b36..b27c03c361111a01dbc5c2407c209e5f8530eec2 100644 (file)
@@ -3,7 +3,7 @@ git-credential-store(1)
 
 NAME
 ----
-git-credential-store - helper to store credentials on disk
+git-credential-store - Helper to store credentials on disk
 
 SYNOPSIS
 --------
index 2620d28b4b38ed3f57ee426e27a2115db8160343..6603a7ab733f4c59dd8725ada536b44bf5e8d12a 100644 (file)
@@ -39,6 +39,10 @@ OPTIONS
        See ``Date Formats'' below for details about which formats
        are supported, and their syntax.
 
+-- done::
+       Terminate with error if there is no 'done' command at the
+       end of the stream.
+
 --force::
        Force updating modified existing branches, even if doing
        so would cause commits to be lost (as the new commit does
@@ -1047,7 +1051,9 @@ done::
        Error out if the stream ends without a 'done' command.
        Without this feature, errors causing the frontend to end
        abruptly at a convenient point in the stream can go
-       undetected.
+       undetected.  This may occur, for example, if an import
+       front end dies in mid-operation without emitting SIGTERM
+       or SIGKILL at its subordinate git fast-import instance.
 
 `option`
 ~~~~~~~~
index 15e7ac80c087eee7d0bf10af5653f421bcbee0dc..e2301f5c0106a35e5fa14d63944abeea2cb09e9b 100644 (file)
@@ -304,6 +304,11 @@ committed a merge between P1 and P2, it will be propagated properly
 and all children of the merge will become merge commits with P1,P2
 as their parents instead of the merge commit.
 
+*NOTE* the changes introduced by the commits, and which are not reverted
+by subsequent commits, will still be in the rewritten branch. If you want
+to throw out _changes_ together with the commits, you should use the
+interactive mode of 'git rebase'.
+
 You can rewrite the commit log messages using `--msg-filter`.  For
 example, 'git svn-id' strings in a repository created by 'git svn' can
 be removed this way:
@@ -314,11 +319,6 @@ git filter-branch --msg-filter '
 '
 -------------------------------------------------------
 
-To restrict rewriting to only part of the history, specify a revision
-range in addition to the new branch name.  The new branch name will
-point to the top-most revision that a 'git rev-list' of this range
-will print.
-
 If you need to add 'Acked-by' lines to, say, the last 10 commits (none
 of which is a merge), use this command:
 
@@ -329,11 +329,10 @@ git filter-branch --msg-filter '
 ' HEAD~10..HEAD
 --------------------------------------------------------
 
-*NOTE* the changes introduced by the commits, and which are not reverted
-by subsequent commits, will still be in the rewritten branch. If you want
-to throw out _changes_ together with the commits, you should use the
-interactive mode of 'git rebase'.
-
+To restrict rewriting to only part of the history, specify a revision
+range in addition to the new branch name.  The new branch name will
+point to the top-most revision that a 'git rev-list' of this range
+will print.
 
 Consider this history:
 
index 1f906208f9514180fe9f20293ab28ce8180b5357..585dac40baabbee291f43a6e7c59c36340286e43 100644 (file)
@@ -24,10 +24,6 @@ each commit introduces are shown.
 OPTIONS
 -------
 
--<n>::
-       Limits the number of commits to show.
-       Note that this is a commit limiting option, see below.
-
 <since>..<until>::
        Show only commits between the named two commits.  When
        either <since> or <until> is omitted, it defaults to
@@ -137,6 +133,8 @@ Examples
        This makes sense only when following a strict policy of merging all
        topic branches when staying on a single integration branch.
 
+`git log -3`::
+       Limits the number of commits to show to 3.
 
 Discussion
 ----------
index 7a9b86a58a1c00c08803e9ef40bb6a17146125a9..774de5e9d9fc2d4d88e4f820be177ea6c0a09360 100644 (file)
@@ -42,6 +42,11 @@ OPTIONS
        it successfully talked with the remote repository, whether it
        found any matching refs.
 
+--get-url::
+       Expand the URL of the given remote repository taking into account any
+       "url.<base>.insteadOf" config setting (See linkgit:git-config[1]) and
+       exit without talking to the remote.
+
 <repository>::
        Location of the repository.  The shorthand defined in
        $GIT_DIR/branches/ can be used. Use "." (dot) to list references in
index a308f4c79f1a879e124486ef6cffbb2e9f8e606c..e8c396b5f92903777ce5905cf52e2ef879850739 100644 (file)
@@ -12,7 +12,7 @@ SYNOPSIS
 'git remote' [-v | --verbose]
 'git remote add' [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <name> <url>
 'git remote rename' <old> <new>
-'git remote rm' <name>
+'git remote remove' <name>
 'git remote set-head' <name> (-a | -d | <branch>)
 'git remote set-branches' [--add] <name> <branch>...
 'git remote set-url' [--push] <name> <newurl> [<oldurl>]
@@ -85,6 +85,7 @@ In case <old> and <new> are the same, and <old> is a file under
 `$GIT_DIR/remotes` or `$GIT_DIR/branches`, the remote is converted to
 the configuration file format.
 
+'remove'::
 'rm'::
 
 Remove the remote named <name>. All remote-tracking branches and
index fbbbcb282cc8d6b2fd9c0ea8aea28d4a584646ea..2de7bf090094cd4a5c2d6697493040b445077bf7 100644 (file)
@@ -149,6 +149,11 @@ submodule with the `--init` option.
 +
 If `--recursive` is specified, this command will recurse into the
 registered submodules, and update any nested submodules within.
++
+If `--force` is specified, the submodule will be checked out (using
+`git checkout --force` if appropriate), even if the commit specified in the
+index of the containing repository already matches the commit checked out in
+the submodule.
 
 summary::
        Show commit summary between the given commit (defaults to HEAD) and
@@ -210,7 +215,9 @@ OPTIONS
        This option is only valid for add and update commands.
        When running add, allow adding an otherwise ignored submodule path.
        When running update, throw away local changes in submodules when
-       switching to a different commit.
+       switching to a different commit; and always run a checkout operation
+       in the submodule, even if the commit listed in the index of the
+       containing repository matches the commit checked out in the submodule.
 
 --cached::
        This option is only valid for status and summary commands.  These
index 27da0eb209446ea9d7c1b7705f64403f0013e49b..6710cb0a418fef503f0a8419e9b3cd617a15c485 100644 (file)
@@ -22,18 +22,17 @@ unusually rich command set that provides both high-level operations
 and full access to internals.
 
 See linkgit:gittutorial[7] to get started, then see
-link:everyday.html[Everyday Git] for a useful minimum set of commands, and
-"man git-commandname" for documentation of each command.  CVS users may
-also want to read linkgit:gitcvs-migration[7].  See
-the link:user-manual.html[Git User's Manual] for a more in-depth
-introduction.
+link:everyday.html[Everyday Git] for a useful minimum set of
+commands.  The link:user-manual.html[Git User's Manual] has a more
+in-depth introduction.
 
-The '<command>' is either a name of a Git command (see below) or an alias
-as defined in the configuration file (see linkgit:git-config[1]).
+After you mastered the basic concepts, you can come back to this
+page to learn what commands git offers.  You can learn more about
+individual git commands with "git help command".  linkgit:gitcli[7]
+manual page gives you an overview of the command line command syntax.
 
-Formatted and hyperlinked version of the latest git
-documentation can be viewed at
-`http://git-htmldocs.googlecode.com/git/git.html`.
+Formatted and hyperlinked version of the latest git documentation
+can be viewed at `http://git-htmldocs.googlecode.com/git/git.html`.
 
 ifdef::stalenotes[]
 [NOTE]
@@ -44,14 +43,17 @@ unreleased) version of git, that is available from 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v1.7.12/git.html[documentation for release 1.7.12]
+* link:v1.7.12.1/git.html[documentation for release 1.7.12.1]
 
 * release notes for
+  link:RelNotes/1.7.12.1.txt[1.7.12.1],
   link:RelNotes/1.7.12.txt[1.7.12].
 
-* link:v1.7.11.5/git.html[documentation for release 1.7.11.5]
+* link:v1.7.11.7/git.html[documentation for release 1.7.11.7]
 
 * release notes for
+  link:RelNotes/1.7.11.7.txt[1.7.11.7],
+  link:RelNotes/1.7.11.6.txt[1.7.11.6],
   link:RelNotes/1.7.11.5.txt[1.7.11.5],
   link:RelNotes/1.7.11.4.txt[1.7.11.4],
   link:RelNotes/1.7.11.3.txt[1.7.11.3],
@@ -411,24 +413,6 @@ help ...`.
        linkgit:git-replace[1] for more information.
 
 
-FURTHER DOCUMENTATION
----------------------
-
-See the references above to get started using git.  The following is
-probably more detail than necessary for a first-time user.
-
-The link:user-manual.html#git-concepts[git concepts chapter of the
-user-manual] and linkgit:gitcore-tutorial[7] both provide
-introductions to the underlying git architecture.
-
-See linkgit:gitworkflows[7] for an overview of recommended workflows.
-
-See also the link:howto-index.html[howto] documents for some useful
-examples.
-
-The internals are documented in the
-link:technical/api-index.html[GIT API documentation].
-
 GIT COMMANDS
 ------------
 
@@ -848,6 +832,29 @@ The index is also capable of storing multiple entries (called "stages")
 for a given pathname.  These stages are used to hold the various
 unmerged version of a file when a merge is in progress.
 
+FURTHER DOCUMENTATION
+---------------------
+
+See the references in the "description" section to get started
+using git.  The following is probably more detail than necessary
+for a first-time user.
+
+The link:user-manual.html#git-concepts[git concepts chapter of the
+user-manual] and linkgit:gitcore-tutorial[7] both provide
+introductions to the underlying git architecture.
+
+See linkgit:gitworkflows[7] for an overview of recommended workflows.
+
+See also the link:howto-index.html[howto] documents for some useful
+examples.
+
+The internals are documented in the
+link:technical/api-index.html[GIT API documentation].
+
+Users migrating from CVS may also want to
+read linkgit:gitcvs-migration[7].
+
+
 Authors
 -------
 Git was started by Linus Torvalds, and is currently maintained by Junio
index 3e72a5d68ea75f4e88ef6ec8cf5bd354f1094a5d..f6ba90c2da8f381bc714762f24bbfc33fa82b356 100644 (file)
@@ -37,11 +37,28 @@ arguments.  Here are the rules:
    file called HEAD in your work tree, `git diff HEAD` is ambiguous, and
    you have to say either `git diff HEAD --` or `git diff -- HEAD` to
    disambiguate.
-
++
 When writing a script that is expected to handle random user-input, it is
 a good practice to make it explicit which arguments are which by placing
 disambiguating `--` at appropriate places.
 
+ * Many commands allow wildcards in paths, but you need to protect
+   them from getting globbed by the shell.  These two mean different
+   things:
++
+--------------------------------
+$ git checkout -- *.c
+$ git checkout -- \*.c
+--------------------------------
++
+The former lets your shell expand the fileglob, and you are asking
+the dot-C files in your working tree to be overwritten with the version
+in the index.  The latter passes the `*.c` to Git, and you are asking
+the paths in the index that match the pattern to be checked out to your
+working tree.  After running `git add hello.c; rm hello.c`, you will _not_
+see `hello.c` in your working tree with the former, but with the latter
+you will.
+
 Here are the rules regarding the "flags" that you should follow when you are
 scripting git:
 
index e3d8a83b23aff51c8dd4281f18de8661514b62b1..d9eddedc72a5e6362d68df1b126b76804b9676e1 100644 (file)
@@ -130,6 +130,9 @@ The placeholders are:
 - '%b': body
 - '%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
+- '%GS': show the name of the signer for a signed commit
 - '%gD': reflog selector, e.g., `refs/stash@{1}`
 - '%gd': shortened reflog selector, e.g., `stash@{1}`
 - '%gn': reflog identity name
index 2a3dc8664f16957a05bc4d81824d7995517ac89c..5e499421a43526e133c7bd3be134da803b35c00d 100644 (file)
@@ -66,3 +66,7 @@ being displayed. Examples: "--notes=foo" will show only notes from
 --[no-]standard-notes::
        These options are deprecated. Use the above --notes/--no-notes
        options instead.
+
+--show-signature::
+       Check the validity of a signed commit object by passing the signature
+       to `gpg --verify` and show the output.
index def1340ac73cc3abab8084f14dfb8d54d2476177..918c1109f263c667264c9961c118d549795eab9d 100644 (file)
@@ -8,7 +8,8 @@ ordering and formatting options, such as '--reverse'.
 
 --
 
--n 'number'::
+-<number>::
+-n <number>::
 --max-count=<number>::
 
        Limit the number of commits to output.
@@ -636,10 +637,14 @@ These options are mostly targeted for packing of git repositories.
        Only useful with '--objects'; print the object IDs that are not
        in packs.
 
---no-walk::
+--no-walk[=(sorted|unsorted)]::
 
-       Only show the given revs, but do not traverse their ancestors.
-       This has no effect if a range is specified.
+       Only show the given commits, but do not traverse their ancestors.
+       This has no effect if a range is specified. If the argument
+       "unsorted" is given, the commits are show in the order they were
+       given on the command line. Otherwise (if "sorted" or no argument
+       was given), the commits are show in reverse chronological order
+       by commit time.
 
 --do-walk::
 
index dc0070bcb7ec2f4e6773066ffb745967d9df6fb3..69d996bc3899a89de49b0cbdf65f5b8ebd47d714 100644 (file)
@@ -213,6 +213,13 @@ of 'r1' and 'r2' and is defined as
 It is the set of commits that are reachable from either one of
 'r1' or 'r2' but not from both.
 
+In these two shorthands, you can omit one end and let it default to HEAD.
+For example, 'origin..' is a shorthand for 'origin..HEAD' and asks "What
+did I do since I forked from the origin branch?"  Similarly, '..origin'
+is a shorthand for 'HEAD..origin' and asks "What did the origin do since
+I forked from them?"  Note that '..' would mean 'HEAD..HEAD' which is an
+empty range that is both reachable and unreachable from HEAD.
+
 Two other shorthands for naming a set that is formed by a commit
 and its parent commits exist.  The 'r1{caret}@' notation means all
 parents of 'r1'.  'r1{caret}!' includes commit 'r1' but excludes
index 49cdc571cd7e276df2913b0ccf9d1e2320b31c9d..d51e20f3526e2681b8c05c296b91dd90a4d3e322 100644 (file)
@@ -259,8 +259,10 @@ a positive depth, this step is skipped.
 ----
 
 If the client has requested a positive depth, the server will compute
-the set of commits which are no deeper than the desired depth, starting
-at the client's wants. The server writes 'shallow' lines for each
+the set of commits which are no deeper than the desired depth. The set
+of commits start at the client's wants.
+
+The server writes 'shallow' lines for each
 commit whose parents will not be sent as a result. The server writes
 an 'unshallow' line for each commit which the client has indicated is
 shallow, but is no longer shallow at the currently requested depth
index 339b30919e6cd9791a5cc30b93395a88fb5e9d96..d87294de2f54c354c6215fb6029a182c966d6b2e 100644 (file)
@@ -14,7 +14,7 @@ ifdef::backend-docbook[]
 # "unbreak" docbook-xsl v1.68 for manpages. v1.69 works with or without this.
 [listingblock]
 <example><title>{title}</title>
-<literallayout>
+<literallayout class="monospaced">
 |
 </literallayout>
 {title#}</example>
index b27a2ff687183607854ed630519b30e4136d0b6c..c4220a09de9d3365a7d36a0ee85964c40f2d2c37 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v1.7.12
+DEF_VER=v1.7.12.1
 
 LF='
 '
index 6b0c961d3acd6eb476c979e51f32a258e15c743d..26b697d1756dac4f37e04b8857ca9ea15df7d18d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -496,6 +496,7 @@ TEST_PROGRAMS_NEED_X += test-mergesort
 TEST_PROGRAMS_NEED_X += test-mktemp
 TEST_PROGRAMS_NEED_X += test-parse-options
 TEST_PROGRAMS_NEED_X += test-path-utils
+TEST_PROGRAMS_NEED_X += test-regex
 TEST_PROGRAMS_NEED_X += test-revision-walking
 TEST_PROGRAMS_NEED_X += test-run-command
 TEST_PROGRAMS_NEED_X += test-scrap-cache-tree
@@ -2805,8 +2806,13 @@ endif
 
 ### Check documentation
 #
+ALL_COMMANDS = $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS)
+ALL_COMMANDS += git
+ALL_COMMANDS += gitk
+ALL_COMMANDS += gitweb
+ALL_COMMANDS += git-gui git-citool
 check-docs::
-       @(for v in $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git gitk; \
+       @(for v in $(ALL_COMMANDS); \
        do \
                case "$$v" in \
                git-merge-octopus | git-merge-ours | git-merge-recursive | \
@@ -2828,35 +2834,13 @@ check-docs::
                sed -e '/^#/d' \
                    -e 's/[     ].*//' \
                    -e 's/^/listed /' command-list.txt; \
-               ls -1 Documentation/git*txt | \
+               $(MAKE) -C Documentation print-man1 | \
+               grep '\.txt$$' | \
                sed -e 's|Documentation/|documented |' \
                    -e 's/\.txt//'; \
        ) | while read how cmd; \
        do \
-               case "$$how,$$cmd" in \
-               *,git-citool | \
-               *,git-gui | \
-               *,git-help | \
-               documented,gitattributes | \
-               documented,gitignore | \
-               documented,gitmodules | \
-               documented,gitcli | \
-               documented,git-tools | \
-               documented,gitcore-tutorial | \
-               documented,gitcvs-migration | \
-               documented,gitdiffcore | \
-               documented,gitglossary | \
-               documented,githooks | \
-               documented,gitrepository-layout | \
-               documented,gitrevisions | \
-               documented,gittutorial | \
-               documented,gittutorial-2 | \
-               documented,git-bisect-lk2009 | \
-               documented,git-remote-helpers | \
-               documented,gitworkflows | \
-               sentinel,not,matching,is,ok ) continue ;; \
-               esac; \
-               case " $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git gitk " in \
+               case " $(ALL_COMMANDS) " in \
                *" $$cmd "*)    ;; \
                *) echo "removed but $$how: $$cmd" ;; \
                esac; \
index 19bb2ebbe687d9ded1a5c82d28d4410de1e2f19f..53d76d1a47e0750b0d8b14287ff3d923ca55b438 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/1.7.12.txt
\ No newline at end of file
+Documentation/RelNotes/1.7.12.1.txt
\ No newline at end of file
diff --git a/attr.c b/attr.c
index b52efb55a036be10618d531d66697d7f7220c524..056d702f6e244e4188abc3c8dc4db647699ec4d1 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -352,8 +352,11 @@ static struct attr_stack *read_attr_from_file(const char *path, int macro_ok)
        char buf[2048];
        int lineno = 0;
 
-       if (!fp)
+       if (!fp) {
+               if (errno != ENOENT && errno != ENOTDIR)
+                       warn_on_inaccessible(path);
                return NULL;
+       }
        res = xcalloc(1, sizeof(*res));
        while (fgets(buf, sizeof(buf), fp))
                handle_attr_line(res, buf, path, ++lineno, macro_ok);
index ba6626b03505dd0622faea4e2bea51ed4b6720f5..8e377522fee4be94f9cdca40d44ecdcc18b42d8b 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -43,7 +43,7 @@ extern int check_pager_config(const char *cmd);
 struct diff_options;
 extern void setup_diff_pager(struct diff_options *);
 
-extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, char **buf, unsigned long *buf_size);
+extern int textconv_object(const char *path, unsigned mode, const unsigned char *sha1, int sha1_valid, char **buf, unsigned long *buf_size);
 
 extern int cmd_add(int argc, const char **argv, const char *prefix);
 extern int cmd_annotate(int argc, const char **argv, const char *prefix);
index d453c833782c6aae4dd04fb9f9f68c3a8211d3d5..ca8695ad31073618b286bc4a086b0b74083aaad7 100644 (file)
@@ -188,7 +188,6 @@ struct patch {
        int is_new, is_delete;  /* -1 = unknown, 0 = false, 1 = true */
        int rejected;
        unsigned ws_rule;
-       unsigned long deflate_origlen;
        int lines_added, lines_deleted;
        int score;
        unsigned int is_toplevel_relative:1;
@@ -1096,15 +1095,23 @@ static int gitdiff_unrecognized(const char *line, struct patch *patch)
        return -1;
 }
 
-static const char *stop_at_slash(const char *line, int llen)
+/*
+ * Skip p_value leading components from "line"; as we do not accept
+ * absolute paths, return NULL in that case.
+ */
+static const char *skip_tree_prefix(const char *line, int llen)
 {
-       int nslash = p_value;
+       int nslash;
        int i;
 
+       if (!p_value)
+               return (llen && line[0] == '/') ? NULL : line;
+
+       nslash = p_value;
        for (i = 0; i < llen; i++) {
                int ch = line[i];
                if (ch == '/' && --nslash <= 0)
-                       return &line[i];
+                       return (i == 0) ? NULL : &line[i + 1];
        }
        return NULL;
 }
@@ -1134,12 +1141,11 @@ static char *git_header_name(const char *line, int llen)
                if (unquote_c_style(&first, line, &second))
                        goto free_and_fail1;
 
-               /* advance to the first slash */
-               cp = stop_at_slash(first.buf, first.len);
-               /* we do not accept absolute paths */
-               if (!cp || cp == first.buf)
+               /* strip the a/b prefix including trailing slash */
+               cp = skip_tree_prefix(first.buf, first.len);
+               if (!cp)
                        goto free_and_fail1;
-               strbuf_remove(&first, 0, cp + 1 - first.buf);
+               strbuf_remove(&first, 0, cp - first.buf);
 
                /*
                 * second points at one past closing dq of name.
@@ -1153,22 +1159,21 @@ static char *git_header_name(const char *line, int llen)
                if (*second == '"') {
                        if (unquote_c_style(&sp, second, NULL))
                                goto free_and_fail1;
-                       cp = stop_at_slash(sp.buf, sp.len);
-                       if (!cp || cp == sp.buf)
+                       cp = skip_tree_prefix(sp.buf, sp.len);
+                       if (!cp)
                                goto free_and_fail1;
                        /* They must match, otherwise ignore */
-                       if (strcmp(cp + 1, first.buf))
+                       if (strcmp(cp, first.buf))
                                goto free_and_fail1;
                        strbuf_release(&sp);
                        return strbuf_detach(&first, NULL);
                }
 
                /* unquoted second */
-               cp = stop_at_slash(second, line + llen - second);
-               if (!cp || cp == second)
+               cp = skip_tree_prefix(second, line + llen - second);
+               if (!cp)
                        goto free_and_fail1;
-               cp++;
-               if (line + llen - cp != first.len + 1 ||
+               if (line + llen - cp != first.len ||
                    memcmp(first.buf, cp, first.len))
                        goto free_and_fail1;
                return strbuf_detach(&first, NULL);
@@ -1180,10 +1185,9 @@ static char *git_header_name(const char *line, int llen)
        }
 
        /* unquoted first name */
-       name = stop_at_slash(line, llen);
-       if (!name || name == line)
+       name = skip_tree_prefix(line, llen);
+       if (!name)
                return NULL;
-       name++;
 
        /*
         * since the first name is unquoted, a dq if exists must be
@@ -1197,10 +1201,9 @@ static char *git_header_name(const char *line, int llen)
                        if (unquote_c_style(&sp, second, NULL))
                                goto free_and_fail2;
 
-                       np = stop_at_slash(sp.buf, sp.len);
-                       if (!np || np == sp.buf)
+                       np = skip_tree_prefix(sp.buf, sp.len);
+                       if (!np)
                                goto free_and_fail2;
-                       np++;
 
                        len = sp.buf + sp.len - np;
                        if (len < second - name &&
@@ -1232,13 +1235,27 @@ static char *git_header_name(const char *line, int llen)
                case '\n':
                        return NULL;
                case '\t': case ' ':
-                       second = stop_at_slash(name + len, line_len - len);
+                       /*
+                        * Is this the separator between the preimage
+                        * and the postimage pathname?  Again, we are
+                        * only interested in the case where there is
+                        * no rename, as this is only to set def_name
+                        * and a rename patch has the names elsewhere
+                        * in an unambiguous form.
+                        */
+                       if (!name[len + 1])
+                               return NULL; /* no postimage name */
+                       second = skip_tree_prefix(name + len + 1,
+                                                 line_len - (len + 1));
                        if (!second)
                                return NULL;
-                       second++;
-                       if (second[len] == '\n' && !strncmp(name, second, len)) {
+                       /*
+                        * Does len bytes starting at "name" and "second"
+                        * (that are separated by one HT or SP we just
+                        * found) exactly match?
+                        */
+                       if (second[len] == '\n' && !strncmp(name, second, len))
                                return xmemdupz(name, len);
-                       }
                }
        }
 }
index 0d50273ce975d956cba3c17160bf3704b57f3f9c..ed5d01b36a309a53619c2615aed2382b2aebf056 100644 (file)
@@ -110,6 +110,7 @@ static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b, long ctxlen,
 int textconv_object(const char *path,
                    unsigned mode,
                    const unsigned char *sha1,
+                   int sha1_valid,
                    char **buf,
                    unsigned long *buf_size)
 {
@@ -117,7 +118,7 @@ int textconv_object(const char *path,
        struct userdiff_driver *textconv;
 
        df = alloc_filespec(path);
-       fill_filespec(df, sha1, mode);
+       fill_filespec(df, sha1, sha1_valid, mode);
        textconv = get_textconv(df);
        if (!textconv) {
                free_filespec(df);
@@ -142,7 +143,7 @@ static void fill_origin_blob(struct diff_options *opt,
 
                num_read_blob++;
                if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
-                   textconv_object(o->path, o->mode, o->blob_sha1, &file->ptr, &file_size))
+                   textconv_object(o->path, o->mode, o->blob_sha1, 1, &file->ptr, &file_size))
                        ;
                else
                        file->ptr = read_sha1_file(o->blob_sha1, &type, &file_size);
@@ -406,8 +407,7 @@ static struct origin *find_origin(struct scoreboard *sb,
        paths[1] = NULL;
 
        diff_tree_setup_paths(paths, &diff_opts);
-       if (diff_setup_done(&diff_opts) < 0)
-               die("diff-setup");
+       diff_setup_done(&diff_opts);
 
        if (is_null_sha1(origin->commit->object.sha1))
                do_diff_cache(parent->tree->object.sha1, &diff_opts);
@@ -493,8 +493,7 @@ static struct origin *find_rename(struct scoreboard *sb,
        diff_opts.single_follow = origin->path;
        paths[0] = NULL;
        diff_tree_setup_paths(paths, &diff_opts);
-       if (diff_setup_done(&diff_opts) < 0)
-               die("diff-setup");
+       diff_setup_done(&diff_opts);
 
        if (is_null_sha1(origin->commit->object.sha1))
                do_diff_cache(parent->tree->object.sha1, &diff_opts);
@@ -1074,8 +1073,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
 
        paths[0] = NULL;
        diff_tree_setup_paths(paths, &diff_opts);
-       if (diff_setup_done(&diff_opts) < 0)
-               die("diff-setup");
+       diff_setup_done(&diff_opts);
 
        /* Try "find copies harder" on new path if requested;
         * we do not want to use diffcore_rename() actually to
@@ -2123,7 +2121,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
                switch (st.st_mode & S_IFMT) {
                case S_IFREG:
                        if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
-                           textconv_object(read_from, mode, null_sha1, &buf_ptr, &buf_len))
+                           textconv_object(read_from, mode, null_sha1, 0, &buf_ptr, &buf_len))
                                strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1);
                        else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
                                die_errno("cannot open or read '%s'", read_from);
@@ -2516,7 +2514,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
                        die("no such path %s in %s", path, final_commit_name);
 
                if (DIFF_OPT_TST(&sb.revs->diffopt, ALLOW_TEXTCONV) &&
-                   textconv_object(path, o->mode, o->blob_sha1, (char **) &sb.final_buf,
+                   textconv_object(path, o->mode, o->blob_sha1, 1, (char **) &sb.final_buf,
                                    &sb.final_buf_size))
                        ;
                else
index af74e775a182bdf764436362cb37471e74930459..0eca2d7bd0e6d620edc70b4f643a8911efbbc8ae 100644 (file)
@@ -146,7 +146,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
                        die("git cat-file --textconv %s: <object> must be <sha1:path>",
                            obj_name);
 
-               if (!textconv_object(obj_context.path, obj_context.mode, sha1, &buf, &size))
+               if (!textconv_object(obj_context.path, obj_context.mode, sha1, 1, &buf, &size))
                        die("git cat-file --textconv: unable to run textconv on %s",
                            obj_name);
                break;
index 44c421eb0fe9cd8947d6666d15d790bc241ee7f3..9000c2db513aa20c16de7c891fd3549c6f49e398 100644 (file)
@@ -9,7 +9,7 @@ static int cached_attrs;
 static int stdin_paths;
 static const char * const check_attr_usage[] = {
 "git check-attr [-a | --all | attr...] [--] pathname...",
-"git check-attr --stdin [-a | --all | attr...] < <list-of-paths>",
+"git check-attr --stdin [-z] [-a | --all | attr...] < <list-of-paths>",
 NULL
 };
 
index d812219b30247795b6db7487329605a088057db1..7d922c612a9ef0784fa381c89899ba7a959338f2 100644 (file)
@@ -316,8 +316,7 @@ static void show_local_changes(struct object *head, struct diff_options *opts)
        init_revisions(&rev, NULL);
        rev.diffopt.flags = opts->flags;
        rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS;
-       if (diff_setup_done(&rev.diffopt) < 0)
-               die(_("diff_setup_done failed"));
+       diff_setup_done(&rev.diffopt);
        add_pending_object(&rev, head, NULL);
        run_diff_index(&rev, 0);
 }
index 20cef95d600aeb15b716793beb5fb2534cc2b682..62028e7b44b206e9722eef750be8c067aae31b32 100644 (file)
@@ -478,6 +478,20 @@ static void export_one(const char *var, const char *s, const char *e, int hack)
        strbuf_release(&buf);
 }
 
+static int sane_ident_split(struct ident_split *person)
+{
+       if (!person->name_begin || !person->name_end ||
+           person->name_begin == person->name_end)
+               return 0; /* no human readable name */
+       if (!person->mail_begin || !person->mail_end ||
+           person->mail_begin == person->mail_end)
+               return 0; /* no usable mail */
+       if (!person->date_begin || !person->date_end ||
+           !person->tz_begin || !person->tz_end)
+               return 0;
+       return 1;
+}
+
 static void determine_author_info(struct strbuf *author_ident)
 {
        char *name, *email, *date;
@@ -530,7 +544,8 @@ static void determine_author_info(struct strbuf *author_ident)
        if (force_date)
                date = force_date;
        strbuf_addstr(author_ident, fmt_ident(name, email, date, IDENT_STRICT));
-       if (!split_ident_line(&author, author_ident->buf, author_ident->len)) {
+       if (!split_ident_line(&author, author_ident->buf, author_ident->len) &&
+           sane_ident_split(&author)) {
                export_one("GIT_AUTHOR_NAME", author.name_begin, author.name_end, 0);
                export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0);
                export_one("GIT_AUTHOR_DATE", author.date_begin, author.tz_end, '@');
index 8cd08da99122bc79025d2a78204d316f1b7ba478..442ccc2497c4e2e889d9de55359e36a1db07c1a4 100644 (file)
@@ -160,7 +160,7 @@ static int show_config(const char *key_, const char *value_, void *cb)
 
 static int get_value(const char *key_, const char *regex_)
 {
-       int ret = -1;
+       int ret = CONFIG_GENERIC_ERROR;
        char *global = NULL, *xdg = NULL, *repo_config = NULL;
        const char *system_wide = NULL, *local;
        struct config_include_data inc = CONFIG_INCLUDE_INIT;
@@ -196,11 +196,14 @@ static int get_value(const char *key_, const char *regex_)
                if (regcomp(key_regexp, key, REG_EXTENDED)) {
                        fprintf(stderr, "Invalid key pattern: %s\n", key_);
                        free(key);
+                       ret = CONFIG_INVALID_PATTERN;
                        goto free_strings;
                }
        } else {
-               if (git_config_parse_key(key_, &key, NULL))
+               if (git_config_parse_key(key_, &key, NULL)) {
+                       ret = CONFIG_INVALID_KEY;
                        goto free_strings;
+               }
        }
 
        if (regex_) {
@@ -212,6 +215,7 @@ static int get_value(const char *key_, const char *regex_)
                regexp = (regex_t*)xmalloc(sizeof(regex_t));
                if (regcomp(regexp, regex_, REG_EXTENDED)) {
                        fprintf(stderr, "Invalid pattern: %s\n", regex_);
+                       ret = CONFIG_INVALID_PATTERN;
                        goto free_strings;
                }
        }
@@ -396,8 +400,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                         */
                        die("$HOME not set");
 
-               if (access(user_config, R_OK) &&
-                   xdg_config && !access(xdg_config, R_OK))
+               if (access_or_warn(user_config, R_OK) &&
+                   xdg_config && !access_or_warn(xdg_config, R_OK))
                        given_config_file = xdg_config;
                else
                        given_config_file = user_config;
index da8f6aac2bde9bb93cb059898a21c19c9bb27634..9650be2c50e6f79dbe033fae39f490d49c6318da 100644 (file)
@@ -29,6 +29,8 @@ static void stuff_change(struct diff_options *opt,
                         unsigned old_mode, unsigned new_mode,
                         const unsigned char *old_sha1,
                         const unsigned char *new_sha1,
+                        int old_sha1_valid,
+                        int new_sha1_valid,
                         const char *old_name,
                         const char *new_name)
 {
@@ -54,8 +56,8 @@ static void stuff_change(struct diff_options *opt,
 
        one = alloc_filespec(old_name);
        two = alloc_filespec(new_name);
-       fill_filespec(one, old_sha1, old_mode);
-       fill_filespec(two, new_sha1, new_mode);
+       fill_filespec(one, old_sha1, old_sha1_valid, old_mode);
+       fill_filespec(two, new_sha1, new_sha1_valid, new_mode);
 
        diff_queue(&diff_queued_diff, one, two);
 }
@@ -84,6 +86,7 @@ static int builtin_diff_b_f(struct rev_info *revs,
        stuff_change(&revs->diffopt,
                     blob[0].mode, canon_mode(st.st_mode),
                     blob[0].sha1, null_sha1,
+                    1, 0,
                     path, path);
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
@@ -108,6 +111,7 @@ static int builtin_diff_blobs(struct rev_info *revs,
        stuff_change(&revs->diffopt,
                     blob[0].mode, blob[1].mode,
                     blob[0].sha1, blob[1].sha1,
+                    1, 1,
                     blob[0].name, blob[1].name);
        diffcore_std(&revs->diffopt);
        diff_flush(&revs->diffopt);
@@ -298,8 +302,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
        argc = setup_revisions(argc, argv, &rev, NULL);
        if (!rev.diffopt.output_format) {
                rev.diffopt.output_format = DIFF_FORMAT_PATCH;
-               if (diff_setup_done(&rev.diffopt) < 0)
-                       die(_("diff_setup_done failed"));
+               diff_setup_done(&rev.diffopt);
        }
 
        DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
index 149db88726b8b5f924e6d136828008ec952bc88e..fdda36f1497eaa971e81cc1df0fb21ada6d21120 100644 (file)
@@ -10,6 +10,7 @@
 #include "remote.h"
 #include "run-command.h"
 #include "transport.h"
+#include "version.h"
 
 static int transfer_unpack_limit = -1;
 static int fetch_unpack_limit = -1;
@@ -18,6 +19,7 @@ static int prefer_ofs_delta = 1;
 static int no_done;
 static int fetch_fsck_objects = -1;
 static int transfer_fsck_objects = -1;
+static int agent_supported;
 static struct fetch_pack_args args = {
        /* .uploadpack = */ "git-upload-pack",
 };
@@ -327,6 +329,8 @@ static int find_common(int fd[2], unsigned char *result_sha1,
                        if (args.no_progress)   strbuf_addstr(&c, " no-progress");
                        if (args.include_tag)   strbuf_addstr(&c, " include-tag");
                        if (prefer_ofs_delta)   strbuf_addstr(&c, " ofs-delta");
+                       if (agent_supported)    strbuf_addf(&c, " agent=%s",
+                                                           git_user_agent_sanitized());
                        packet_buf_write(&req_buf, "want %s%s\n", remote_hex, c.buf);
                        strbuf_release(&c);
                } else
@@ -783,6 +787,8 @@ static struct ref *do_fetch_pack(int fd[2],
 {
        struct ref *ref = copy_ref_list(orig_ref);
        unsigned char sha1[20];
+       const char *agent_feature;
+       int agent_len;
 
        sort_ref_list(&ref, ref_compare_name);
 
@@ -814,11 +820,25 @@ static struct ref *do_fetch_pack(int fd[2],
                        fprintf(stderr, "Server supports side-band\n");
                use_sideband = 1;
        }
+       if (!server_supports("thin-pack"))
+               args.use_thin_pack = 0;
+       if (!server_supports("no-progress"))
+               args.no_progress = 0;
+       if (!server_supports("include-tag"))
+               args.include_tag = 0;
        if (server_supports("ofs-delta")) {
                if (args.verbose)
                        fprintf(stderr, "Server supports ofs-delta\n");
        } else
                prefer_ofs_delta = 0;
+
+       if ((agent_feature = server_feature_value("agent", &agent_len))) {
+               agent_supported = 1;
+               if (args.verbose && agent_len)
+                       fprintf(stderr, "Server version is %.*s\n",
+                               agent_len, agent_feature);
+       }
+
        if (everything_local(&ref, nr_match, match)) {
                packet_flush(fd[1]);
                goto all_done;
index b01d76a24323e86e9c9cbf1cd3adc9c0d1b2c6d8..0c5294e5e8fb92ca4757929a4bdf4bc49ca659bb 100644 (file)
@@ -962,7 +962,9 @@ static int opt_parse_sort(const struct option *opt, const char *arg, int unset)
        if (!arg) /* should --no-sort void the list ? */
                return -1;
 
-       *sort_tail = s = xcalloc(1, sizeof(*s));
+       s = xcalloc(1, sizeof(*s));
+       s->next = *sort_tail;
+       *sort_tail = s;
 
        if (*arg == '-') {
                s->reverse = 1;
index ecc2793690496531546765516d80032a1cbf8844..dff79212d0f6e027f3ec316a5892c80b6b55e7af 100644 (file)
@@ -109,9 +109,9 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
                             PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
                             PARSE_OPT_KEEP_DASHDASH);
 
-       argc = setup_revisions(argc, argv, rev, opt);
        if (quiet)
                rev->diffopt.output_format |= DIFF_FORMAT_NO_OUTPUT;
+       argc = setup_revisions(argc, argv, rev, opt);
 
        /* Any arguments at this point are not recognized */
        if (argc > 1)
@@ -456,7 +456,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)
        init_revisions(&rev, prefix);
        rev.diff = 1;
        rev.always_show_header = 1;
-       rev.no_walk = 1;
+       rev.no_walk = REVISION_WALK_NO_WALK_SORTED;
        rev.diffopt.stat_width = -1;    /* Scale to real terminal size */
 
        memset(&opt, 0, sizeof(opt));
index 41c88a98a2de1ce817351243f9aa9e2811604097..25e83cfe9de3dc3cee19f03f82b56396eb6b65de 100644 (file)
@@ -5,7 +5,7 @@
 
 static const char ls_remote_usage[] =
 "git ls-remote [--heads] [--tags]  [-u <exec> | --upload-pack <exec>]\n"
-"                     [-q|--quiet] [--exit-code] [<repository> [<refs>...]]";
+"                     [-q|--quiet] [--exit-code] [--get-url] [<repository> [<refs>...]]";
 
 /*
  * Is there one among the list of patterns that match the tail part
index dd50a0c57b4d73d03cc84afd90594a56616d4953..e81fde6d79e8896235c4a3901bc303f6094a9e55 100644 (file)
@@ -404,8 +404,7 @@ static void finish(struct commit *head_commit,
                opts.output_format |=
                        DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
                opts.detect_rename = DIFF_DETECT_RENAME;
-               if (diff_setup_done(&opts) < 0)
-                       die(_("diff_setup_done failed"));
+               diff_setup_done(&opts);
                diff_tree_sha1(head, new_head, "", &opts);
                diffcore_std(&opts);
                diff_flush(&opts);
index b99b635e44f6145395b5c761505099c0a0f5b6cc..6cb99443c1a1773b6a8207dfbcc6d1e053e70ce4 100644 (file)
@@ -25,7 +25,8 @@ static int prune_tmp_object(const char *path, const char *filename)
                return error("Could not stat '%s'", fullpath);
        if (st.st_mtime > expire)
                return 0;
-       printf("Removing stale temporary file %s\n", fullpath);
+       if (show_only || verbose)
+               printf("Removing stale temporary file %s\n", fullpath);
        if (!show_only)
                unlink_or_warn(fullpath);
        return 0;
index 0afb8b289621c419bd7472097335e4235da37d61..2cb854feb4b3a701201ef683c6644aaa852d50b5 100644 (file)
@@ -12,6 +12,7 @@
 #include "string-list.h"
 #include "sha1-array.h"
 #include "connected.h"
+#include "version.h"
 
 static const char receive_pack_usage[] = "git receive-pack <git-dir>";
 
@@ -121,10 +122,11 @@ static void show_ref(const char *path, const unsigned char *sha1)
        if (sent_capabilities)
                packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
        else
-               packet_write(1, "%s %s%c%s%s\n",
+               packet_write(1, "%s %s%c%s%s agent=%s\n",
                             sha1_to_hex(sha1), path, 0,
                             " report-status delete-refs side-band-64k quiet",
-                            prefer_ofs_delta ? " ofs-delta" : "");
+                            prefer_ofs_delta ? " ofs-delta" : "",
+                            git_user_agent_sanitized());
        sent_capabilities = 1;
 }
 
@@ -977,7 +979,8 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
                        const char *argv_gc_auto[] = {
                                "gc", "--auto", "--quiet", NULL,
                        };
-                       run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
+                       int opt = RUN_GIT_CMD | RUN_COMMAND_STDOUT_TO_STDERR;
+                       run_command_v_opt(argv_gc_auto, opt);
                }
                if (auto_update_server_info)
                        update_server_info(0);
index 920262d76ec9bdc40a8ad7703cf1eb972a40eb9e..357d59d66792308c4c4d767523767c6d078d7341 100644 (file)
@@ -11,7 +11,7 @@ static const char * const builtin_remote_usage[] = {
        "git remote [-v | --verbose]",
        "git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <name> <url>",
        "git remote rename <old> <new>",
-       "git remote rm <name>",
+       "git remote remove <name>",
        "git remote set-head <name> (-a | -d | <branch>)",
        "git remote [-v | --verbose] show [-n] <name>",
        "git remote prune [-n | --dry-run] <name>",
@@ -34,7 +34,7 @@ static const char * const builtin_remote_rename_usage[] = {
 };
 
 static const char * const builtin_remote_rm_usage[] = {
-       "git remote rm <name>",
+       "git remote remove <name>",
        NULL
 };
 
@@ -1580,7 +1580,7 @@ int cmd_remote(int argc, const char **argv, const char *prefix)
                result = add(argc, argv);
        else if (!strcmp(argv[0], "rename"))
                result = mv(argc, argv);
-       else if (!strcmp(argv[0], "rm"))
+       else if (!strcmp(argv[0], "rm") || !strcmp(argv[0], "remove"))
                result = rm(argc, argv);
        else if (!strcmp(argv[0], "set-head"))
                result = set_head(argc, argv);
index 32788a9f86427237d0f4838362c1e3bc722fa258..25e225f06717bfc2fd1f988269ff503a907d9302 100644 (file)
@@ -230,6 +230,7 @@ static int try_difference(const char *arg)
        const char *next;
        const char *this;
        int symmetric;
+       static const char head_by_default[] = "HEAD";
 
        if (!(dotdot = strstr(arg, "..")))
                return 0;
@@ -241,9 +242,20 @@ static int try_difference(const char *arg)
        next += symmetric;
 
        if (!*next)
-               next = "HEAD";
+               next = head_by_default;
        if (dotdot == arg)
-               this = "HEAD";
+               this = head_by_default;
+
+       if (this == head_by_default && next == head_by_default &&
+           !symmetric) {
+               /*
+                * Just ".."?  That is not a range but the
+                * pathspec for the parent directory.
+                */
+               *dotdot = '.';
+               return 0;
+       }
+
        if (!get_sha1_committish(this, sha1) && !get_sha1_committish(next, end)) {
                show_rev(NORMAL, end, next);
                show_rev(symmetric ? NORMAL : REVERSED, sha1, this);
index 82d1bf844b996d5d121169f244358964fd36fd19..98ad6410abb603cb8285f88df58ed0937ea64609 100644 (file)
@@ -193,7 +193,7 @@ static void parse_args(int argc, const char **argv, struct replay_opts *opts)
                struct setup_revision_opt s_r_opt;
                opts->revs = xmalloc(sizeof(*opts->revs));
                init_revisions(opts->revs, NULL);
-               opts->revs->no_walk = 1;
+               opts->revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED;
                if (argc < 2)
                        usage_with_options(usage_str, options);
                memset(&s_r_opt, 0, sizeof(s_r_opt));
index d5d7105ba2debde9fa6f2f33171d84cc7c25339a..7d05064218184b815fe01228a24138c1f9ac7c7f 100644 (file)
@@ -8,6 +8,7 @@
 #include "send-pack.h"
 #include "quote.h"
 #include "transport.h"
+#include "version.h"
 
 static const char send_pack_usage[] =
 "git send-pack [--all | --mirror] [--dry-run] [--force] [--receive-pack=<git-receive-pack>] [--verbose] [--thin] [<host>:]<directory> [<ref>...]\n"
@@ -251,6 +252,7 @@ int send_pack(struct send_pack_args *args,
        int status_report = 0;
        int use_sideband = 0;
        int quiet_supported = 0;
+       int agent_supported = 0;
        unsigned cmds_sent = 0;
        int ret;
        struct async demux;
@@ -266,6 +268,8 @@ int send_pack(struct send_pack_args *args,
                use_sideband = 1;
        if (server_supports("quiet"))
                quiet_supported = 1;
+       if (server_supports("agent"))
+               agent_supported = 1;
 
        if (!remote_refs) {
                fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
@@ -305,12 +309,17 @@ int send_pack(struct send_pack_args *args,
                        char *new_hex = sha1_to_hex(ref->new_sha1);
                        int quiet = quiet_supported && (args->quiet || !args->progress);
 
-                       if (!cmds_sent && (status_report || use_sideband || args->quiet)) {
-                               packet_buf_write(&req_buf, "%s %s %s%c%s%s%s",
+                       if (!cmds_sent && (status_report || use_sideband ||
+                                          quiet || agent_supported)) {
+                               packet_buf_write(&req_buf,
+                                                "%s %s %s%c%s%s%s%s%s",
                                                 old_hex, new_hex, ref->name, 0,
                                                 status_report ? " report-status" : "",
                                                 use_sideband ? " side-band-64k" : "",
-                                                quiet ? " quiet" : "");
+                                                quiet ? " quiet" : "",
+                                                agent_supported ? " agent=" : "",
+                                                agent_supported ? git_user_agent_sanitized() : ""
+                                               );
                        }
                        else
                                packet_buf_write(&req_buf, "%s %s %s",
diff --git a/cache.h b/cache.h
index 67f28b4da97b5aded337e1594043a73c075ea02f..eb4a0316d2d654160a51789dce5ad69fc9d1af45 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -1038,7 +1038,9 @@ struct extra_have_objects {
 };
 extern struct ref **get_remote_heads(int in, struct ref **list, unsigned int flags, struct extra_have_objects *);
 extern int server_supports(const char *feature);
-extern const char *parse_feature_request(const char *features, const char *feature);
+extern int parse_feature_request(const char *features, const char *feature);
+extern const char *server_feature_value(const char *feature, int *len_ret);
+extern const char *parse_feature_value(const char *feature_list, const char *feature, int *len_ret);
 
 extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
 
@@ -1108,6 +1110,7 @@ extern int update_server_info(int);
 #define CONFIG_NO_WRITE 4
 #define CONFIG_NOTHING_SET 5
 #define CONFIG_INVALID_PATTERN 6
+#define CONFIG_GENERIC_ERROR 7
 
 typedef int (*config_fn_t)(const char *, const char *, void *);
 extern int git_default_config(const char *, const char *, void *);
index 978668036835e16df4b6bfd37a7b1e9f8494cf07..bb1cc96c4e73c90ee327858aa3b36cf2bfe043a4 100644 (file)
@@ -111,7 +111,7 @@ static char *grab_blob(const unsigned char *sha1, unsigned int mode,
                return xcalloc(1, 1);
        } else if (textconv) {
                struct diff_filespec *df = alloc_filespec(path);
-               fill_filespec(df, sha1, mode);
+               fill_filespec(df, sha1, 1, mode);
                *size = fill_textconv(textconv, df, &blob);
                free_filespec(df);
        } else {
@@ -823,7 +823,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
                                                   &result_size, NULL, NULL);
                } else if (textconv) {
                        struct diff_filespec *df = alloc_filespec(elem->path);
-                       fill_filespec(df, null_sha1, st.st_mode);
+                       fill_filespec(df, null_sha1, 0, st.st_mode);
                        result_size = fill_textconv(textconv, df, &result);
                        free_filespec(df);
                } else if (0 <= (fd = open(elem->path, O_RDONLY))) {
index ec64cacf06d1cc7c0f2de4a12bb2b465f5351250..7e8cfec29d9e00cd6dfb26bca1f1295f64ae53fd 100644 (file)
@@ -26,6 +26,8 @@ git-commit-tree                         plumbingmanipulators
 git-config                              ancillarymanipulators
 git-count-objects                       ancillaryinterrogators
 git-credential                          purehelpers
+git-credential-cache                    purehelpers
+git-credential-store                    purehelpers
 git-cvsexportcommit                     foreignscminterface
 git-cvsimport                           foreignscminterface
 git-cvsserver                           foreignscminterface
@@ -114,6 +116,7 @@ git-show                                mainporcelain common
 git-show-branch                         ancillaryinterrogators
 git-show-index                          plumbinginterrogators
 git-show-ref                            plumbinginterrogators
+git-sh-i18n                             purehelpers
 git-sh-setup                            purehelpers
 git-stash                               mainporcelain
 git-status                              mainporcelain common
index d40d1b38076d690faaf7e77e590c0d6245ad1139..8cf59558e1c6fcc6782b8eaf94534ea041599191 100644 (file)
@@ -1,8 +1,7 @@
 /*
  * Converts filenames from decomposed unicode into precomposed unicode.
  * Used on MacOS X.
-*/
-
+ */
 
 #define PRECOMPOSE_UNICODE_C
 
 #include "precompose_utf8.h"
 
 typedef char *iconv_ibp;
-const static char *repo_encoding = "UTF-8";
-const static char *path_encoding = "UTF-8-MAC";
-
+static const char *repo_encoding = "UTF-8";
+static const char *path_encoding = "UTF-8-MAC";
 
-static size_t has_utf8(const char *s, size_t maxlen, size_t *strlen_c)
+static size_t has_non_ascii(const char *s, size_t maxlen, size_t *strlen_c)
 {
-       const uint8_t *utf8p = (const uint8_t*) s;
+       const uint8_t *ptr = (const uint8_t *)s;
        size_t strlen_chars = 0;
        size_t ret = 0;
 
-       if ((!utf8p) || (!*utf8p)) {
+       if (!ptr || !*ptr)
                return 0;
-       }
 
-       while((*utf8p) && maxlen) {
-               if (*utf8p & 0x80)
+       while (*ptr && maxlen) {
+               if (*ptr & 0x80)
                        ret++;
                strlen_chars++;
-               utf8p++;
+               ptr++;
                maxlen--;
        }
        if (strlen_c)
@@ -41,26 +38,24 @@ static size_t has_utf8(const char *s, size_t maxlen, size_t *strlen_c)
 
 void probe_utf8_pathname_composition(char *path, int len)
 {
-       const static char *auml_nfc = "\xc3\xa4";
-       const static char *auml_nfd = "\x61\xcc\x88";
+       static const char *auml_nfc = "\xc3\xa4";
+       static const char *auml_nfd = "\x61\xcc\x88";
        int output_fd;
        if (precomposed_unicode != -1)
                return; /* We found it defined in the global config, respect it */
-       path[len] = 0;
        strcpy(path + len, auml_nfc);
        output_fd = open(path, O_CREAT|O_EXCL|O_RDWR, 0600);
-       if (output_fd >=0) {
+       if (output_fd >= 0) {
                close(output_fd);
-               path[len] = 0;
                strcpy(path + len, auml_nfd);
                /* Indicate to the user, that we can configure it to true */
-               if (0 == access(path, R_OK))
+               if (!access(path, R_OK))
                        git_config_set("core.precomposeunicode", "false");
-                       /* To be backward compatible, set precomposed_unicode to 0 */
+               /* To be backward compatible, set precomposed_unicode to 0 */
                precomposed_unicode = 0;
-               path[len] = 0;
                strcpy(path + len, auml_nfc);
-               unlink(path);
+               if (unlink(path))
+                       die_errno(_("failed to unlink '%s'"), path);
        }
 }
 
@@ -82,7 +77,7 @@ void precompose_argv(int argc, const char **argv)
        while (i < argc) {
                size_t namelen;
                oldarg = argv[i];
-               if (has_utf8(oldarg, (size_t)-1, &namelen)) {
+               if (has_non_ascii(oldarg, (size_t)-1, &namelen)) {
                        newarg = reencode_string_iconv(oldarg, namelen, ic_precompose);
                        if (newarg)
                                argv[i] = newarg;
@@ -135,7 +130,7 @@ struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)
                prec_dir->dirent_nfc->d_ino  = res->d_ino;
                prec_dir->dirent_nfc->d_type = res->d_type;
 
-               if ((precomposed_unicode == 1) && has_utf8(res->d_name, (size_t)-1, NULL)) {
+               if ((precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) {
                        if (prec_dir->ic_precompose == (iconv_t)-1) {
                                die("iconv_open(%s,%s) failed, but needed:\n"
                                                "    precomposed unicode is not supported.\n"
@@ -160,8 +155,7 @@ struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)
                                        namelenz = 0; /* trigger strlcpy */
                                }
                        }
-               }
-               else
+               } else
                        namelenz = 0;
 
                if (!namelenz)
index 2b706ea2053714fdcec8997d978ce5688d072941..08e47e2e48a5bd310025752ee5ecdce81721b34d 100644 (file)
--- a/config.c
+++ b/config.c
@@ -60,7 +60,7 @@ static int handle_path_include(const char *path, struct config_include_data *inc
                path = buf.buf;
        }
 
-       if (!access(path, R_OK)) {
+       if (!access_or_warn(path, R_OK)) {
                if (++inc->depth > MAX_INCLUDE_DEPTH)
                        die(include_depth_advice, MAX_INCLUDE_DEPTH, path,
                            cf && cf->name ? cf->name : "the command line");
@@ -939,23 +939,23 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 
        home_config_paths(&user_config, &xdg_config, "config");
 
-       if (git_config_system() && !access(git_etc_gitconfig(), R_OK)) {
+       if (git_config_system() && !access_or_warn(git_etc_gitconfig(), R_OK)) {
                ret += git_config_from_file(fn, git_etc_gitconfig(),
                                            data);
                found += 1;
        }
 
-       if (xdg_config && !access(xdg_config, R_OK)) {
+       if (xdg_config && !access_or_warn(xdg_config, R_OK)) {
                ret += git_config_from_file(fn, xdg_config, data);
                found += 1;
        }
 
-       if (user_config && !access(user_config, R_OK)) {
+       if (user_config && !access_or_warn(user_config, R_OK)) {
                ret += git_config_from_file(fn, user_config, data);
                found += 1;
        }
 
-       if (repo_config && !access(repo_config, R_OK)) {
+       if (repo_config && !access_or_warn(repo_config, R_OK)) {
                ret += git_config_from_file(fn, repo_config, data);
                found += 1;
        }
index 55a85adea94c87c912280079ee13afd6926901aa..49e56ba35a645359b0d7c1f7bbc9e2108b3424d9 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -115,12 +115,7 @@ struct ref **get_remote_heads(int in, struct ref **list,
        return list;
 }
 
-int server_supports(const char *feature)
-{
-       return !!parse_feature_request(server_capabilities, feature);
-}
-
-const char *parse_feature_request(const char *feature_list, const char *feature)
+const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp)
 {
        int len;
 
@@ -132,14 +127,46 @@ const char *parse_feature_request(const char *feature_list, const char *feature)
                const char *found = strstr(feature_list, feature);
                if (!found)
                        return NULL;
-               if ((feature_list == found || isspace(found[-1])) &&
-                   (!found[len] || isspace(found[len]) || found[len] == '='))
-                       return found;
+               if (feature_list == found || isspace(found[-1])) {
+                       const char *value = found + len;
+                       /* feature with no value (e.g., "thin-pack") */
+                       if (!*value || isspace(*value)) {
+                               if (lenp)
+                                       *lenp = 0;
+                               return value;
+                       }
+                       /* feature with a value (e.g., "agent=git/1.2.3") */
+                       else if (*value == '=') {
+                               value++;
+                               if (lenp)
+                                       *lenp = strcspn(value, " \t\n");
+                               return value;
+                       }
+                       /*
+                        * otherwise we matched a substring of another feature;
+                        * keep looking
+                        */
+               }
                feature_list = found + 1;
        }
        return NULL;
 }
 
+int parse_feature_request(const char *feature_list, const char *feature)
+{
+       return !!parse_feature_value(feature_list, feature, NULL);
+}
+
+const char *server_feature_value(const char *feature, int *len)
+{
+       return parse_feature_value(server_capabilities, feature, len);
+}
+
+int server_supports(const char *feature)
+{
+       return !!server_feature_value(feature, NULL);
+}
+
 enum protocol {
        PROTO_LOCAL = 1,
        PROTO_SSH,
index ffedce751c80eac032843f6ecad50246cfc28035..3b982903491e01b8ca03c1e8f8943f5abc4dc553 100644 (file)
@@ -225,6 +225,13 @@ _get_comp_words_by_ref ()
 fi
 fi
 
+# Quotes the argument for shell reuse
+__git_quote()
+{
+       local quoted=${1//\'/\'\\\'\'}
+       printf "'%s'" "$quoted"
+}
+
 # Generates completion reply with compgen, appending a space to possible
 # completion words, if necessary.
 # It accepts 1 to 4 arguments:
@@ -261,7 +268,7 @@ __gitcomp ()
 __gitcomp_nl ()
 {
        local IFS=$'\n'
-       COMPREPLY=($(compgen -P "${2-}" -S "${4- }" -W "$1" -- "${3-$cur}"))
+       COMPREPLY=($(compgen -P "${2-}" -S "${4- }" -W "$(__git_quote "$1")" -- "${3-$cur}"))
 }
 
 __git_heads ()
@@ -1014,7 +1021,8 @@ _git_commit ()
        --*)
                __gitcomp "
                        --all --author= --signoff --verify --no-verify
-                       --edit --amend --include --only --interactive
+                       --edit --no-edit
+                       --amend --include --only --interactive
                        --dry-run --reuse-message= --reedit-message=
                        --reset-author --file= --message= --template=
                        --cleanup= --untracked-files --untracked-files=
@@ -2032,7 +2040,7 @@ _git_config ()
 
 _git_remote ()
 {
-       local subcommands="add rename rm set-head set-branches set-url show prune update"
+       local subcommands="add rename remove set-head set-branches set-url show prune update"
        local subcommand="$(__git_find_on_cmdline "$subcommands")"
        if [ -z "$subcommand" ]; then
                __gitcomp "$subcommands"
@@ -2040,7 +2048,7 @@ _git_remote ()
        fi
 
        case "$subcommand" in
-       rename|rm|set-url|show|prune)
+       rename|remove|set-url|show|prune)
                __gitcomp_nl "$(__git_remotes)"
                ;;
        set-head|set-branches)
index a33674e47a669e45f257a92aaffad8002d190c5d..dc90cd6379de4e9bf1eadc69560867601227b55d 100755 (executable)
@@ -21,9 +21,9 @@ open_editor() {
 }
 
 mode_diff() {
-       git diff --relative "$@" |
+       git diff --no-prefix --relative "$@" |
        perl -ne '
-       if (m{^\+\+\+ b/(.*)}) { $file = $1; next }
+       if (m{^\+\+\+ (.*)}) { $file = $1; next }
        defined($file) or next;
        if (m/^@@ .*\+(\d+)/) { $line = $1; next }
        defined($line) or next;
index fc0dff31b58c8bd6668de5c6396a93b31cc5729d..f35de0ffa0ec263acae7ac6211e3c2817987f760 100644 (file)
@@ -206,7 +206,8 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
                        if (silent_on_removed)
                                continue;
                        diff_addremove(&revs->diffopt, '-', ce->ce_mode,
-                                      ce->sha1, ce->name, 0);
+                                      ce->sha1, !is_null_sha1(ce->sha1),
+                                      ce->name, 0);
                        continue;
                }
                changed = match_stat_with_submodule(&revs->diffopt, ce, &st,
@@ -220,6 +221,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
                newmode = ce_mode_from_stat(ce, st.st_mode);
                diff_change(&revs->diffopt, oldmode, newmode,
                            ce->sha1, (changed ? null_sha1 : ce->sha1),
+                           !is_null_sha1(ce->sha1), (changed ? 0 : !is_null_sha1(ce->sha1)),
                            ce->name, 0, dirty_submodule);
 
        }
@@ -236,11 +238,12 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
 static void diff_index_show_file(struct rev_info *revs,
                                 const char *prefix,
                                 struct cache_entry *ce,
-                                const unsigned char *sha1, unsigned int mode,
+                                const unsigned char *sha1, int sha1_valid,
+                                unsigned int mode,
                                 unsigned dirty_submodule)
 {
        diff_addremove(&revs->diffopt, prefix[0], mode,
-                      sha1, ce->name, dirty_submodule);
+                      sha1, sha1_valid, ce->name, dirty_submodule);
 }
 
 static int get_stat_data(struct cache_entry *ce,
@@ -295,7 +298,7 @@ static void show_new_file(struct rev_info *revs,
            &dirty_submodule, &revs->diffopt) < 0)
                return;
 
-       diff_index_show_file(revs, "+", new, sha1, mode, dirty_submodule);
+       diff_index_show_file(revs, "+", new, sha1, !is_null_sha1(sha1), mode, dirty_submodule);
 }
 
 static int show_modified(struct rev_info *revs,
@@ -312,7 +315,7 @@ static int show_modified(struct rev_info *revs,
                          &dirty_submodule, &revs->diffopt) < 0) {
                if (report_missing)
                        diff_index_show_file(revs, "-", old,
-                                            old->sha1, old->ce_mode, 0);
+                                            old->sha1, 1, old->ce_mode, 0);
                return -1;
        }
 
@@ -347,7 +350,8 @@ static int show_modified(struct rev_info *revs,
                return 0;
 
        diff_change(&revs->diffopt, oldmode, mode,
-                   old->sha1, sha1, old->name, 0, dirty_submodule);
+                   old->sha1, sha1, 1, !is_null_sha1(sha1),
+                   old->name, 0, dirty_submodule);
        return 0;
 }
 
@@ -380,7 +384,7 @@ static void do_oneway_diff(struct unpack_trees_options *o,
                struct diff_filepair *pair;
                pair = diff_unmerge(&revs->diffopt, idx->name);
                if (tree)
-                       fill_filespec(pair->one, tree->sha1, tree->ce_mode);
+                       fill_filespec(pair->one, tree->sha1, 1, tree->ce_mode);
                return;
        }
 
@@ -396,7 +400,7 @@ static void do_oneway_diff(struct unpack_trees_options *o,
         * Something removed from the tree?
         */
        if (!idx) {
-               diff_index_show_file(revs, "-", tree, tree->sha1, tree->ce_mode, 0);
+               diff_index_show_file(revs, "-", tree, tree->sha1, 1, tree->ce_mode, 0);
                return;
        }
 
index 7d805a06afacae7eaa36a192e3a16406ef0fb41f..74da659368e4db67715a9c81dc7a5e0edcd3bcce 100644 (file)
@@ -82,7 +82,7 @@ static struct diff_filespec *noindex_filespec(const char *name, int mode)
        if (!name)
                name = "/dev/null";
        s = alloc_filespec(name);
-       fill_filespec(s, null_sha1, mode);
+       fill_filespec(s, null_sha1, 0, mode);
        if (name == file_from_standard_input)
                populate_from_stdin(s);
        return s;
@@ -258,8 +258,7 @@ void diff_no_index(struct rev_info *revs,
        DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
 
        revs->max_count = -2;
-       if (diff_setup_done(&revs->diffopt) < 0)
-               die("diff_setup_done failed");
+       diff_setup_done(&revs->diffopt);
 
        setup_diff_pager(&revs->diffopt);
        DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
diff --git a/diff.c b/diff.c
index 95706a5b4098afc8f20fe53425ff760c996a3b4e..e6846ca7507aa8a423c5e1f89390fa37723248ff 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -574,6 +574,7 @@ static void emit_rewrite_lines(struct emit_callback *ecb,
        if (!endp) {
                const char *plain = diff_get_color(ecb->color_diff,
                                                   DIFF_PLAIN);
+               putc('\n', ecb->opt->file);
                emit_line_0(ecb->opt, plain, reset, '\\',
                            nneof, strlen(nneof));
        }
@@ -2541,12 +2542,12 @@ void free_filespec(struct diff_filespec *spec)
 }
 
 void fill_filespec(struct diff_filespec *spec, const unsigned char *sha1,
-                  unsigned short mode)
+                  int sha1_valid, unsigned short mode)
 {
        if (mode) {
                spec->mode = canon_mode(mode);
                hashcpy(spec->sha1, sha1);
-               spec->sha1_valid = !is_null_sha1(sha1);
+               spec->sha1_valid = sha1_valid;
        }
 }
 
@@ -3187,7 +3188,7 @@ void diff_setup(struct diff_options *options)
        }
 }
 
-int diff_setup_done(struct diff_options *options)
+void diff_setup_done(struct diff_options *options)
 {
        int count = 0;
 
@@ -3286,8 +3287,6 @@ int diff_setup_done(struct diff_options *options)
                options->output_format = DIFF_FORMAT_NO_OUTPUT;
                DIFF_OPT_SET(options, EXIT_WITH_STATUS);
        }
-
-       return 0;
 }
 
 static int opt_arg(const char *arg, int arg_short, const char *arg_long, int *val)
@@ -4693,6 +4692,7 @@ static int is_submodule_ignored(const char *path, struct diff_options *options)
 void diff_addremove(struct diff_options *options,
                    int addremove, unsigned mode,
                    const unsigned char *sha1,
+                   int sha1_valid,
                    const char *concatpath, unsigned dirty_submodule)
 {
        struct diff_filespec *one, *two;
@@ -4724,9 +4724,9 @@ void diff_addremove(struct diff_options *options,
        two = alloc_filespec(concatpath);
 
        if (addremove != '+')
-               fill_filespec(one, sha1, mode);
+               fill_filespec(one, sha1, sha1_valid, mode);
        if (addremove != '-') {
-               fill_filespec(two, sha1, mode);
+               fill_filespec(two, sha1, sha1_valid, mode);
                two->dirty_submodule = dirty_submodule;
        }
 
@@ -4739,6 +4739,7 @@ void diff_change(struct diff_options *options,
                 unsigned old_mode, unsigned new_mode,
                 const unsigned char *old_sha1,
                 const unsigned char *new_sha1,
+                int old_sha1_valid, int new_sha1_valid,
                 const char *concatpath,
                 unsigned old_dirty_submodule, unsigned new_dirty_submodule)
 {
@@ -4753,6 +4754,8 @@ void diff_change(struct diff_options *options,
                const unsigned char *tmp_c;
                tmp = old_mode; old_mode = new_mode; new_mode = tmp;
                tmp_c = old_sha1; old_sha1 = new_sha1; new_sha1 = tmp_c;
+               tmp = old_sha1_valid; old_sha1_valid = new_sha1_valid;
+                       new_sha1_valid = tmp;
                tmp = old_dirty_submodule; old_dirty_submodule = new_dirty_submodule;
                        new_dirty_submodule = tmp;
        }
@@ -4763,8 +4766,8 @@ void diff_change(struct diff_options *options,
 
        one = alloc_filespec(concatpath);
        two = alloc_filespec(concatpath);
-       fill_filespec(one, old_sha1, old_mode);
-       fill_filespec(two, new_sha1, new_mode);
+       fill_filespec(one, old_sha1, old_sha1_valid, old_mode);
+       fill_filespec(two, new_sha1, new_sha1_valid, new_mode);
        one->dirty_submodule = old_dirty_submodule;
        two->dirty_submodule = new_dirty_submodule;
 
diff --git a/diff.h b/diff.h
index e027650cb0ff2651e2e890e7f00753c15f5b3cff..e25addb806a190f138a14ca64190fa5d2f311aaa 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -19,12 +19,14 @@ typedef void (*change_fn_t)(struct diff_options *options,
                 unsigned old_mode, unsigned new_mode,
                 const unsigned char *old_sha1,
                 const unsigned char *new_sha1,
+                int old_sha1_valid, int new_sha1_valid,
                 const char *fullpath,
                 unsigned old_dirty_submodule, unsigned new_dirty_submodule);
 
 typedef void (*add_remove_fn_t)(struct diff_options *options,
                    int addremove, unsigned mode,
                    const unsigned char *sha1,
+                   int sha1_valid,
                    const char *fullpath, unsigned dirty_submodule);
 
 typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
@@ -214,12 +216,15 @@ extern void diff_addremove(struct diff_options *,
                           int addremove,
                           unsigned mode,
                           const unsigned char *sha1,
+                          int sha1_valid,
                           const char *fullpath, unsigned dirty_submodule);
 
 extern void diff_change(struct diff_options *,
                        unsigned mode1, unsigned mode2,
                        const unsigned char *sha1,
                        const unsigned char *sha2,
+                       int sha1_valid,
+                       int sha2_valid,
                        const char *fullpath,
                        unsigned dirty_submodule1, unsigned dirty_submodule2);
 
@@ -241,7 +246,7 @@ extern int git_diff_ui_config(const char *var, const char *value, void *cb);
 extern int diff_use_color_default;
 extern void diff_setup(struct diff_options *);
 extern int diff_opt_parse(struct diff_options *, const char **, int);
-extern int diff_setup_done(struct diff_options *);
+extern void diff_setup_done(struct diff_options *);
 
 #define DIFF_DETECT_RENAME     1
 #define DIFF_DETECT_COPY       2
index 216a7a4bbcab189b5c3d1b7f58728b94b8d6aec8..512d0ac5fd2bc0acfb57147a6eb77f61f92b7c7e 100644 (file)
@@ -48,7 +48,7 @@ static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two,
                memmove(rename_dst + first + 1, rename_dst + first,
                        (rename_dst_nr - first - 1) * sizeof(*rename_dst));
        rename_dst[first].two = alloc_filespec(two->path);
-       fill_filespec(rename_dst[first].two, two->sha1, two->mode);
+       fill_filespec(rename_dst[first].two, two->sha1, two->sha1_valid, two->mode);
        rename_dst[first].pair = NULL;
        return &(rename_dst[first]);
 }
index be0739c5c401c059a0d3030acbc99a7744f17065..1c16c8595b21c2712259041c01d4b58d76a60222 100644 (file)
@@ -55,7 +55,7 @@ struct diff_filespec {
 extern struct diff_filespec *alloc_filespec(const char *);
 extern void free_filespec(struct diff_filespec *);
 extern void fill_filespec(struct diff_filespec *, const unsigned char *,
-                         unsigned short);
+                         int, unsigned short);
 
 extern int diff_populate_filespec(struct diff_filespec *, int);
 extern void diff_free_filespec_data(struct diff_filespec *);
diff --git a/dir.c b/dir.c
index 240bf0c49c9654b7cef56959786613e17113c3a0..486833986ed4b4e7d05d2086d53b15ec63905dd0 100644 (file)
--- a/dir.c
+++ b/dir.c
@@ -397,6 +397,8 @@ int add_excludes_from_file_to_list(const char *fname,
 
        fd = open(fname, O_RDONLY);
        if (fd < 0 || fstat(fd, &st) < 0) {
+               if (errno != ENOENT)
+                       warn_on_inaccessible(fname);
                if (0 <= fd)
                        close(fd);
                if (!check_index ||
@@ -1311,9 +1313,9 @@ void setup_standard_excludes(struct dir_struct *dir)
                home_config_paths(NULL, &xdg_path, "ignore");
                excludes_file = xdg_path;
        }
-       if (!access(path, R_OK))
+       if (!access_or_warn(path, R_OK))
                add_excludes_from_file(dir, path);
-       if (excludes_file && !access(excludes_file, R_OK))
+       if (excludes_file && !access_or_warn(excludes_file, R_OK))
                add_excludes_from_file(dir, excludes_file);
 }
 
diff --git a/fsck.c b/fsck.c
index 4c63b2cc41eec4f568ee6f0d18a51c97304d5d96..7395ef6a425f5c7725767f34a0383f61907fce93 100644 (file)
--- a/fsck.c
+++ b/fsck.c
@@ -139,6 +139,7 @@ static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, con
 static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
 {
        int retval;
+       int has_null_sha1 = 0;
        int has_full_path = 0;
        int has_empty_name = 0;
        int has_zero_pad = 0;
@@ -157,9 +158,12 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
        while (desc.size) {
                unsigned mode;
                const char *name;
+               const unsigned char *sha1;
 
-               tree_entry_extract(&desc, &name, &mode);
+               sha1 = tree_entry_extract(&desc, &name, &mode);
 
+               if (is_null_sha1(sha1))
+                       has_null_sha1 = 1;
                if (strchr(name, '/'))
                        has_full_path = 1;
                if (!*name)
@@ -207,6 +211,8 @@ static int fsck_tree(struct tree *item, int strict, fsck_error error_func)
        }
 
        retval = 0;
+       if (has_null_sha1)
+               retval += error_func(&item->object, FSCK_WARN, "contains entries pointing to null sha1");
        if (has_full_path)
                retval += error_func(&item->object, FSCK_WARN, "contains full pathnames");
        if (has_empty_name)
index 35b095e8ae989ae02228f814528b43d5bd026aab..000042d79352b4a7bb789d60e5324af92f29871a 100644 (file)
@@ -604,6 +604,12 @@ int rmdir_or_warn(const char *path);
  */
 int remove_or_warn(unsigned int mode, const char *path);
 
+/* Call access(2), but warn for any error besides ENOENT. */
+int access_or_warn(const char *path, int mode);
+
+/* Warn on an inaccessible file that ought to be accessible */
+void warn_on_inaccessible(const char *path);
+
 /* Get the passwd entry for the UID of the current process. */
 struct passwd *xgetpwuid_self(void);
 
index 0db0c44845f54920e26d97391f577e76305ecc56..c50e18a8998c1f4ca1449e1733f76cb769f501b9 100755 (executable)
@@ -18,270 +18,301 @@ require_work_tree
 
 # Returns true if the mode reflects a symlink
 is_symlink () {
-    test "$1" = 120000
+       test "$1" = 120000
 }
 
 is_submodule () {
-    test "$1" = 160000
+       test "$1" = 160000
 }
 
 local_present () {
-    test -n "$local_mode"
+       test -n "$local_mode"
 }
 
 remote_present () {
-    test -n "$remote_mode"
+       test -n "$remote_mode"
 }
 
 base_present () {
-    test -n "$base_mode"
+       test -n "$base_mode"
 }
 
 cleanup_temp_files () {
-    if test "$1" = --save-backup ; then
-       rm -rf -- "$MERGED.orig"
-       test -e "$BACKUP" && mv -- "$BACKUP" "$MERGED.orig"
-       rm -f -- "$LOCAL" "$REMOTE" "$BASE"
-    else
-       rm -f -- "$LOCAL" "$REMOTE" "$BASE" "$BACKUP"
-    fi
+       if test "$1" = --save-backup
+       then
+               rm -rf -- "$MERGED.orig"
+               test -e "$BACKUP" && mv -- "$BACKUP" "$MERGED.orig"
+               rm -f -- "$LOCAL" "$REMOTE" "$BASE"
+       else
+               rm -f -- "$LOCAL" "$REMOTE" "$BASE" "$BACKUP"
+       fi
 }
 
 describe_file () {
-    mode="$1"
-    branch="$2"
-    file="$3"
-
-    printf "  {%s}: " "$branch"
-    if test -z "$mode"; then
-       echo "deleted"
-    elif is_symlink "$mode" ; then
-       echo "a symbolic link -> '$(cat "$file")'"
-    elif is_submodule "$mode" ; then
-       echo "submodule commit $file"
-    else
-       if base_present; then
-           echo "modified file"
+       mode="$1"
+       branch="$2"
+       file="$3"
+
+       printf "  {%s}: " "$branch"
+       if test -z "$mode"
+       then
+               echo "deleted"
+       elif is_symlink "$mode"
+       then
+               echo "a symbolic link -> '$(cat "$file")'"
+       elif is_submodule "$mode"
+       then
+               echo "submodule commit $file"
+       elif base_present
+       then
+               echo "modified file"
        else
-           echo "created file"
+               echo "created file"
        fi
-    fi
 }
 
-
 resolve_symlink_merge () {
-    while true; do
-       printf "Use (l)ocal or (r)emote, or (a)bort? "
-       read ans || return 1
-       case "$ans" in
-           [lL]*)
-               git checkout-index -f --stage=2 -- "$MERGED"
-               git add -- "$MERGED"
-               cleanup_temp_files --save-backup
-               return 0
-               ;;
-           [rR]*)
-               git checkout-index -f --stage=3 -- "$MERGED"
-               git add -- "$MERGED"
-               cleanup_temp_files --save-backup
-               return 0
-               ;;
-           [aA]*)
-               return 1
-               ;;
-           esac
+       while true
+       do
+               printf "Use (l)ocal or (r)emote, or (a)bort? "
+               read ans || return 1
+               case "$ans" in
+               [lL]*)
+                       git checkout-index -f --stage=2 -- "$MERGED"
+                       git add -- "$MERGED"
+                       cleanup_temp_files --save-backup
+                       return 0
+                       ;;
+               [rR]*)
+                       git checkout-index -f --stage=3 -- "$MERGED"
+                       git add -- "$MERGED"
+                       cleanup_temp_files --save-backup
+                       return 0
+                       ;;
+               [aA]*)
+                       return 1
+                       ;;
+               esac
        done
 }
 
 resolve_deleted_merge () {
-    while true; do
-       if base_present; then
-           printf "Use (m)odified or (d)eleted file, or (a)bort? "
-       else
-           printf "Use (c)reated or (d)eleted file, or (a)bort? "
-       fi
-       read ans || return 1
-       case "$ans" in
-           [mMcC]*)
-               git add -- "$MERGED"
-               cleanup_temp_files --save-backup
-               return 0
-               ;;
-           [dD]*)
-               git rm -- "$MERGED" > /dev/null
-               cleanup_temp_files
-               return 0
-               ;;
-           [aA]*)
-               return 1
-               ;;
-           esac
+       while true
+       do
+               if base_present
+               then
+                       printf "Use (m)odified or (d)eleted file, or (a)bort? "
+               else
+                       printf "Use (c)reated or (d)eleted file, or (a)bort? "
+               fi
+               read ans || return 1
+               case "$ans" in
+               [mMcC]*)
+                       git add -- "$MERGED"
+                       cleanup_temp_files --save-backup
+                       return 0
+                       ;;
+               [dD]*)
+                       git rm -- "$MERGED" > /dev/null
+                       cleanup_temp_files
+                       return 0
+                       ;;
+               [aA]*)
+                       return 1
+                       ;;
+               esac
        done
 }
 
 resolve_submodule_merge () {
-    while true; do
-       printf "Use (l)ocal or (r)emote, or (a)bort? "
-       read ans || return 1
-       case "$ans" in
-           [lL]*)
-               if ! local_present; then
-                   if test -n "$(git ls-tree HEAD -- "$MERGED")"; then
-                       # Local isn't present, but it's a subdirectory
-                       git ls-tree --full-name -r HEAD -- "$MERGED" | git update-index --index-info || exit $?
-                   else
-                       test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
-                       git update-index --force-remove "$MERGED"
+       while true
+       do
+               printf "Use (l)ocal or (r)emote, or (a)bort? "
+               read ans || return 1
+               case "$ans" in
+               [lL]*)
+                       if ! local_present
+                       then
+                               if test -n "$(git ls-tree HEAD -- "$MERGED")"
+                               then
+                                       # Local isn't present, but it's a subdirectory
+                                       git ls-tree --full-name -r HEAD -- "$MERGED" |
+                                       git update-index --index-info || exit $?
+                               else
+                                       test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
+                                       git update-index --force-remove "$MERGED"
+                                       cleanup_temp_files --save-backup
+                               fi
+                       elif is_submodule "$local_mode"
+                       then
+                               stage_submodule "$MERGED" "$local_sha1"
+                       else
+                               git checkout-index -f --stage=2 -- "$MERGED"
+                               git add -- "$MERGED"
+                       fi
+                       return 0
+                       ;;
+               [rR]*)
+                       if ! remote_present
+                       then
+                               if test -n "$(git ls-tree MERGE_HEAD -- "$MERGED")"
+                               then
+                                       # Remote isn't present, but it's a subdirectory
+                                       git ls-tree --full-name -r MERGE_HEAD -- "$MERGED" |
+                                       git update-index --index-info || exit $?
+                               else
+                                       test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
+                                       git update-index --force-remove "$MERGED"
+                               fi
+                       elif is_submodule "$remote_mode"
+                       then
+                               ! is_submodule "$local_mode" &&
+                               test -e "$MERGED" &&
+                               mv -- "$MERGED" "$BACKUP"
+                               stage_submodule "$MERGED" "$remote_sha1"
+                       else
+                               test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
+                               git checkout-index -f --stage=3 -- "$MERGED"
+                               git add -- "$MERGED"
+                       fi
                        cleanup_temp_files --save-backup
-                   fi
-               elif is_submodule "$local_mode"; then
-                   stage_submodule "$MERGED" "$local_sha1"
-               else
-                   git checkout-index -f --stage=2 -- "$MERGED"
-                   git add -- "$MERGED"
-               fi
-               return 0
-               ;;
-           [rR]*)
-               if ! remote_present; then
-                   if test -n "$(git ls-tree MERGE_HEAD -- "$MERGED")"; then
-                       # Remote isn't present, but it's a subdirectory
-                       git ls-tree --full-name -r MERGE_HEAD -- "$MERGED" | git update-index --index-info || exit $?
-                   else
-                       test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
-                       git update-index --force-remove "$MERGED"
-                   fi
-               elif is_submodule "$remote_mode"; then
-                   ! is_submodule "$local_mode" && test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
-                   stage_submodule "$MERGED" "$remote_sha1"
-               else
-                   test -e "$MERGED" && mv -- "$MERGED" "$BACKUP"
-                   git checkout-index -f --stage=3 -- "$MERGED"
-                   git add -- "$MERGED"
-               fi
-               cleanup_temp_files --save-backup
-               return 0
-               ;;
-           [aA]*)
-               return 1
-               ;;
-           esac
+                       return 0
+                       ;;
+               [aA]*)
+                       return 1
+                       ;;
+               esac
        done
 }
 
 stage_submodule () {
-    path="$1"
-    submodule_sha1="$2"
-    mkdir -p "$path" || die "fatal: unable to create directory for module at $path"
-    # Find $path relative to work tree
-    work_tree_root=$(cd_to_toplevel && pwd)
-    work_rel_path=$(cd "$path" && GIT_WORK_TREE="${work_tree_root}" git rev-parse --show-prefix)
-    test -n "$work_rel_path" || die "fatal: unable to get path of module $path relative to work tree"
-    git update-index --add --replace --cacheinfo 160000 "$submodule_sha1" "${work_rel_path%/}" || die
+       path="$1"
+       submodule_sha1="$2"
+       mkdir -p "$path" ||
+       die "fatal: unable to create directory for module at $path"
+       # Find $path relative to work tree
+       work_tree_root=$(cd_to_toplevel && pwd)
+       work_rel_path=$(cd "$path" &&
+               GIT_WORK_TREE="${work_tree_root}" git rev-parse --show-prefix
+       )
+       test -n "$work_rel_path" ||
+       die "fatal: unable to get path of module $path relative to work tree"
+       git update-index --add --replace --cacheinfo 160000 "$submodule_sha1" "${work_rel_path%/}" || die
 }
 
 checkout_staged_file () {
-    tmpfile=$(expr \
-           "$(git checkout-index --temp --stage="$1" "$2" 2>/dev/null)" \
-           : '\([^     ]*\)    ')
-
-    if test $? -eq 0 -a -n "$tmpfile" ; then
-       mv -- "$(git rev-parse --show-cdup)$tmpfile" "$3"
-    else
-       >"$3"
-    fi
+       tmpfile=$(expr \
+               "$(git checkout-index --temp --stage="$1" "$2" 2>/dev/null)" \
+               : '\([^ ]*\)    ')
+
+       if test $? -eq 0 -a -n "$tmpfile"
+       then
+               mv -- "$(git rev-parse --show-cdup)$tmpfile" "$3"
+       else
+               >"$3"
+       fi
 }
 
 merge_file () {
-    MERGED="$1"
+       MERGED="$1"
 
-    f=$(git ls-files -u -- "$MERGED")
-    if test -z "$f" ; then
-       if test ! -f "$MERGED" ; then
-           echo "$MERGED: file not found"
-       else
-           echo "$MERGED: file does not need merging"
+       f=$(git ls-files -u -- "$MERGED")
+       if test -z "$f"
+       then
+               if test ! -f "$MERGED"
+               then
+                       echo "$MERGED: file not found"
+               else
+                       echo "$MERGED: file does not need merging"
+               fi
+               return 1
        fi
-       return 1
-    fi
-
-    ext="$$$(expr "$MERGED" : '.*\(\.[^/]*\)$')"
-    BACKUP="./$MERGED.BACKUP.$ext"
-    LOCAL="./$MERGED.LOCAL.$ext"
-    REMOTE="./$MERGED.REMOTE.$ext"
-    BASE="./$MERGED.BASE.$ext"
-
-    base_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==1) print $1;}')
-    local_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}')
-    remote_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}')
-
-    if is_submodule "$local_mode" || is_submodule "$remote_mode"; then
-       echo "Submodule merge conflict for '$MERGED':"
-       local_sha1=$(git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $2;}')
-       remote_sha1=$(git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $2;}')
-       describe_file "$local_mode" "local" "$local_sha1"
-       describe_file "$remote_mode" "remote" "$remote_sha1"
-       resolve_submodule_merge
-       return
-    fi
-
-    mv -- "$MERGED" "$BACKUP"
-    cp -- "$BACKUP" "$MERGED"
-
-    checkout_staged_file 1 "$MERGED" "$BASE"
-    checkout_staged_file 2 "$MERGED" "$LOCAL"
-    checkout_staged_file 3 "$MERGED" "$REMOTE"
-
-    if test -z "$local_mode" -o -z "$remote_mode"; then
-       echo "Deleted merge conflict for '$MERGED':"
-       describe_file "$local_mode" "local" "$LOCAL"
-       describe_file "$remote_mode" "remote" "$REMOTE"
-       resolve_deleted_merge
-       return
-    fi
 
-    if is_symlink "$local_mode" || is_symlink "$remote_mode"; then
-       echo "Symbolic link merge conflict for '$MERGED':"
+       ext="$$$(expr "$MERGED" : '.*\(\.[^/]*\)$')"
+       BACKUP="./$MERGED.BACKUP.$ext"
+       LOCAL="./$MERGED.LOCAL.$ext"
+       REMOTE="./$MERGED.REMOTE.$ext"
+       BASE="./$MERGED.BASE.$ext"
+
+       base_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==1) print $1;}')
+       local_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $1;}')
+       remote_mode=$(git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $1;}')
+
+       if is_submodule "$local_mode" || is_submodule "$remote_mode"
+       then
+               echo "Submodule merge conflict for '$MERGED':"
+               local_sha1=$(git ls-files -u -- "$MERGED" | awk '{if ($3==2) print $2;}')
+               remote_sha1=$(git ls-files -u -- "$MERGED" | awk '{if ($3==3) print $2;}')
+               describe_file "$local_mode" "local" "$local_sha1"
+               describe_file "$remote_mode" "remote" "$remote_sha1"
+               resolve_submodule_merge
+               return
+       fi
+
+       mv -- "$MERGED" "$BACKUP"
+       cp -- "$BACKUP" "$MERGED"
+
+       checkout_staged_file 1 "$MERGED" "$BASE"
+       checkout_staged_file 2 "$MERGED" "$LOCAL"
+       checkout_staged_file 3 "$MERGED" "$REMOTE"
+
+       if test -z "$local_mode" -o -z "$remote_mode"
+       then
+               echo "Deleted merge conflict for '$MERGED':"
+               describe_file "$local_mode" "local" "$LOCAL"
+               describe_file "$remote_mode" "remote" "$REMOTE"
+               resolve_deleted_merge
+               return
+       fi
+
+       if is_symlink "$local_mode" || is_symlink "$remote_mode"
+       then
+               echo "Symbolic link merge conflict for '$MERGED':"
+               describe_file "$local_mode" "local" "$LOCAL"
+               describe_file "$remote_mode" "remote" "$REMOTE"
+               resolve_symlink_merge
+               return
+       fi
+
+       echo "Normal merge conflict for '$MERGED':"
        describe_file "$local_mode" "local" "$LOCAL"
        describe_file "$remote_mode" "remote" "$REMOTE"
-       resolve_symlink_merge
-       return
-    fi
-
-    echo "Normal merge conflict for '$MERGED':"
-    describe_file "$local_mode" "local" "$LOCAL"
-    describe_file "$remote_mode" "remote" "$REMOTE"
-    if "$prompt" = true; then
-       printf "Hit return to start merge resolution tool (%s): " "$merge_tool"
-       read ans || return 1
-    fi
-
-    if base_present; then
-           present=true
-    else
-           present=false
-    fi
-
-    if ! run_merge_tool "$merge_tool" "$present"; then
-       echo "merge of $MERGED failed" 1>&2
-       mv -- "$BACKUP" "$MERGED"
-
-       if test "$merge_keep_temporaries" = "false"; then
-           cleanup_temp_files
+       if "$prompt" = true
+       then
+               printf "Hit return to start merge resolution tool (%s): " "$merge_tool"
+               read ans || return 1
        fi
 
-       return 1
-    fi
+       if base_present
+       then
+               present=true
+       else
+               present=false
+       fi
+
+       if ! run_merge_tool "$merge_tool" "$present"
+       then
+               echo "merge of $MERGED failed" 1>&2
+               mv -- "$BACKUP" "$MERGED"
+
+               if test "$merge_keep_temporaries" = "false"
+               then
+                       cleanup_temp_files
+               fi
 
-    if test "$merge_keep_backup" = "true"; then
-       mv -- "$BACKUP" "$MERGED.orig"
-    else
-       rm -- "$BACKUP"
-    fi
+               return 1
+       fi
 
-    git add -- "$MERGED"
-    cleanup_temp_files
-    return 0
+       if test "$merge_keep_backup" = "true"
+       then
+               mv -- "$BACKUP" "$MERGED.orig"
+       else
+               rm -- "$BACKUP"
+       fi
+
+       git add -- "$MERGED"
+       cleanup_temp_files
+       return 0
 }
 
 show_tool_help () {
@@ -325,61 +356,61 @@ prompt=$(git config --bool mergetool.prompt || echo true)
 
 while test $# != 0
 do
-    case "$1" in
+       case "$1" in
        --tool-help)
                show_tool_help
                ;;
        -t|--tool*)
-           case "$#,$1" in
+               case "$#,$1" in
                *,*=*)
-                   merge_tool=$(expr "z$1" : 'z-[^=]*=\(.*\)')
-                   ;;
+                       merge_tool=$(expr "z$1" : 'z-[^=]*=\(.*\)')
+                       ;;
                1,*)
-                   usage ;;
+                       usage ;;
                *)
-                   merge_tool="$2"
-                   shift ;;
-           esac
-           ;;
+                       merge_tool="$2"
+                       shift ;;
+               esac
+               ;;
        -y|--no-prompt)
-           prompt=false
-           ;;
+               prompt=false
+               ;;
        --prompt)
-           prompt=true
-           ;;
+               prompt=true
+               ;;
        --)
-           shift
-           break
-           ;;
+               shift
+               break
+               ;;
        -*)
-           usage
-           ;;
-       *)
-           break
-           ;;
-    esac
-    shift
-done
-
-prompt_after_failed_merge() {
-    while true; do
-       printf "Continue merging other unresolved paths (y/n) ? "
-       read ans || return 1
-       case "$ans" in
-
-           [yY]*)
-               return 0
+               usage
                ;;
-
-           [nN]*)
-               return 1
+       *)
+               break
                ;;
        esac
-    done
+       shift
+done
+
+prompt_after_failed_merge () {
+       while true
+       do
+               printf "Continue merging other unresolved paths (y/n) ? "
+               read ans || return 1
+               case "$ans" in
+               [yY]*)
+                       return 0
+                       ;;
+               [nN]*)
+                       return 1
+                       ;;
+               esac
+       done
 }
 
-if test -z "$merge_tool"; then
-    merge_tool=$(get_merge_tool "$merge_tool") || exit
+if test -z "$merge_tool"
+then
+       merge_tool=$(get_merge_tool "$merge_tool") || exit
 fi
 merge_keep_backup="$(git config --bool mergetool.keepBackup || echo true)"
 merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)"
@@ -388,22 +419,24 @@ last_status=0
 rollup_status=0
 files=
 
-if test $# -eq 0 ; then
-    cd_to_toplevel
+if test $# -eq 0
+then
+       cd_to_toplevel
 
-    if test -e "$GIT_DIR/MERGE_RR"
-    then
-       files=$(git rerere remaining)
-    else
-       files=$(git ls-files -u | sed -e 's/^[^ ]*      //' | sort -u)
-    fi
+       if test -e "$GIT_DIR/MERGE_RR"
+       then
+               files=$(git rerere remaining)
+       else
+               files=$(git ls-files -u | sed -e 's/^[^ ]*      //' | sort -u)
+       fi
 else
-    files=$(git ls-files -u -- "$@" | sed -e 's/^[^    ]*      //' | sort -u)
+       files=$(git ls-files -u -- "$@" | sed -e 's/^[^ ]*      //' | sort -u)
 fi
 
-if test -z "$files" ; then
-    echo "No files need merging"
-    exit 0
+if test -z "$files"
+then
+       echo "No files need merging"
+       exit 0
 fi
 
 printf "Merging:\n"
@@ -413,15 +446,17 @@ IFS='
 '
 for i in $files
 do
-    if test $last_status -ne 0; then
-       prompt_after_failed_merge || exit 1
-    fi
-    printf "\n"
-    merge_file "$i"
-    last_status=$?
-    if test $last_status -ne 0; then
-       rollup_status=1
-    fi
+       if test $last_status -ne 0
+       then
+               prompt_after_failed_merge || exit 1
+       fi
+       printf "\n"
+       merge_file "$i"
+       last_status=$?
+       if test $last_status -ne 0
+       then
+               rollup_status=1
+       fi
 done
 
 exit $rollup_status
index 0d2056f027cbd6811faee3c45088a11b24d86102..a09e8423ddb1d05c581ef72101c3f5201ce2eeb9 100644 (file)
@@ -569,11 +569,10 @@ do_next () {
        test -s "$todo" && return
 
        comment_for_reflog finish &&
-       shortonto=$(git rev-parse --short $onto) &&
        newhead=$(git rev-parse HEAD) &&
        case $head_name in
        refs/*)
-               message="$GIT_REFLOG_ACTION: $head_name onto $shortonto" &&
+               message="$GIT_REFLOG_ACTION: $head_name onto $onto" &&
                git update-ref -m "$message" $head_name $newhead $orig_head &&
                git symbolic-ref \
                  -m "$GIT_REFLOG_ACTION: returning to $head_name" \
index ef30c557c7dee549e891fe7605902ba58d0566a3..aea66a0d47a9ad64fe805351c631fe5fddbf6182 100755 (executable)
@@ -681,6 +681,7 @@ sub ask {
        my ($prompt, %arg) = @_;
        my $valid_re = $arg{valid_re};
        my $default = $arg{default};
+       my $confirm_only = $arg{confirm_only};
        my $resp;
        my $i = 0;
        return defined $default ? $default : undef
@@ -698,6 +699,12 @@ sub ask {
                if (!defined $valid_re or $resp =~ /$valid_re/) {
                        return $resp;
                }
+               if ($confirm_only) {
+                       my $yesno = $term->readline("Are you sure you want to use <$resp> [y/N]? ");
+                       if (defined $yesno && $yesno =~ /y/i) {
+                               return $resp;
+                       }
+               }
        }
        return undef;
 }
@@ -745,13 +752,16 @@ sub file_declares_8bit_cte {
 if (!defined $sender) {
        $sender = $repoauthor || $repocommitter || '';
        $sender = ask("Who should the emails appear to be from? [$sender] ",
-                     default => $sender);
+                     default => $sender,
+                     valid_re => qr/\@.*\./, confirm_only => 1);
        print "Emails will be sent from: ", $sender, "\n";
        $prompting++;
 }
 
 if (!@initial_to && !defined $to_cmd) {
-       my $to = ask("Who should the emails be sent to? ");
+       my $to = ask("Who should the emails be sent to (if any)? ",
+                    default => "",
+                    valid_re => qr/\@.*\./, confirm_only => 1);
        push @initial_to, parse_address_line($to) if defined $to; # sanitized/validated later
        $prompting++;
 }
@@ -777,7 +787,9 @@ sub expand_one_alias {
 
 if ($thread && !defined $initial_reply_to && $prompting) {
        $initial_reply_to = ask(
-               "Message-ID to be used as In-Reply-To for the first email? ");
+               "Message-ID to be used as In-Reply-To for the first email (if any)? ",
+               default => "",
+               valid_re => qr/\@.*\./, confirm_only => 1);
 }
 if (defined $initial_reply_to) {
        $initial_reply_to =~ s/^\s*<?//;
@@ -862,11 +874,13 @@ sub make_message_id {
 sub unquote_rfc2047 {
        local ($_) = @_;
        my $encoding;
-       if (s/=\?([^?]+)\?q\?(.*)\?=/$2/g) {
+       s{=\?([^?]+)\?q\?(.*?)\?=}{
                $encoding = $1;
-               s/_/ /g;
-               s/=([0-9A-F]{2})/chr(hex($1))/eg;
-       }
+               my $e = $2;
+               $e =~ s/_/ /g;
+               $e =~ s/=([0-9A-F]{2})/chr(hex($1))/eg;
+               $e;
+       }eg;
        return wantarray ? ($_, $encoding) : $_;
 }
 
index 770a86e2b7a5e517e51d9897b274b876a6b9e0e1..ee0e0bc045bb7d92045a3afb0a042748834e6163 100644 (file)
@@ -9,8 +9,12 @@
 # you would cause "cd" to be taken to unexpected places.  If you
 # like CDPATH, define it for your interactive shell sessions without
 # exporting it.
+# But we protect ourselves from such a user mistake nevertheless.
 unset CDPATH
 
+# Similarly for IFS
+unset IFS
+
 git_broken_path_fix () {
        case ":$PATH:" in
        *:$1:*) : ok ;;
index 4e2c7f83314954de6655b0d1bff773c31dfe3ed1..bbefdf64244063f4708f381b8a772466d64e90e5 100755 (executable)
@@ -469,6 +469,7 @@ apply_stash () {
        else
                # Merge conflict; keep the exit status from merge-recursive
                status=$?
+               git rerere
                if test -n "$INDEX_OPTION"
                then
                        gettextln "Index was not unstashed." >&2
index aac575e74f833c9bce28b779733b28a7611246b2..3e2045e52daf43cc351af23af0fd770fb1a5044f 100755 (executable)
@@ -109,26 +109,48 @@ resolve_relative_url ()
 #
 module_list()
 {
-       git ls-files --error-unmatch --stage -- "$@" |
+       (
+               git ls-files --error-unmatch --stage -- "$@" ||
+               echo "unmatched pathspec exists"
+       ) |
        perl -e '
        my %unmerged = ();
        my ($null_sha1) = ("0" x 40);
+       my @out = ();
+       my $unmatched = 0;
        while (<STDIN>) {
+               if (/^unmatched pathspec/) {
+                       $unmatched = 1;
+                       next;
+               }
                chomp;
                my ($mode, $sha1, $stage, $path) =
                        /^([0-7]+) ([0-9a-f]{40}) ([0-3])\t(.*)$/;
                next unless $mode eq "160000";
                if ($stage ne "0") {
                        if (!$unmerged{$path}++) {
-                               print "$mode $null_sha1 U\t$path\n";
+                               push @out, "$mode $null_sha1 U\t$path\n";
                        }
                        next;
                }
-               print "$_\n";
+               push @out, "$_\n";
+       }
+       if ($unmatched) {
+               print "#unmatched\n";
+       } else {
+               print for (@out);
        }
        '
 }
 
+die_if_unmatched ()
+{
+       if test "$1" = "#unmatched"
+       then
+               exit 1
+       fi
+}
+
 #
 # Map submodule path to submodule name
 #
@@ -385,6 +407,7 @@ cmd_foreach()
        module_list |
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                if test -e "$sm_path"/.git
                then
                        say "$(eval_gettext "Entering '\$prefix\$sm_path'")"
@@ -437,6 +460,7 @@ cmd_init()
        module_list "$@" |
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                name=$(module_name "$sm_path") || exit
 
                # Copy url setting when it is not set yet
@@ -537,6 +561,7 @@ cmd_update()
        err=
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                if test "$stage" = U
                then
                        echo >&2 "Skipping unmerged submodule $sm_path"
@@ -578,7 +603,7 @@ Maybe you want to use 'update --init'?")"
                        die "$(eval_gettext "Unable to find current revision in submodule path '\$sm_path'")"
                fi
 
-               if test "$subsha1" != "$sha1"
+               if test "$subsha1" != "$sha1" -o -n "$force"
                then
                        subforce=$force
                        # If we don't already have a -f flag and the submodule has never been checked out
@@ -932,6 +957,7 @@ cmd_status()
        module_list "$@" |
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                name=$(module_name "$sm_path") || exit
                url=$(git config submodule."$name".url)
                displaypath="$prefix$sm_path"
@@ -1000,6 +1026,7 @@ cmd_sync()
        module_list "$@" |
        while read mode sha1 stage sm_path
        do
+               die_if_unmatched "$mode"
                name=$(module_name "$sm_path")
                url=$(git config -f .gitmodules --get submodule."$name".url)
 
index 22270ce46bb73bc8fc8e82409ef0179576f7ba20..6f24f53d217884607f1bf04c4b2f715cf6ad78ac 100755 (executable)
@@ -2038,7 +2038,7 @@ proc makewindow {} {
     set file {
        mc "File" cascade {
            {mc "Update" command updatecommits -accelerator F5}
-           {mc "Reload" command reloadcommits -accelerator Meta1-F5}
+           {mc "Reload" command reloadcommits -accelerator Shift-F5}
            {mc "Reread references" command rereadrefs}
            {mc "List references" command showrefs -accelerator F2}
            {xx "" separator}
@@ -2495,7 +2495,7 @@ proc makewindow {} {
     bindkey ? {dofind -1 1}
     bindkey f nextfile
     bind . <F5> updatecommits
-    bind . <$M1B-F5> reloadcommits
+    bind . <Shift-F5> reloadcommits
     bind . <F2> showrefs
     bind . <Shift-F4> {newview 0}
     catch { bind . <Shift-Key-XF86_Switch_VT_4> {newview 0} }
@@ -10599,7 +10599,7 @@ proc movedhead {hid head} {
 }
 
 proc changedrefs {} {
-    global cached_dheads cached_dtags cached_atags
+    global cached_dheads cached_dtags cached_atags cached_tagcontent
     global arctags archeads arcnos arcout idheads idtags
 
     foreach id [concat [array names idheads] [array names idtags]] {
@@ -10611,6 +10611,7 @@ proc changedrefs {} {
            }
        }
     }
+    catch {unset cached_tagcontent}
     catch {unset cached_dtags}
     catch {unset cached_atags}
     catch {unset cached_dheads}
@@ -10663,7 +10664,7 @@ proc listrefs {id} {
 }
 
 proc showtag {tag isnew} {
-    global ctext tagcontents tagids linknum tagobjid
+    global ctext cached_tagcontent tagids linknum tagobjid
 
     if {$isnew} {
        addtohistory [list showtag $tag 0] savectextpos
@@ -10672,13 +10673,13 @@ proc showtag {tag isnew} {
     clear_ctext
     settabs 0
     set linknum 0
-    if {![info exists tagcontents($tag)]} {
+    if {![info exists cached_tagcontent($tag)]} {
        catch {
-           set tagcontents($tag) [exec git cat-file tag $tag]
+           set cached_tagcontent($tag) [exec git cat-file tag $tag]
        }
     }
-    if {[info exists tagcontents($tag)]} {
-       set text $tagcontents($tag)
+    if {[info exists cached_tagcontent($tag)]} {
+       set text $cached_tagcontent($tag)
     } else {
        set text "[mc "Tag"]: $tag\n[mc "Id"]:  $tagids($tag)"
     }
index 3d6a7053881ec7646dc28a2eba991a15ff80c634..7f8c1878d407e07c3ac4ac16d840557a18176d29 100755 (executable)
@@ -54,6 +54,11 @@ sub evaluate_uri {
        # to build the base URL ourselves:
        our $path_info = decode_utf8($ENV{"PATH_INFO"});
        if ($path_info) {
+               # $path_info has already been URL-decoded by the web server, but
+               # $my_url and $my_uri have not. URL-decode them so we can properly
+               # strip $path_info.
+               $my_url = unescape($my_url);
+               $my_uri = unescape($my_uri);
                if ($my_url =~ s,\Q$path_info\E$,, &&
                    $my_uri =~ s,\Q$path_info\E$,, &&
                    defined $ENV{'SCRIPT_NAME'}) {
diff --git a/http.c b/http.c
index b61ac85d4b19a0b9121c5b19f2b9c731bbb238d4..9bac1d89fdb639f6991bfe9f683ccf7bd5ada4cb 100644 (file)
--- a/http.c
+++ b/http.c
@@ -745,6 +745,35 @@ char *get_remote_object_url(const char *url, const char *hex,
        return strbuf_detach(&buf, NULL);
 }
 
+int handle_curl_result(struct active_request_slot *slot)
+{
+       struct slot_results *results = slot->results;
+
+       if (results->curl_result == CURLE_OK) {
+               credential_approve(&http_auth);
+               return HTTP_OK;
+       } else if (missing_target(results))
+               return HTTP_MISSING_TARGET;
+       else if (results->http_code == 401) {
+               if (http_auth.username && http_auth.password) {
+                       credential_reject(&http_auth);
+                       return HTTP_NOAUTH;
+               } else {
+                       credential_fill(&http_auth);
+                       init_curl_http_auth(slot->curl);
+                       return HTTP_REAUTH;
+               }
+       } else {
+#if LIBCURL_VERSION_NUM >= 0x070c00
+               if (!curl_errorstr[0])
+                       strlcpy(curl_errorstr,
+                               curl_easy_strerror(results->curl_result),
+                               sizeof(curl_errorstr));
+#endif
+               return HTTP_ERROR;
+       }
+}
+
 /* http_request() targets */
 #define HTTP_REQUEST_STRBUF    0
 #define HTTP_REQUEST_FILE      1
@@ -792,26 +821,7 @@ static int http_request(const char *url, void *result, int target, int options)
 
        if (start_active_slot(slot)) {
                run_active_slot(slot);
-               if (results.curl_result == CURLE_OK)
-                       ret = HTTP_OK;
-               else if (missing_target(&results))
-                       ret = HTTP_MISSING_TARGET;
-               else if (results.http_code == 401) {
-                       if (http_auth.username && http_auth.password) {
-                               credential_reject(&http_auth);
-                               ret = HTTP_NOAUTH;
-                       } else {
-                               credential_fill(&http_auth);
-                               init_curl_http_auth(slot->curl);
-                               ret = HTTP_REAUTH;
-                       }
-               } else {
-                       if (!curl_errorstr[0])
-                               strlcpy(curl_errorstr,
-                                       curl_easy_strerror(results.curl_result),
-                                       sizeof(curl_errorstr));
-                       ret = HTTP_ERROR;
-               }
+               ret = handle_curl_result(slot);
        } else {
                error("Unable to start HTTP request for %s", url);
                ret = HTTP_START_FAILED;
@@ -820,9 +830,6 @@ static int http_request(const char *url, void *result, int target, int options)
        curl_slist_free_all(headers);
        strbuf_release(&buf);
 
-       if (ret == HTTP_OK)
-               credential_approve(&http_auth);
-
        return ret;
 }
 
diff --git a/http.h b/http.h
index 915c2862a65bdbf42472099f9ed53ca68c2ccfd9..12de25597df4077a52a44dace83093091514c10d 100644 (file)
--- a/http.h
+++ b/http.h
@@ -78,6 +78,7 @@ extern int start_active_slot(struct active_request_slot *slot);
 extern void run_active_slot(struct active_request_slot *slot);
 extern void finish_active_slot(struct active_request_slot *slot);
 extern void finish_all_active_slots(void);
+extern int handle_curl_result(struct active_request_slot *slot);
 
 #ifdef USE_CURL_MULTI
 extern void fill_active_slots(void);
diff --git a/ident.c b/ident.c
index 443c0751bd1f63c059649f9f7f9174349cc1d270..484e0a980308fd2201bf443815a58c41bea17073 100644 (file)
--- a/ident.c
+++ b/ident.c
@@ -210,8 +210,10 @@ int split_ident_line(struct ident_split *split, const char *line, int len)
                        split->name_end = cp + 1;
                        break;
                }
-       if (!split->name_end)
-               return status;
+       if (!split->name_end) {
+               /* no human readable name */
+               split->name_end = split->name_begin;
+       }
 
        for (cp = split->mail_begin; cp < line + len; cp++)
                if (*cp == '>') {
index 39b2e165e05472daf38cd6f458541b6db4abc9a8..7866ca1026730e2e0446f711e3c621e44cef9f60 100644 (file)
@@ -493,8 +493,7 @@ static struct string_list *get_renames(struct merge_options *o,
        opts.rename_score = o->rename_score;
        opts.show_rename_progress = o->show_rename_progress;
        opts.output_format = DIFF_FORMAT_NO_OUTPUT;
-       if (diff_setup_done(&opts) < 0)
-               die(_("diff setup failed"));
+       diff_setup_done(&opts);
        diff_tree_sha1(o_tree->object.sha1, tree->object.sha1, "", &opts);
        diffcore_std(&opts);
        if (opts.needed_rename_limit > o->needed_rename_limit)
@@ -614,23 +613,6 @@ static char *unique_path(struct merge_options *o, const char *path, const char *
        return newpath;
 }
 
-static void flush_buffer(int fd, const char *buf, unsigned long size)
-{
-       while (size > 0) {
-               long ret = write_in_full(fd, buf, size);
-               if (ret < 0) {
-                       /* Ignore epipe */
-                       if (errno == EPIPE)
-                               break;
-                       die_errno("merge-recursive");
-               } else if (!ret) {
-                       die(_("merge-recursive: disk full?"));
-               }
-               size -= ret;
-               buf += ret;
-       }
-}
-
 static int dir_in_way(const char *path, int check_working_copy)
 {
        int pos, pathlen = strlen(path);
@@ -789,7 +771,7 @@ static void update_file_flags(struct merge_options *o,
                        fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
                        if (fd < 0)
                                die_errno(_("failed to open '%s'"), path);
-                       flush_buffer(fd, buf, size);
+                       write_in_full(fd, buf, size);
                        close(fd);
                } else if (S_ISLNK(mode)) {
                        char *lnk = xmemdupz(buf, size);
index 29c6411fc63a01460f95b25bf62115c350ef2191..0f67bd3f9605aa7a3c98b88b4ae4aae037ace3d7 100644 (file)
@@ -126,8 +126,7 @@ static struct notes_merge_pair *diff_tree_remote(struct notes_merge_options *o,
        diff_setup(&opt);
        DIFF_OPT_SET(&opt, RECURSIVE);
        opt.output_format = DIFF_FORMAT_NO_OUTPUT;
-       if (diff_setup_done(&opt) < 0)
-               die("diff_setup_done failed");
+       diff_setup_done(&opt);
        diff_tree_sha1(base, remote, "", &opt);
        diffcore_std(&opt);
 
@@ -190,8 +189,7 @@ static void diff_tree_local(struct notes_merge_options *o,
        diff_setup(&opt);
        DIFF_OPT_SET(&opt, RECURSIVE);
        opt.output_format = DIFF_FORMAT_NO_OUTPUT;
-       if (diff_setup_done(&opt) < 0)
-               die("diff_setup_done failed");
+       diff_setup_done(&opt);
        diff_tree_sha1(base, local, "", &opt);
        diffcore_std(&opt);
 
index 5717257051aceff129a4d0777c0a11bc156cae54..bc8a28fdd71ae1476002d26adec64f54841f5cba 100644 (file)
@@ -39,8 +39,7 @@ int init_patch_ids(struct patch_ids *ids)
        memset(ids, 0, sizeof(*ids));
        diff_setup(&ids->diffopts);
        DIFF_OPT_SET(&ids->diffopts, RECURSIVE);
-       if (diff_setup_done(&ids->diffopts) < 0)
-               return error("diff_setup_done failed");
+       diff_setup_done(&ids->diffopts);
        return 0;
 }
 
index 2f8159fb165f853aafb5e0cee61f35aa854271ec..79e3bbe0240e16629e8ba4b755d60f986132802a 100644 (file)
@@ -1414,11 +1414,9 @@ int read_index_from(struct index_state *istate, const char *path)
        size_t mmap_size;
        struct strbuf previous_name_buf = STRBUF_INIT, *previous_name;
 
-       errno = EBUSY;
        if (istate->initialized)
                return istate->cache_nr;
 
-       errno = ENOENT;
        istate->timestamp.sec = 0;
        istate->timestamp.nsec = 0;
        fd = open(path, O_RDONLY);
@@ -1431,15 +1429,14 @@ int read_index_from(struct index_state *istate, const char *path)
        if (fstat(fd, &st))
                die_errno("cannot stat the open index");
 
-       errno = EINVAL;
        mmap_size = xsize_t(st.st_size);
        if (mmap_size < sizeof(struct cache_header) + 20)
                die("index file smaller than expected");
 
        mmap = xmmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
-       close(fd);
        if (mmap == MAP_FAILED)
                die_errno("unable to map index file");
+       close(fd);
 
        hdr = mmap;
        if (verify_hdr(hdr, mmap_size) < 0)
@@ -1495,7 +1492,6 @@ int read_index_from(struct index_state *istate, const char *path)
 
 unmap:
        munmap(mmap, mmap_size);
-       errno = EINVAL;
        die("index file corrupt");
 }
 
@@ -1800,6 +1796,8 @@ int write_index(struct index_state *istate, int newfd)
                        continue;
                if (!ce_uptodate(ce) && is_racy_timestamp(istate, ce))
                        ce_smudge_racily_clean_entry(ce);
+               if (is_null_sha1(ce->sha1))
+                       return error("cache entry has null sha1: %s", ce->name);
                if (ce_write_entry(&c, newfd, ce, previous_name) < 0)
                        return -1;
        }
index 04a9d6277db8fac78cb223a906b12744aab32193..3ec474fc631eb3b433b3cadbd74aed4b83cba724 100644 (file)
@@ -362,16 +362,17 @@ static size_t rpc_in(char *ptr, size_t eltsize,
 
 static int run_slot(struct active_request_slot *slot)
 {
-       int err = 0;
+       int err;
        struct slot_results results;
 
        slot->results = &results;
        slot->curl_result = curl_easy_perform(slot->curl);
        finish_active_slot(slot);
 
-       if (results.curl_result != CURLE_OK) {
-               err |= error("RPC failed; result=%d, HTTP code = %ld",
-                       results.curl_result, results.http_code);
+       err = handle_curl_result(slot);
+       if (err != HTTP_OK && err != HTTP_REAUTH) {
+               error("RPC failed; result=%d, HTTP code = %ld",
+                     results.curl_result, results.http_code);
        }
 
        return err;
@@ -436,9 +437,11 @@ static int post_rpc(struct rpc_state *rpc)
        }
 
        if (large_request) {
-               err = probe_rpc(rpc);
-               if (err)
-                       return err;
+               do {
+                       err = probe_rpc(rpc);
+               } while (err == HTTP_REAUTH);
+               if (err != HTTP_OK)
+                       return -1;
        }
 
        slot = get_active_slot();
@@ -525,7 +528,11 @@ static int post_rpc(struct rpc_state *rpc)
        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, rpc_in);
        curl_easy_setopt(slot->curl, CURLOPT_FILE, rpc);
 
-       err = run_slot(slot);
+       do {
+               err = run_slot(slot);
+       } while (err == HTTP_REAUTH && !large_request && !use_gzip);
+       if (err != HTTP_OK)
+               err = -1;
 
        curl_slist_free_all(headers);
        free(gzip_body);
index 9e8f47a25d8def94cbf2a8389039e4d3d670cd06..dc3fecf903aa0ce4927b9ebe5b95f99cc9c1018d 100644 (file)
@@ -345,6 +345,7 @@ static int tree_difference = REV_TREE_SAME;
 static void file_add_remove(struct diff_options *options,
                    int addremove, unsigned mode,
                    const unsigned char *sha1,
+                   int sha1_valid,
                    const char *fullpath, unsigned dirty_submodule)
 {
        int diff = addremove == '+' ? REV_TREE_NEW : REV_TREE_OLD;
@@ -358,6 +359,7 @@ static void file_change(struct diff_options *options,
                 unsigned old_mode, unsigned new_mode,
                 const unsigned char *old_sha1,
                 const unsigned char *new_sha1,
+                int old_sha1_valid, int new_sha1_valid,
                 const char *fullpath,
                 unsigned old_dirty_submodule, unsigned new_dirty_submodule)
 {
@@ -1132,15 +1134,27 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
                const char *this = arg;
                int symmetric = *next == '.';
                unsigned int flags_exclude = flags ^ UNINTERESTING;
+               static const char head_by_default[] = "HEAD";
                unsigned int a_flags;
 
                *dotdot = 0;
                next += symmetric;
 
                if (!*next)
-                       next = "HEAD";
+                       next = head_by_default;
                if (dotdot == arg)
-                       this = "HEAD";
+                       this = head_by_default;
+               if (this == head_by_default && next == head_by_default &&
+                   !symmetric) {
+                       /*
+                        * Just ".."?  That is not a range but the
+                        * pathspec for the parent directory.
+                        */
+                       if (!cant_be_filename) {
+                               *dotdot = '.';
+                               return -1;
+                       }
+               }
                if (!get_sha1_committish(this, from_sha1) &&
                    !get_sha1_committish(next, sha1)) {
                        struct commit *a, *b;
@@ -1298,7 +1312,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
            !strcmp(arg, "--no-walk") || !strcmp(arg, "--do-walk") ||
            !strcmp(arg, "--bisect") || !prefixcmp(arg, "--glob=") ||
            !prefixcmp(arg, "--branches=") || !prefixcmp(arg, "--tags=") ||
-           !prefixcmp(arg, "--remotes="))
+           !prefixcmp(arg, "--remotes=") || !prefixcmp(arg, "--no-walk="))
        {
                unkv[(*unkc)++] = arg;
                return 1;
@@ -1693,7 +1707,18 @@ static int handle_revision_pseudo_opt(const char *submodule,
        } else if (!strcmp(arg, "--not")) {
                *flags ^= UNINTERESTING;
        } else if (!strcmp(arg, "--no-walk")) {
-               revs->no_walk = 1;
+               revs->no_walk = REVISION_WALK_NO_WALK_SORTED;
+       } else if (!prefixcmp(arg, "--no-walk=")) {
+               /*
+                * Detached form ("--no-walk X" as opposed to "--no-walk=X")
+                * not allowed, since the argument is optional.
+                */
+               if (!strcmp(arg + 10, "sorted"))
+                       revs->no_walk = REVISION_WALK_NO_WALK_SORTED;
+               else if (!strcmp(arg + 10, "unsorted"))
+                       revs->no_walk = REVISION_WALK_NO_WALK_UNSORTED;
+               else
+                       return error("invalid argument to --no-walk");
        } else if (!strcmp(arg, "--do-walk")) {
                revs->no_walk = 0;
        } else {
@@ -1861,8 +1886,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
        if (revs->combine_merges)
                revs->ignore_merges = 0;
        revs->diffopt.abbrev = revs->abbrev;
-       if (diff_setup_done(&revs->diffopt) < 0)
-               die("diff_setup_done failed");
+       diff_setup_done(&revs->diffopt);
 
        compile_grep_patterns(&revs->grep_filter);
 
@@ -2116,10 +2140,11 @@ int prepare_revision_walk(struct rev_info *revs)
                }
                e++;
        }
-       commit_list_sort_by_date(&revs->commits);
        if (!revs->leak_pending)
                free(list);
 
+       if (revs->no_walk != REVISION_WALK_NO_WALK_UNSORTED)
+               commit_list_sort_by_date(&revs->commits);
        if (revs->no_walk)
                return 0;
        if (revs->limited)
index cb5ab3513bc9982095e292119b9119d333556256..a95bd0b3f3026068046d469a74d1a2d85e50e314 100644 (file)
@@ -41,6 +41,10 @@ struct rev_cmdline_info {
        } *rev;
 };
 
+#define REVISION_WALK_WALK 0
+#define REVISION_WALK_NO_WALK_SORTED 1
+#define REVISION_WALK_NO_WALK_UNSORTED 2
+
 struct rev_info {
        /* Starting list */
        struct commit_list *commits;
@@ -62,7 +66,7 @@ struct rev_info {
        /* Traversal flags */
        unsigned int    dense:1,
                        prune:1,
-                       no_walk:1,
+                       no_walk:2,
                        show_all:1,
                        remove_empty_trees:1,
                        simplify_history:1,
index 606791dc674a1d24459d85504f0c981634b52020..f9922b9ecc8e4956e19d7143bb6cb6ef4d97abf8 100644 (file)
@@ -139,6 +139,8 @@ int sane_execvp(const char *file, char * const argv[])
         */
        if (errno == EACCES && !strchr(file, '/'))
                errno = exists_in_PATH(file) ? EACCES : ENOENT;
+       else if (errno == ENOTDIR && !strchr(file, '/'))
+               errno = ENOENT;
        return -1;
 }
 
index bf078f274bfe23997fcd1bc8c2a1c958f39ac9fe..bd626806d64b9cd9a814f062d092501315546bdf 100644 (file)
@@ -543,7 +543,11 @@ static int do_pick_commit(struct commit *commit, struct replay_opts *opts)
 
 static void prepare_revs(struct replay_opts *opts)
 {
-       if (opts->action != REPLAY_REVERT)
+       /*
+        * picking (but not reverting) ranges (but not individual revisions)
+        * should be done in reverse
+        */
+       if (opts->action == REPLAY_PICK && !opts->revs->no_walk)
                opts->revs->reverse ^= 1;
 
        if (prepare_revision_walk(opts->revs))
diff --git a/setup.c b/setup.c
index 9139beefc75c4fe92cf8c7dc54a9fae972995aca..3a1b2fd45580cad7ecd55efa755872efc81075ad 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -79,7 +79,7 @@ static void NORETURN die_verify_filename(const char *prefix,
 {
        if (!diagnose_misspelt_rev)
                die("%s: no such path in the working tree.\n"
-                   "Use '-- <path>...' to specify paths that do not exist locally.",
+                   "Use 'git <command> -- <path>...' to specify paths that do not exist locally.",
                    arg);
        /*
         * Saying "'(icase)foo' does not exist in the index" when the
@@ -92,7 +92,8 @@ static void NORETURN die_verify_filename(const char *prefix,
 
        /* ... or fall back the most general message. */
        die("ambiguous argument '%s': unknown revision or path not in the working tree.\n"
-           "Use '--' to separate paths from revisions", arg);
+           "Use '--' to separate paths from revisions, like this:\n"
+           "'git <command> [<revision>...] -- [<file>...]'", arg);
 
 }
 
@@ -141,7 +142,8 @@ void verify_non_filename(const char *prefix, const char *arg)
        if (!check_filename(prefix, arg))
                return;
        die("ambiguous argument '%s': both revision and filename\n"
-           "Use '--' to separate filenames from revisions", arg);
+           "Use '--' to separate paths from revisions, like this:\n"
+           "'git <command> [<revision>...] -- [<file>...]'", arg);
 }
 
 /*
index af5cfbde63aed41d95ac7318d064d3012832d2c5..9152974642986de2307ec4ed6beda4efa49e8383 100644 (file)
@@ -731,6 +731,24 @@ void free_pack_by_name(const char *pack_name)
        }
 }
 
+static unsigned int get_max_fd_limit(void)
+{
+#ifdef RLIMIT_NOFILE
+       struct rlimit lim;
+
+       if (getrlimit(RLIMIT_NOFILE, &lim))
+               die_errno("cannot get RLIMIT_NOFILE");
+
+       return lim.rlim_cur;
+#elif defined(_SC_OPEN_MAX)
+       return sysconf(_SC_OPEN_MAX);
+#elif defined(OPEN_MAX)
+       return OPEN_MAX;
+#else
+       return 1; /* see the caller ;-) */
+#endif
+}
+
 /*
  * Do not call this directly as this leaks p->pack_fd on error return;
  * call open_packed_git() instead.
@@ -747,13 +765,7 @@ static int open_packed_git_1(struct packed_git *p)
                return error("packfile %s index unavailable", p->pack_name);
 
        if (!pack_max_fds) {
-               struct rlimit lim;
-               unsigned int max_fds;
-
-               if (getrlimit(RLIMIT_NOFILE, &lim))
-                       die_errno("cannot get RLIMIT_NOFILE");
-
-               max_fds = lim.rlim_cur;
+               unsigned int max_fds = get_max_fd_limit();
 
                /* Save 3 for stdin/stdout/stderr, 22 for work */
                if (25 < max_fds)
index 959d349ea7426344289020ee4216785fa65ec1e6..19dc6a6c0d5cf7d9a4c80c61e160290b4462665d 100644 (file)
@@ -574,8 +574,7 @@ static void calculate_changed_submodule_paths(void)
                        DIFF_OPT_SET(&diff_opts, RECURSIVE);
                        diff_opts.output_format |= DIFF_FORMAT_CALLBACK;
                        diff_opts.format_callback = submodule_collect_changed_cb;
-                       if (diff_setup_done(&diff_opts) < 0)
-                               die("diff_setup_done failed");
+                       diff_setup_done(&diff_opts);
                        diff_tree_sha1(parent->item->object.sha1, commit->object.sha1, "", &diff_opts);
                        diffcore_std(&diff_opts);
                        diff_flush(&diff_opts);
index 4c3ea25e6649007c9dde7ae4570d6311824051b6..e4128e5769722473f7fd1024fdf8a5100bd8ccf6 100644 (file)
--- a/t/README
+++ b/t/README
@@ -625,6 +625,15 @@ use these, and "test_set_prereq" for how to define your own.
    Git was compiled with USE_LIBPCRE=YesPlease. Wrap any tests
    that use git-grep --perl-regexp or git-grep -P in these.
 
+ - CASE_INSENSITIVE_FS
+
+   Test is run on a case insensitive file system.
+
+ - UTF8_NFD_TO_NFC
+
+   Test is run on a filesystem which converts decomposed utf-8 (nfd)
+   to precomposed utf-8 (nfc).
+
 Tips for Writing Tests
 ----------------------
 
index d773542680d9f3c3d77e52871877560a9e545a26..02f442bfadbb1239785a456cddc50223da4f3834 100644 (file)
@@ -167,3 +167,42 @@ test_http_push_nonff() {
                test_i18ngrep "Updates were rejected because" output
        '
 }
+
+setup_askpass_helper() {
+       test_expect_success 'setup askpass helper' '
+               write_script "$TRASH_DIRECTORY/askpass" <<-\EOF &&
+               echo >>"$TRASH_DIRECTORY/askpass-query" "askpass: $*" &&
+               cat "$TRASH_DIRECTORY/askpass-response"
+               EOF
+               GIT_ASKPASS="$TRASH_DIRECTORY/askpass" &&
+               export GIT_ASKPASS &&
+               export TRASH_DIRECTORY
+       '
+}
+
+set_askpass() {
+       >"$TRASH_DIRECTORY/askpass-query" &&
+       echo "$*" >"$TRASH_DIRECTORY/askpass-response"
+}
+
+expect_askpass() {
+       dest=$HTTPD_DEST
+       {
+               case "$1" in
+               none)
+                       ;;
+               pass)
+                       echo "askpass: Password for 'http://$2@$dest': "
+                       ;;
+               both)
+                       echo "askpass: Username for 'http://$dest': "
+                       echo "askpass: Password for 'http://$2@$dest': "
+                       ;;
+               *)
+                       false
+                       ;;
+               esac
+       } >"$TRASH_DIRECTORY/askpass-expect" &&
+       test_cmp "$TRASH_DIRECTORY/askpass-expect" \
+                "$TRASH_DIRECTORY/askpass-query"
+}
index 36b1596a10c04b5c5c095e96e8e247463eb3f022..49d5d877ceeeba3738b0939f14d059c2a75ff3ae 100644 (file)
@@ -46,24 +46,22 @@ PassEnv GIT_VALGRIND
 PassEnv GIT_VALGRIND_OPTIONS
 
 Alias /dumb/ www/
-Alias /auth/ www/auth/
+Alias /auth/dumb/ www/auth/dumb/
 
-<Location /smart/>
+<LocationMatch /smart/>
        SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
        SetEnv GIT_HTTP_EXPORT_ALL
-</Location>
-<Location /smart_noexport/>
+</LocationMatch>
+<LocationMatch /smart_noexport/>
        SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
-</Location>
-<Location /smart_custom_env/>
+</LocationMatch>
+<LocationMatch /smart_custom_env/>
        SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH}
        SetEnv GIT_HTTP_EXPORT_ALL
        SetEnv GIT_COMMITTER_NAME "Custom User"
        SetEnv GIT_COMMITTER_EMAIL custom@example.com
-</Location>
-ScriptAlias /smart/ ${GIT_EXEC_PATH}/git-http-backend/
-ScriptAlias /smart_noexport/ ${GIT_EXEC_PATH}/git-http-backend/
-ScriptAlias /smart_custom_env/ ${GIT_EXEC_PATH}/git-http-backend/
+</LocationMatch>
+ScriptAliasMatch /smart_*[^/]*/(.*) ${GIT_EXEC_PATH}/git-http-backend/$1
 <Directory ${GIT_EXEC_PATH}>
        Options FollowSymlinks
 </Directory>
@@ -94,6 +92,13 @@ SSLEngine On
        Require valid-user
 </Location>
 
+<LocationMatch "^/auth-push/.*/git-receive-pack$">
+       AuthType Basic
+       AuthName "git-auth"
+       AuthUserFile passwd
+       Require valid-user
+</LocationMatch>
+
 <IfDefine DAV>
        LoadModule dav_module modules/mod_dav.so
        LoadModule dav_fs_module modules/mod_dav_fs.so
index 50f5cc1ed901e5abd7839dcb58ff94aa96a9c641..982eb8e3a949a74e5c26a952a33364c25f6f5b74 100644 (file)
@@ -1,2 +1,3 @@
-build/
-test-results/
+/build/
+/test-results/
+/trash directory*/
index 51f3045ba4bde549b06ea669b1877f0e2db7c401..febc45c9cc6f34a606ebac8470e582efad798148 100755 (executable)
@@ -123,16 +123,6 @@ test_expect_success 'attribute matching is case insensitive when core.ignorecase
 
 '
 
-test_expect_success 'check whether FS is case-insensitive' '
-       mkdir junk &&
-       echo good >junk/CamelCase &&
-       echo bad >junk/camelcase &&
-       if test "$(cat junk/CamelCase)" != good
-       then
-               test_set_prereq CASE_INSENSITIVE_FS
-       fi
-'
-
 test_expect_success CASE_INSENSITIVE_FS 'additional case insensitivity tests' '
        test_must_fail attr_check a/B/D/g "a/b/d/*" "-c core.ignorecase=0" &&
        test_must_fail attr_check A/B/D/NO "a/b/d/*" "-c core.ignorecase=0" &&
index 1542cf6a1313963fccdf42702c620be9e05f7143..78816d9d935df478f5cdf93e06fae26cc5488910 100755 (executable)
@@ -7,48 +7,26 @@ test_description='Various filesystem issues'
 auml=$(printf '\303\244')
 aumlcdiar=$(printf '\141\314\210')
 
-case_insensitive=
-unibad=
-no_symlinks=
-test_expect_success 'see what we expect' '
-
-       test_case=test_expect_success &&
-       test_unicode=test_expect_success &&
-       mkdir junk &&
-       echo good >junk/CamelCase &&
-       echo bad >junk/camelcase &&
-       if test "$(cat junk/CamelCase)" != good
-       then
-               test_case=test_expect_failure &&
-               case_insensitive=t
-       fi &&
-       rm -fr junk &&
-       mkdir junk &&
-       >junk/"$auml" &&
-       case "$(cd junk && echo *)" in
-       "$aumlcdiar")
-               test_unicode=test_expect_failure &&
-               unibad=t
-               ;;
-       *)      ;;
-       esac &&
-       rm -fr junk &&
-       {
-               ln -s x y 2> /dev/null &&
-               test -h y 2> /dev/null ||
-               no_symlinks=1 &&
-               rm -f y
-       }
-'
-
-test "$case_insensitive" &&
+if test_have_prereq CASE_INSENSITIVE_FS
+then
        say "will test on a case insensitive filesystem"
-test "$unibad" &&
+       test_case=test_expect_failure
+else
+       test_case=test_expect_success
+fi
+
+if test_have_prereq UTF8_NFD_TO_NFC
+then
        say "will test on a unicode corrupting filesystem"
-test "$no_symlinks" &&
+       test_unicode=test_expect_failure
+else
+       test_unicode=test_expect_success
+fi
+
+test_have_prereq SYMLINKS ||
        say "will test on a filesystem lacking symbolic links"
 
-if test "$case_insensitive"
+if test_have_prereq CASE_INSENSITIVE_FS
 then
 test_expect_success "detection of case insensitive filesystem during repo init" '
 
@@ -62,18 +40,18 @@ test_expect_success "detection of case insensitive filesystem during repo init"
 '
 fi
 
-if test "$no_symlinks"
+if test_have_prereq SYMLINKS
 then
 test_expect_success "detection of filesystem w/o symlink support during repo init" '
 
-       v=$(git config --bool core.symlinks) &&
-       test "$v" = false
+       test_must_fail git config --bool core.symlinks ||
+       test "$(git config --bool core.symlinks)" = true
 '
 else
 test_expect_success "detection of filesystem w/o symlink support during repo init" '
 
-       test_must_fail git config --bool core.symlinks ||
-       test "$(git config --bool core.symlinks)" = true
+       v=$(git config --bool core.symlinks) &&
+       test "$v" = false
 '
 fi
 
index 9bee8bfd2e063c40bae2d76930370bd9e8ba8fa5..da2c504e53e37840f71790d6b262106b7b57d697 100755 (executable)
@@ -25,4 +25,9 @@ test_expect_success POSIXPERM 'mktemp to unwritable directory prints filename' '
        grep "cannotwrite/test" err
 '
 
+test_expect_success 'check for a bug in the regex routines' '
+       # if this test fails, re-build git with NO_REGEX=1
+       test-regex
+'
+
 test_done
index 5b79c51b8c51b3fc62823e1b51f9087fbd7f30e3..bf7a2cd6fb649e3b210b537d4d25312ba2921f16 100755 (executable)
@@ -213,4 +213,30 @@ test_expect_success 'rev-list --verify-objects with bad sha1' '
        grep -q "error: sha1 mismatch 63ffffffffffffffffffffffffffffffffffffff" out
 '
 
+_bz='\0'
+_bz5="$_bz$_bz$_bz$_bz$_bz"
+_bz20="$_bz5$_bz5$_bz5$_bz5"
+
+test_expect_success 'fsck notices blob entry pointing to null sha1' '
+       (git init null-blob &&
+        cd null-blob &&
+        sha=$(printf "100644 file$_bz$_bz20" |
+              git hash-object -w --stdin -t tree) &&
+         git fsck 2>out &&
+         cat out &&
+         grep "warning.*null sha1" out
+       )
+'
+
+test_expect_success 'fsck notices submodule entry pointing to null sha1' '
+       (git init null-commit &&
+        cd null-commit &&
+        sha=$(printf "160000 submodule$_bz$_bz20" |
+              git hash-object -w --stdin -t tree) &&
+         git fsck 2>out &&
+         cat out &&
+         grep "warning.*null sha1" out
+       )
+'
+
 test_done
index c5cb77a0e1f34ac46dd8727341948389624e8f38..f950c101287c2f05bbd70c1faffbcf2cda1edbee 100755 (executable)
@@ -182,4 +182,18 @@ test_expect_success '<commit>:file correctly diagnosed after a pathname' '
        test_cmp expect actual
 '
 
+test_expect_success 'dotdot is not an empty set' '
+       ( H=$(git rev-parse HEAD) && echo $H && echo ^$H ) >expect &&
+
+       git rev-parse HEAD.. >actual &&
+       test_cmp expect actual &&
+
+       git rev-parse ..HEAD >actual &&
+       test_cmp expect actual &&
+
+       echo .. >expect &&
+       git rev-parse .. >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 809fafe208cbf68121295922a4c230b2a5e1aee3..0dbbb00d740da8b1e62325c7daea659bb97eb399 100755 (executable)
@@ -29,4 +29,23 @@ test_expect_success 'update-index -h with corrupt index' '
        grep "[Uu]sage: git update-index" broken/usage
 '
 
+test_expect_success '--cacheinfo does not accept blob null sha1' '
+       echo content >file &&
+       git add file &&
+       git rev-parse :file >expect &&
+       test_must_fail git update-index --cacheinfo 100644 $_z40 file &&
+       git rev-parse :file >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '--cacheinfo does not accept gitlink null sha1' '
+       git init submodule &&
+       (cd submodule && test_commit foo) &&
+       git add submodule &&
+       git rev-parse :submodule >expect &&
+       test_must_fail git update-index --cacheinfo 160000 $_z40 submodule &&
+       git rev-parse :submodule >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 7f8693b928fdb827906f7c51ec0a13b2f36c5b83..58f482378392c8c358a3129094885f90ead9808c 100755 (executable)
@@ -47,7 +47,23 @@ test_expect_success 'rebase ignores empty commit' '
        git commit --allow-empty -m empty &&
        test_commit D &&
        git rebase C &&
-       test $(git log --format=%s C..) = "D"
+       test "$(git log --format=%s C..)" = "D"
+'
+
+test_expect_success 'rebase --keep-empty' '
+       git reset --hard D &&
+       git rebase --keep-empty C &&
+       test "$(git log --format=%s C..)" = "D
+empty"
+'
+
+test_expect_success 'rebase --keep-empty keeps empty even if already in upstream' '
+       git reset --hard A &&
+       git commit --allow-empty -m also-empty &&
+       git rebase --keep-empty D &&
+       test "$(git log --format=%s A..)" = "also-empty
+D
+empty"
 '
 
 test_done
index 75f7ff4f2fe21e86e0a26fe5a6c2119bef38404c..340afc760de030879fff496dca3db8432a6b992b 100755 (executable)
@@ -44,6 +44,21 @@ test_expect_success 'cherry-pick first..fourth works' '
        check_head_differs_from fourth
 '
 
+test_expect_success 'cherry-pick three one two works' '
+       git checkout -f first &&
+       test_commit one &&
+       test_commit two &&
+       test_commit three &&
+       git checkout -f master &&
+       git reset --hard first &&
+       git cherry-pick three one two &&
+       git diff --quiet three &&
+       git diff --quiet HEAD three &&
+       test "$(git log --reverse --format=%s first..)" = "three
+one
+two"
+'
+
 test_expect_success 'output to keep user entertained during multi-pick' '
        cat <<-\EOF >expected &&
        [master OBJID] second
index 88b7a20c112a523b9c6640d778ac2840ce9adeb4..5fe57c5438e72150639fd6b970471a1689d30911 100755 (executable)
@@ -7,158 +7,147 @@ test_description='utf-8 decomposed (nfd) converted to precomposed (nfc)'
 
 . ./test-lib.sh
 
+if ! test_have_prereq UTF8_NFD_TO_NFC
+then
+       skip_all="filesystem does not corrupt utf-8"
+       test_done
+fi
+
+# create utf-8 variables
 Adiarnfc=`printf '\303\204'`
 Adiarnfd=`printf 'A\314\210'`
 
-# check if the feature is compiled in
-mkdir junk &&
->junk/"$Adiarnfc" &&
-case "$(cd junk && echo *)" in
-       "$Adiarnfd")
-       test_nfd=1
-       ;;
-       *)      ;;
-esac
-rm -rf junk
+Odiarnfc=`printf '\303\226'`
+Odiarnfd=`printf 'O\314\210'`
+AEligatu=`printf '\303\206'`
+Invalidu=`printf '\303\377'`
 
 
-if test "$test_nfd"
-then
-       # create more utf-8 variables
-       Odiarnfc=`printf '\303\226'`
-       Odiarnfd=`printf 'O\314\210'`
-       AEligatu=`printf '\303\206'`
-       Invalidu=`printf '\303\377'`
+#Create a string with 255 bytes (decomposed)
+Alongd=$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd #21 Byte
+Alongd=$Alongd$Alongd$Alongd                                           #63 Byte
+Alongd=$Alongd$Alongd$Alongd$Alongd$Adiarnfd                           #255 Byte
 
+#Create a string with 254 bytes (precomposed)
+Alongc=$AEligatu$AEligatu$AEligatu$AEligatu$AEligatu #10 Byte
+Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc           #50 Byte
+Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc           #250 Byte
+Alongc=$Alongc$AEligatu$AEligatu                     #254 Byte
 
-       #Create a string with 255 bytes (decomposed)
-       Alongd=$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd$Adiarnfd #21 Byte
-       Alongd=$Alongd$Alongd$Alongd                                           #63 Byte
-       Alongd=$Alongd$Alongd$Alongd$Alongd$Adiarnfd                           #255 Byte
-
-       #Create a string with 254 bytes (precomposed)
-       Alongc=$AEligatu$AEligatu$AEligatu$AEligatu$AEligatu #10 Byte
-       Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc           #50 Byte
-       Alongc=$Alongc$Alongc$Alongc$Alongc$Alongc           #250 Byte
-       Alongc=$Alongc$AEligatu$AEligatu                     #254 Byte
-
-       test_expect_success "detect if nfd needed" '
-               precomposeunicode=`git config core.precomposeunicode` &&
-               test "$precomposeunicode" = false &&
-               git config core.precomposeunicode true
-       '
-       test_expect_success "setup" '
-               >x &&
-               git add x &&
-               git commit -m "1st commit" &&
-               git rm x &&
-               git commit -m "rm x"
-       '
-       test_expect_success "setup case mac" '
-               git checkout -b mac_os
-       '
-       # This will test nfd2nfc in readdir()
-       test_expect_success "add file Adiarnfc" '
-               echo f.Adiarnfc >f.$Adiarnfc &&
-               git add f.$Adiarnfc &&
-               git commit -m "add f.$Adiarnfc"
-       '
-       # This will test nfd2nfc in git stage()
-       test_expect_success "stage file d.Adiarnfd/f.Adiarnfd" '
-               mkdir d.$Adiarnfd &&
-               echo d.$Adiarnfd/f.$Adiarnfd >d.$Adiarnfd/f.$Adiarnfd &&
-               git stage d.$Adiarnfd/f.$Adiarnfd &&
-               git commit -m "add d.$Adiarnfd/f.$Adiarnfd"
-       '
-       test_expect_success "add link Adiarnfc" '
-               ln -s d.$Adiarnfd/f.$Adiarnfd l.$Adiarnfc &&
-               git add l.$Adiarnfc &&
-               git commit -m "add l.Adiarnfc"
-       '
-       # This will test git log
-       test_expect_success "git log f.Adiar" '
-               git log f.$Adiarnfc > f.Adiarnfc.log &&
-               git log f.$Adiarnfd > f.Adiarnfd.log &&
-               test -s f.Adiarnfc.log &&
-               test -s f.Adiarnfd.log &&
-               test_cmp f.Adiarnfc.log f.Adiarnfd.log &&
-               rm f.Adiarnfc.log f.Adiarnfd.log
-       '
-       # This will test git ls-files
-       test_expect_success "git lsfiles f.Adiar" '
-               git ls-files f.$Adiarnfc > f.Adiarnfc.log &&
-               git ls-files f.$Adiarnfd > f.Adiarnfd.log &&
-               test -s f.Adiarnfc.log &&
-               test -s f.Adiarnfd.log &&
-               test_cmp f.Adiarnfc.log f.Adiarnfd.log &&
-               rm f.Adiarnfc.log f.Adiarnfd.log
-       '
-       # This will test git mv
-       test_expect_success "git mv" '
-               git mv f.$Adiarnfd f.$Odiarnfc &&
-               git mv d.$Adiarnfd d.$Odiarnfc &&
-               git mv l.$Adiarnfd l.$Odiarnfc &&
-               git commit -m "mv Adiarnfd Odiarnfc"
-       '
-       # Files can be checked out as nfc
-       # And the link has been corrected from nfd to nfc
-       test_expect_success "git checkout nfc" '
-               rm f.$Odiarnfc &&
-               git checkout f.$Odiarnfc
-       '
-       # Make it possible to checkout files with their NFD names
-       test_expect_success "git checkout file nfd" '
-               rm -f f.* &&
-               git checkout f.$Odiarnfd
-       '
-       # Make it possible to checkout links with their NFD names
-       test_expect_success "git checkout link nfd" '
-               rm l.* &&
-               git checkout l.$Odiarnfd
-       '
-       test_expect_success "setup case mac2" '
-               git checkout master &&
-               git reset --hard &&
-               git checkout -b mac_os_2
-       '
-       # This will test nfd2nfc in git commit
-       test_expect_success "commit file d2.Adiarnfd/f.Adiarnfd" '
-               mkdir d2.$Adiarnfd &&
-               echo d2.$Adiarnfd/f.$Adiarnfd >d2.$Adiarnfd/f.$Adiarnfd &&
-               git add d2.$Adiarnfd/f.$Adiarnfd &&
-               git commit -m "add d2.$Adiarnfd/f.$Adiarnfd" -- d2.$Adiarnfd/f.$Adiarnfd
-       '
-       test_expect_success "setup for long decomposed filename" '
-               git checkout master &&
-               git reset --hard &&
-               git checkout -b mac_os_long_nfd_fn
-       '
-       test_expect_success "Add long decomposed filename" '
-               echo longd >$Alongd &&
-               git add * &&
-               git commit -m "Long filename"
-       '
-       test_expect_success "setup for long precomposed filename" '
-               git checkout master &&
-               git reset --hard &&
-               git checkout -b mac_os_long_nfc_fn
-       '
-       test_expect_success "Add long precomposed filename" '
-               echo longc >$Alongc &&
-               git add * &&
-               git commit -m "Long filename"
-       '
-       # Test if the global core.precomposeunicode stops autosensing
-       # Must be the last test case
-       test_expect_success "respect git config --global core.precomposeunicode" '
-               git config --global core.precomposeunicode true &&
-               rm -rf .git &&
-               git init &&
-               precomposeunicode=`git config core.precomposeunicode` &&
-               test "$precomposeunicode" = "true"
-       '
-else
-        say "Skipping nfc/nfd tests"
-fi
+test_expect_success "detect if nfd needed" '
+       precomposeunicode=`git config core.precomposeunicode` &&
+       test "$precomposeunicode" = false &&
+       git config core.precomposeunicode true
+'
+test_expect_success "setup" '
+       >x &&
+       git add x &&
+       git commit -m "1st commit" &&
+       git rm x &&
+       git commit -m "rm x"
+'
+test_expect_success "setup case mac" '
+       git checkout -b mac_os
+'
+# This will test nfd2nfc in readdir()
+test_expect_success "add file Adiarnfc" '
+       echo f.Adiarnfc >f.$Adiarnfc &&
+       git add f.$Adiarnfc &&
+       git commit -m "add f.$Adiarnfc"
+'
+# This will test nfd2nfc in git stage()
+test_expect_success "stage file d.Adiarnfd/f.Adiarnfd" '
+       mkdir d.$Adiarnfd &&
+       echo d.$Adiarnfd/f.$Adiarnfd >d.$Adiarnfd/f.$Adiarnfd &&
+       git stage d.$Adiarnfd/f.$Adiarnfd &&
+       git commit -m "add d.$Adiarnfd/f.$Adiarnfd"
+'
+test_expect_success "add link Adiarnfc" '
+       ln -s d.$Adiarnfd/f.$Adiarnfd l.$Adiarnfc &&
+       git add l.$Adiarnfc &&
+       git commit -m "add l.Adiarnfc"
+'
+# This will test git log
+test_expect_success "git log f.Adiar" '
+       git log f.$Adiarnfc > f.Adiarnfc.log &&
+       git log f.$Adiarnfd > f.Adiarnfd.log &&
+       test -s f.Adiarnfc.log &&
+       test -s f.Adiarnfd.log &&
+       test_cmp f.Adiarnfc.log f.Adiarnfd.log &&
+       rm f.Adiarnfc.log f.Adiarnfd.log
+'
+# This will test git ls-files
+test_expect_success "git lsfiles f.Adiar" '
+       git ls-files f.$Adiarnfc > f.Adiarnfc.log &&
+       git ls-files f.$Adiarnfd > f.Adiarnfd.log &&
+       test -s f.Adiarnfc.log &&
+       test -s f.Adiarnfd.log &&
+       test_cmp f.Adiarnfc.log f.Adiarnfd.log &&
+       rm f.Adiarnfc.log f.Adiarnfd.log
+'
+# This will test git mv
+test_expect_success "git mv" '
+       git mv f.$Adiarnfd f.$Odiarnfc &&
+       git mv d.$Adiarnfd d.$Odiarnfc &&
+       git mv l.$Adiarnfd l.$Odiarnfc &&
+       git commit -m "mv Adiarnfd Odiarnfc"
+'
+# Files can be checked out as nfc
+# And the link has been corrected from nfd to nfc
+test_expect_success "git checkout nfc" '
+       rm f.$Odiarnfc &&
+       git checkout f.$Odiarnfc
+'
+# Make it possible to checkout files with their NFD names
+test_expect_success "git checkout file nfd" '
+       rm -f f.* &&
+       git checkout f.$Odiarnfd
+'
+# Make it possible to checkout links with their NFD names
+test_expect_success "git checkout link nfd" '
+       rm l.* &&
+       git checkout l.$Odiarnfd
+'
+test_expect_success "setup case mac2" '
+       git checkout master &&
+       git reset --hard &&
+       git checkout -b mac_os_2
+'
+# This will test nfd2nfc in git commit
+test_expect_success "commit file d2.Adiarnfd/f.Adiarnfd" '
+       mkdir d2.$Adiarnfd &&
+       echo d2.$Adiarnfd/f.$Adiarnfd >d2.$Adiarnfd/f.$Adiarnfd &&
+       git add d2.$Adiarnfd/f.$Adiarnfd &&
+       git commit -m "add d2.$Adiarnfd/f.$Adiarnfd" -- d2.$Adiarnfd/f.$Adiarnfd
+'
+test_expect_success "setup for long decomposed filename" '
+       git checkout master &&
+       git reset --hard &&
+       git checkout -b mac_os_long_nfd_fn
+'
+test_expect_success "Add long decomposed filename" '
+       echo longd >$Alongd &&
+       git add * &&
+       git commit -m "Long filename"
+'
+test_expect_success "setup for long precomposed filename" '
+       git checkout master &&
+       git reset --hard &&
+       git checkout -b mac_os_long_nfc_fn
+'
+test_expect_success "Add long precomposed filename" '
+       echo longc >$Alongc &&
+       git add * &&
+       git commit -m "Long filename"
+'
+# Test if the global core.precomposeunicode stops autosensing
+# Must be the last test case
+test_expect_success "respect git config --global core.precomposeunicode" '
+       git config --global core.precomposeunicode true &&
+       rm -rf .git &&
+       git init &&
+       precomposeunicode=`git config core.precomposeunicode` &&
+       test "$precomposeunicode" = "true"
+'
 
 test_done
index c00a94b9ba4498e72a31856aac9cf653bbce8ba3..2d030a4ec35009105c26e9689dcae1150fed7b2d 100755 (executable)
@@ -66,5 +66,35 @@ test_expect_success 'suppress deletion diff with -B -D' '
        grep -v "Linus Torvalds" actual
 '
 
+test_expect_success 'prepare a file that ends with an incomplete line' '
+       test_seq 1 99 >seq &&
+       printf 100 >>seq &&
+       git add seq &&
+       git commit seq -m seq
+'
+
+test_expect_success 'rewrite the middle 90% of sequence file and terminate with newline' '
+       test_seq 1 5 >seq &&
+       test_seq 9331 9420 >>seq &&
+       test_seq 96 100 >>seq
+'
+
+test_expect_success 'confirm that sequence file is considered a rewrite' '
+       git diff -B seq >res &&
+       grep "dissimilarity index" res
+'
+
+test_expect_success 'no newline at eof is on its own line without -B' '
+       git diff seq >res &&
+       grep "^\\\\ " res &&
+       ! grep "^..*\\\\ " res
+'
+
+test_expect_success 'no newline at eof is on its own line with -B' '
+       git diff -B seq >res &&
+       grep "^\\\\ " res &&
+       ! grep "^..*\\\\ " res
+'
+
 test_done
 
diff --git a/t/t4054-diff-bogus-tree.sh b/t/t4054-diff-bogus-tree.sh
new file mode 100755 (executable)
index 0000000..0843c87
--- /dev/null
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+test_description='test diff with a bogus tree containing the null sha1'
+. ./test-lib.sh
+
+empty_tree=4b825dc642cb6eb9a060e54bf8d69288fbee4904
+
+test_expect_success 'create bogus tree' '
+       bogus_tree=$(
+               printf "100644 fooQQQQQQQQQQQQQQQQQQQQQ" |
+               q_to_nul |
+               git hash-object -w --stdin -t tree
+       )
+'
+
+test_expect_success 'create tree with matching file' '
+       echo bar >foo &&
+       git add foo &&
+       good_tree=$(git write-tree)
+       blob=$(git rev-parse :foo)
+'
+
+test_expect_success 'raw diff shows null sha1 (addition)' '
+       echo ":000000 100644 $_z40 $_z40 A      foo" >expect &&
+       git diff-tree $empty_tree $bogus_tree >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'raw diff shows null sha1 (removal)' '
+       echo ":100644 000000 $_z40 $_z40 D      foo" >expect &&
+       git diff-tree $bogus_tree $empty_tree >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'raw diff shows null sha1 (modification)' '
+       echo ":100644 100644 $blob $_z40 M      foo" >expect &&
+       git diff-tree $good_tree $bogus_tree >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'raw diff shows null sha1 (other direction)' '
+       echo ":100644 100644 $_z40 $blob M      foo" >expect &&
+       git diff-tree $bogus_tree $good_tree >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'raw diff shows null sha1 (reverse)' '
+       echo ":100644 100644 $_z40 $blob M      foo" >expect &&
+       git diff-tree -R $good_tree $bogus_tree >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'raw diff shows null sha1 (index)' '
+       echo ":100644 100644 $_z40 $blob M      foo" >expect &&
+       git diff-index $bogus_tree >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'patch fails due to bogus sha1 (addition)' '
+       test_must_fail git diff-tree -p $empty_tree $bogus_tree
+'
+
+test_expect_success 'patch fails due to bogus sha1 (removal)' '
+       test_must_fail git diff-tree -p $bogus_tree $empty_tree
+'
+
+test_expect_success 'patch fails due to bogus sha1 (modification)' '
+       test_must_fail git diff-tree -p $good_tree $bogus_tree
+'
+
+test_expect_success 'patch fails due to bogus sha1 (other direction)' '
+       test_must_fail git diff-tree -p $bogus_tree $good_tree
+'
+
+test_expect_success 'patch fails due to bogus sha1 (reverse)' '
+       test_must_fail git diff-tree -R -p $good_tree $bogus_tree
+'
+
+test_expect_success 'patch fails due to bogus sha1 (index)' '
+       test_must_fail git diff-index -p $bogus_tree
+'
+
+test_done
index 99627bc6d69f17a8dce0ad318764e32cd9d9f507..b1b906b1bb58ad9f96ee8f6146a2d49ec999e3f2 100755 (executable)
@@ -8,30 +8,28 @@ test_description='git apply handling binary patches
 '
 . ./test-lib.sh
 
-# setup
-
-cat >file1 <<EOF
-A quick brown fox jumps over the lazy dog.
-A tiny little penguin runs around in circles.
-There is a flag with Linux written on it.
-A slow black-and-white panda just sits there,
-munching on his bamboo.
-EOF
-cat file1 >file2
-cat file1 >file4
-
-test_expect_success 'setup' "
+test_expect_success 'setup' '
+       cat >file1 <<-\EOF &&
+       A quick brown fox jumps over the lazy dog.
+       A tiny little penguin runs around in circles.
+       There is a flag with Linux written on it.
+       A slow black-and-white panda just sits there,
+       munching on his bamboo.
+       EOF
+       cat file1 >file2 &&
+       cat file1 >file4 &&
+
        git update-index --add --remove file1 file2 file4 &&
-       git commit -m 'Initial Version' 2>/dev/null &&
+       git commit -m "Initial Version" 2>/dev/null &&
 
        git checkout -b binary &&
-       "$PERL_PATH" -pe 'y/x/\000/' <file1 >file3 &&
+       "$PERL_PATH" -pe "y/x/\000/" <file1 >file3 &&
        cat file3 >file4 &&
        git add file2 &&
-       "$PERL_PATH" -pe 'y/\000/v/' <file3 >file1 &&
+       "$PERL_PATH" -pe "y/\000/v/" <file3 >file1 &&
        rm -f file2 &&
        git update-index --add --remove file1 file2 file3 file4 &&
-       git commit -m 'Second Version' &&
+       git commit -m "Second Version" &&
 
        git diff-tree -p master binary >B.diff &&
        git diff-tree -p -C master binary >C.diff &&
@@ -42,17 +40,25 @@ test_expect_success 'setup' "
        git diff-tree -p --full-index master binary >B-index.diff &&
        git diff-tree -p -C --full-index master binary >C-index.diff &&
 
+       git diff-tree -p --binary --no-prefix master binary -- file3 >B0.diff &&
+
        git init other-repo &&
-       (cd other-repo &&
-        git fetch .. master &&
-        git reset --hard FETCH_HEAD
+       (
+               cd other-repo &&
+               git fetch .. master &&
+               git reset --hard FETCH_HEAD
        )
-"
+'
 
 test_expect_success 'stat binary diff -- should not fail.' \
        'git checkout master &&
         git apply --stat --summary B.diff'
 
+test_expect_success 'stat binary -p0 diff -- should not fail.' '
+        git checkout master &&
+        git apply --stat -p0 B0.diff
+'
+
 test_expect_success 'stat binary diff (copy) -- should not fail.' \
        'git checkout master &&
         git apply --stat --summary C.diff'
@@ -143,4 +149,10 @@ test_expect_success 'apply binary diff (copy).' \
         git apply --allow-binary-replacement --index CF.diff &&
         test -z "$(git diff --name-status binary)"'
 
+test_expect_success 'apply binary -p0 diff' '
+       do_reset &&
+       git apply -p0 --index B0.diff &&
+       test -z "$(git diff --name-status binary -- file3)"
+'
+
 test_done
index 71be59d446f773c4b567f00c469ac26225d11cb8..b3ac6be3b0d2cc47af4559bcf7401ef858dae322 100755 (executable)
@@ -178,11 +178,21 @@ test_expect_success 'git log --no-walk <commits> sorts by commit time' '
        test_cmp expect actual
 '
 
+test_expect_success 'git log --no-walk=sorted <commits> sorts by commit time' '
+       git log --no-walk=sorted --oneline 5d31159 804a787 394ef78 > actual &&
+       test_cmp expect actual
+'
+
 cat > expect << EOF
 5d31159 fourth
 804a787 sixth
 394ef78 fifth
 EOF
+test_expect_success 'git log --no-walk=unsorted <commits> leaves list of commits as given' '
+       git log --no-walk=unsorted --oneline 5d31159 804a787 394ef78 > actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'git show <commits> leaves list of commits as given' '
        git show --oneline -s 5d31159 804a787 394ef78 > actual &&
        test_cmp expect actual
@@ -806,4 +816,11 @@ test_expect_success 'log --graph with diff and stats' '
        test_cmp expect actual.sanitized
 '
 
+test_expect_success 'dotdot is a parent directory' '
+       mkdir -p a/b &&
+       ( echo sixth && echo fifth ) >expect &&
+       ( cd a/b && git log --format=%s .. ) >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 0eace37a03d75a7205575c36a0ec0de3ec401b1b..250c720c14602bdf21e6a7200437b13fe6feaca3 100755 (executable)
@@ -145,6 +145,41 @@ test_expect_success 'push --all excludes remote-tracking hierarchy' '
        )
 '
 
+test_expect_success 'receive-pack runs auto-gc in remote repo' '
+       rm -rf parent child &&
+       git init parent &&
+       (
+           # Setup a repo with 2 packs
+           cd parent &&
+           echo "Some text" >file.txt &&
+           git add . &&
+           git commit -m "Initial commit" &&
+           git repack -adl &&
+           echo "Some more text" >>file.txt &&
+           git commit -a -m "Second commit" &&
+           git repack
+       ) &&
+       cp -a parent child &&
+       (
+           # Set the child to auto-pack if more than one pack exists
+           cd child &&
+           git config gc.autopacklimit 1 &&
+           git branch test_auto_gc &&
+           # And create a file that follows the temporary object naming
+           # convention for the auto-gc to remove
+           : >.git/objects/tmp_test_object &&
+           test-chmtime =-1209601 .git/objects/tmp_test_object
+       ) &&
+       (
+           cd parent &&
+           echo "Even more text" >>file.txt &&
+           git commit -a -m "Third commit" &&
+           git send-pack ../child HEAD:refs/heads/test_auto_gc >output 2>&1 &&
+           grep "Auto packing the repository for optimum performance." output
+       ) &&
+       test ! -e child/.git/objects/tmp_test_object
+'
+
 rewound_push_setup() {
        rm -rf parent child &&
        mkdir parent &&
index e8af615e6dcdf365416ef9f71825c17a0d601186..c03ffdde1036f37d35db0d8147af20ffdd79bbb1 100755 (executable)
@@ -125,7 +125,7 @@ EOF
        } &&
        git tag footag &&
        git config --add remote.oops.fetch "+refs/*:refs/*" &&
-       git remote rm oops 2>actual1 &&
+       git remote remove oops 2>actual1 &&
        git branch foobranch &&
        git config --add remote.oops.fetch "+refs/*:refs/*" &&
        git remote rm oops 2>actual2 &&
@@ -672,7 +672,7 @@ test_expect_success 'migrate a remote from named file in $GIT_DIR/remotes' '
        git clone one five &&
        origin_url=$(pwd)/one &&
        (cd five &&
-        git remote rm origin &&
+        git remote remove origin &&
         mkdir -p .git/remotes &&
         cat ../remotes_origin > .git/remotes/origin &&
         git remote rename origin origin &&
index 1eea64765608dc4a2e4b19eec4155890306e5d59..01d0d95b4d6476f691f650cc413fa7156caee88b 100755 (executable)
@@ -46,15 +46,7 @@ test_expect_success 'create password-protected repository' '
               "$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/test_repo.git"
 '
 
-test_expect_success 'setup askpass helper' '
-       cat >askpass <<-\EOF &&
-       #!/bin/sh
-       echo user@host
-       EOF
-       chmod +x askpass &&
-       GIT_ASKPASS="$PWD/askpass" &&
-       export GIT_ASKPASS
-'
+setup_askpass_helper
 
 test_expect_success 'clone remote repository' '
        cd "$ROOT_PATH" &&
@@ -117,7 +109,7 @@ test_expect_success 'http-push fetches packed objects' '
        # By reset, we force git to retrieve the packed object
        (cd "$ROOT_PATH"/test_repo_clone_packed &&
         git reset --hard HEAD^ &&
-        git remote rm origin &&
+        git remote remove origin &&
         git reflog expire --expire=0 --all &&
         git prune &&
         git push -f -v $HTTPD_URL/dumb/test_repo_packed.git master)
@@ -162,6 +154,7 @@ test_http_push_nonff "$HTTPD_DOCUMENT_ROOT_PATH"/test_repo.git \
 
 test_expect_success 'push to password-protected repository (user in URL)' '
        test_commit pw-user &&
+       set_askpass user@host &&
        git push "$HTTPD_URL_USER/auth/dumb/test_repo.git" HEAD &&
        git rev-parse --verify HEAD >expect &&
        git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/test_repo.git" \
@@ -169,9 +162,15 @@ test_expect_success 'push to password-protected repository (user in URL)' '
        test_cmp expect actual
 '
 
+test_expect_failure 'user was prompted only once for password' '
+       expect_askpass pass user@host
+'
+
 test_expect_failure 'push to password-protected repository (no user in URL)' '
        test_commit pw-nouser &&
+       set_askpass user@host &&
        git push "$HTTPD_URL/auth/dumb/test_repo.git" HEAD &&
+       expect_askpass both user@host
        git rev-parse --verify HEAD >expect &&
        git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/test_repo.git" \
                rev-parse --verify HEAD >actual &&
index 312e484090d1ceb392399768f2229ae553182fe7..ef6d6b6e4e1a06e31780cf2a4261a632f5779987 100755 (executable)
@@ -36,6 +36,8 @@ test_expect_success 'setup remote repository' '
        mv test_repo.git "$HTTPD_DOCUMENT_ROOT_PATH"
 '
 
+setup_askpass_helper
+
 cat >exp <<EOF
 GET  /smart/test_repo.git/info/refs?service=git-upload-pack HTTP/1.1 200
 POST /smart/test_repo.git/git-upload-pack HTTP/1.1 200
@@ -266,5 +268,29 @@ test_expect_success 'http push respects GIT_COMMITTER_* in reflog' '
        test_cmp expect actual
 '
 
+test_expect_success 'push over smart http with auth' '
+       cd "$ROOT_PATH/test_repo_clone" &&
+       echo push-auth-test >expect &&
+       test_commit push-auth-test &&
+       set_askpass user@host &&
+       git push "$HTTPD_URL"/auth/smart/test_repo.git &&
+       git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \
+               log -1 --format=%s >actual &&
+       expect_askpass both user@host &&
+       test_cmp expect actual
+'
+
+test_expect_success 'push to auth-only-for-push repo' '
+       cd "$ROOT_PATH/test_repo_clone" &&
+       echo push-half-auth >expect &&
+       test_commit push-half-auth &&
+       set_askpass user@host &&
+       git push "$HTTPD_URL"/auth-push/smart/test_repo.git &&
+       git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git" \
+               log -1 --format=%s >actual &&
+       expect_askpass both user@host &&
+       test_cmp expect actual
+'
+
 stop_httpd
 test_done
index b06f817af32483631b3ec297246e156400bc6b93..16ef0419e9e4ea8d42aebd63c5bc5ec7f63d3732 100755 (executable)
@@ -41,68 +41,34 @@ test_expect_success 'clone http repository' '
 '
 
 test_expect_success 'create password-protected repository' '
-       mkdir "$HTTPD_DOCUMENT_ROOT_PATH/auth/" &&
+       mkdir -p "$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/" &&
        cp -Rf "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \
-              "$HTTPD_DOCUMENT_ROOT_PATH/auth/repo.git"
-'
-
-test_expect_success 'setup askpass helpers' '
-       cat >askpass <<-EOF &&
-       #!/bin/sh
-       echo >>"$PWD/askpass-query" "askpass: \$*" &&
-       cat "$PWD/askpass-response"
-       EOF
-       chmod +x askpass &&
-       GIT_ASKPASS="$PWD/askpass" &&
-       export GIT_ASKPASS
-'
-
-expect_askpass() {
-       dest=$HTTPD_DEST
-       {
-               case "$1" in
-               none)
-                       ;;
-               pass)
-                       echo "askpass: Password for 'http://$2@$dest': "
-                       ;;
-               both)
-                       echo "askpass: Username for 'http://$dest': "
-                       echo "askpass: Password for 'http://$2@$dest': "
-                       ;;
-               *)
-                       false
-                       ;;
-               esac
-       } >askpass-expect &&
-       test_cmp askpass-expect askpass-query
-}
+              "$HTTPD_DOCUMENT_ROOT_PATH/auth/dumb/repo.git"
+'
+
+setup_askpass_helper
 
 test_expect_success 'cloning password-protected repository can fail' '
-       >askpass-query &&
-       echo wrong >askpass-response &&
-       test_must_fail git clone "$HTTPD_URL/auth/repo.git" clone-auth-fail &&
+       set_askpass wrong &&
+       test_must_fail git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-fail &&
        expect_askpass both wrong
 '
 
 test_expect_success 'http auth can use user/pass in URL' '
-       >askpass-query &&
-       echo wrong >askpass-response &&
-       git clone "$HTTPD_URL_USER_PASS/auth/repo.git" clone-auth-none &&
+       set_askpass wrong &&
+       git clone "$HTTPD_URL_USER_PASS/auth/dumb/repo.git" clone-auth-none &&
        expect_askpass none
 '
 
 test_expect_success 'http auth can use just user in URL' '
-       >askpass-query &&
-       echo user@host >askpass-response &&
-       git clone "$HTTPD_URL_USER/auth/repo.git" clone-auth-pass &&
+       set_askpass user@host &&
+       git clone "$HTTPD_URL_USER/auth/dumb/repo.git" clone-auth-pass &&
        expect_askpass pass user@host
 '
 
 test_expect_success 'http auth can request both user and pass' '
-       >askpass-query &&
-       echo user@host >askpass-response &&
-       git clone "$HTTPD_URL/auth/repo.git" clone-auth-both &&
+       set_askpass user@host &&
+       git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-both &&
        expect_askpass both user@host
 '
 
@@ -112,25 +78,22 @@ test_expect_success 'http auth respects credential helper config' '
                echo username=user@host
                echo password=user@host
        }; f" &&
-       >askpass-query &&
-       echo wrong >askpass-response &&
-       git clone "$HTTPD_URL/auth/repo.git" clone-auth-helper &&
+       set_askpass wrong &&
+       git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-helper &&
        expect_askpass none
 '
 
 test_expect_success 'http auth can get username from config' '
        test_config_global "credential.$HTTPD_URL.username" user@host &&
-       >askpass-query &&
-       echo user@host >askpass-response &&
-       git clone "$HTTPD_URL/auth/repo.git" clone-auth-user &&
+       set_askpass user@host &&
+       git clone "$HTTPD_URL/auth/dumb/repo.git" clone-auth-user &&
        expect_askpass pass user@host
 '
 
 test_expect_success 'configured username does not override URL' '
        test_config_global "credential.$HTTPD_URL.username" wrong &&
-       >askpass-query &&
-       echo user@host >askpass-response &&
-       git clone "$HTTPD_URL_USER/auth/repo.git" clone-auth-user2 &&
+       set_askpass user@host &&
+       git clone "$HTTPD_URL_USER/auth/dumb/repo.git" clone-auth-user2 &&
        expect_askpass pass user@host
 '
 
index 91eaf53d1d30f7719e93e88b674f60b6c6eaa376..2db5c3564181818efdf885188d7cc597024c6f12 100755 (executable)
@@ -27,6 +27,8 @@ test_expect_success 'create http-accessible bare repository' '
        git push public master:master
 '
 
+setup_askpass_helper
+
 cat >exp <<EOF
 > GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1
 > Accept: */*
@@ -109,6 +111,24 @@ test_expect_success 'follow redirects (302)' '
        git clone $HTTPD_URL/smart-redir-temp/repo.git --quiet repo-t
 '
 
+test_expect_success 'clone from password-protected repository' '
+       echo two >expect &&
+       set_askpass user@host &&
+       git clone --bare "$HTTPD_URL/auth/smart/repo.git" smart-auth &&
+       expect_askpass both user@host &&
+       git --git-dir=smart-auth log -1 --format=%s >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'clone from auth-only-for-push repository' '
+       echo two >expect &&
+       set_askpass wrong &&
+       git clone --bare "$HTTPD_URL/auth-push/smart/repo.git" smart-noauth &&
+       expect_askpass none &&
+       git --git-dir=smart-noauth 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 172178490ad126e07b70a6e3f72e0bf723d2c42b..752f5cb7d0f522a8a6654bae06b07a1727df7505 100755 (executable)
@@ -456,4 +456,14 @@ test_atom refs/tags/signed-long contents "subject line
 body contents
 $sig"
 
+cat >expected <<\EOF
+408fe76d02a785a006c2e9c669b7be5589ede96d <committer@example.com> refs/tags/master
+90b5ebede4899eda64893bc2a4c8f1d6fb6dfc40 <committer@example.com> refs/tags/bogo
+EOF
+
+test_expect_success 'Verify sort with multiple keys' '
+       git for-each-ref --format="%(objectname) %(taggeremail) %(refname)" --sort=objectname --sort=taggeremail \
+               refs/tags/bogo refs/tags/master > actual &&
+       test_cmp expected actual
+'
 test_done
index a40cd3630c28a13f4e0f36ef9f56925d3c8579ed..e41fa00b80e9b3eb47e45be848397ccda0f47c53 100755 (executable)
@@ -108,4 +108,16 @@ test_expect_success 'showing range' '
        test_cmp expect actual.filtered
 '
 
+test_expect_success '-s suppresses diff' '
+       echo main3 >expect &&
+       git show -s --format=%s main3 >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success '--quiet suppresses diff' '
+       echo main3 >expect &&
+       git show --quiet --format=%s main3 >actual &&
+       test_cmp expect actual
+'
+
 test_done
index c73bec9551eb27dab25aad69c83ae7ce9f9b11a8..56a81cd7486716897cc4f08196d0815a62461ffd 100755 (executable)
@@ -258,6 +258,27 @@ test_expect_success 'init should register submodule url in .git/config' '
        test_cmp expect url
 '
 
+test_failure_with_unknown_submodule () {
+       test_must_fail git submodule $1 no-such-submodule 2>output.err &&
+       grep "^error: .*no-such-submodule" output.err
+}
+
+test_expect_success 'init should fail with unknown submodule' '
+       test_failure_with_unknown_submodule init
+'
+
+test_expect_success 'update should fail with unknown submodule' '
+       test_failure_with_unknown_submodule update
+'
+
+test_expect_success 'status should fail with unknown submodule' '
+       test_failure_with_unknown_submodule status
+'
+
+test_expect_success 'sync should fail with unknown submodule' '
+       test_failure_with_unknown_submodule sync
+'
+
 test_expect_success 'update should fail when path is used by a file' '
        echo hello >expect &&
 
@@ -418,10 +439,7 @@ test_expect_success 'moving to a commit without submodule does not leave empty d
 '
 
 test_expect_success 'submodule <invalid-path> warns' '
-
-       git submodule no-such-submodule 2> output.err &&
-       grep "^error: .*no-such-submodule" output.err
-
+       test_failure_with_unknown_submodule
 '
 
 test_expect_success 'add submodules without specifying an explicit path' '
index ce61d4c0fa3d916757e09224ed79bc191fb0cb3d..15426530e49ef2e42cda2528f4a72a784eb40cd9 100755 (executable)
@@ -123,6 +123,18 @@ test_expect_success 'submodule update should throw away changes with --force ' '
        )
 '
 
+test_expect_success 'submodule update --force forcibly checks out submodules' '
+       (cd super &&
+        (cd submodule &&
+         rm -f file
+        ) &&
+        git submodule update --force submodule &&
+        (cd submodule &&
+         test "$(git status -s file)" = ""
+        )
+       )
+'
+
 test_expect_success 'submodule update --rebase staying on master' '
        (cd super/submodule &&
          git checkout master
@@ -367,7 +379,7 @@ test_expect_success 'submodule update continues after checkout error' '
         git submodule init &&
         git commit -am "new_submodule" &&
         (cd submodule2 &&
-         git rev-parse --max-count=1 HEAD > ../expect
+         git rev-parse --verify HEAD >../expect
         ) &&
         (cd submodule &&
          test_commit "update_submodule" file
@@ -384,7 +396,7 @@ test_expect_success 'submodule update continues after checkout error' '
         git checkout HEAD^ &&
         test_must_fail git submodule update &&
         (cd submodule2 &&
-         git rev-parse --max-count=1 HEAD > ../actual
+         git rev-parse --verify HEAD >../actual
         ) &&
         test_cmp expect actual
        )
@@ -413,7 +425,7 @@ test_expect_success 'submodule update continues after recursive checkout error'
          test_commit "update_submodule_again_again" file
         ) &&
         (cd submodule2 &&
-         git rev-parse --max-count=1 HEAD > ../expect &&
+         git rev-parse --verify HEAD >../expect &&
          test_commit "update_submodule2_again" file
         ) &&
         git add submodule &&
@@ -428,7 +440,7 @@ test_expect_success 'submodule update continues after recursive checkout error'
         ) &&
         test_must_fail git submodule update --recursive &&
         (cd submodule2 &&
-         git rev-parse --max-count=1 HEAD > ../actual
+         git rev-parse --verify HEAD >../actual
         ) &&
         test_cmp expect actual
        )
@@ -460,12 +472,12 @@ test_expect_success 'submodule update exit immediately in case of merge conflict
         ) &&
         git checkout HEAD^ &&
         (cd submodule2 &&
-         git rev-parse --max-count=1 HEAD > ../expect
+         git rev-parse --verify HEAD >../expect
         ) &&
         git config submodule.submodule.update merge &&
         test_must_fail git submodule update &&
         (cd submodule2 &&
-         git rev-parse --max-count=1 HEAD > ../actual
+         git rev-parse --verify HEAD >../actual
         ) &&
         test_cmp expect actual
        )
@@ -495,12 +507,12 @@ test_expect_success 'submodule update exit immediately after recursive rebase er
         ) &&
         git checkout HEAD^ &&
         (cd submodule2 &&
-         git rev-parse --max-count=1 HEAD > ../expect
+         git rev-parse --verify HEAD >../expect
         ) &&
         git config submodule.submodule.update rebase &&
         test_must_fail git submodule update &&
         (cd submodule2 &&
-         git rev-parse --max-count=1 HEAD > ../actual
+         git rev-parse --verify HEAD >../actual
         ) &&
         test_cmp expect actual
        )
index f5e16fc7db3f1dd84aff6d86261d10b3b3d00826..6fa0c70506b4a4f6b066d6f3d25aa0e499b419b5 100755 (executable)
@@ -55,6 +55,16 @@ test_expect_success 'setup' '
     git rm file12 &&
     git commit -m "branch1 changes" &&
 
+    git checkout -b stash1 master &&
+    echo stash1 change file11 >file11 &&
+    git add file11 &&
+    git commit -m "stash1 changes" &&
+
+    git checkout -b stash2 master &&
+    echo stash2 change file11 >file11 &&
+    git add file11 &&
+    git commit -m "stash2 changes" &&
+
     git checkout master &&
     git submodule update -N &&
     echo master updated >file1 &&
@@ -193,7 +203,35 @@ test_expect_success 'mergetool skips resolved paths when rerere is active' '
     git reset --hard
 '
 
+test_expect_success 'conflicted stash sets up rerere'  '
+    git config rerere.enabled true &&
+    git checkout stash1 &&
+    echo "Conflicting stash content" >file11 &&
+    git stash &&
+
+    git checkout --detach stash2 &&
+    test_must_fail git stash apply &&
+
+    test -n "$(git ls-files -u)" &&
+    conflicts="$(git rerere remaining)" &&
+    test "$conflicts" = "file11" &&
+    output="$(git mergetool --no-prompt)" &&
+    test "$output" != "No files need merging" &&
+
+    git commit -am "save the stash resolution" &&
+
+    git reset --hard stash2 &&
+    test_must_fail git stash apply &&
+
+    test -n "$(git ls-files -u)" &&
+    conflicts="$(git rerere remaining)" &&
+    test -z "$conflicts" &&
+    output="$(git mergetool --no-prompt)" &&
+    test "$output" = "No files need merging"
+'
+
 test_expect_success 'mergetool takes partial path' '
+    git reset --hard
     git config rerere.enabled false &&
     git checkout -b test12 branch1 &&
     git submodule update -N &&
index 8c12c65c72658acb37fa715fc93756381bc824bb..035122808b6e859810ee70daf381c2c895527894 100755 (executable)
@@ -841,6 +841,19 @@ test_expect_success $PREREQ '--compose adds MIME for utf8 subject' '
        grep "^Subject: =?UTF-8?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1
 '
 
+test_expect_success $PREREQ 'utf8 author is correctly passed on' '
+       clean_fake_sendmail &&
+       test_commit weird_author &&
+       test_when_finished "git reset --hard HEAD^" &&
+       git commit --amend --author "Füñný Nâmé <odd_?=mail@example.com>" &&
+       git format-patch --stdout -1 >funny_name.patch &&
+       git send-email --from="Example <nobody@example.com>" \
+         --to=nobody@example.com \
+         --smtp-server="$(pwd)/fake.sendmail" \
+         funny_name.patch &&
+       grep "^From: Füñný Nâmé <odd_?=mail@example.com>" msgtxt1
+'
+
 test_expect_success $PREREQ 'detects ambiguous reference/file conflict' '
        echo master > master &&
        git add master &&
index 9096398b184df722492cd6072d618edb78eb5206..9bc57d27e961720c98f75f95ab3186723e77f88b 100644 (file)
@@ -221,9 +221,35 @@ write_script () {
 # capital letters by convention).
 
 test_set_prereq () {
-       satisfied="$satisfied$1 "
+       satisfied_prereq="$satisfied_prereq$1 "
+}
+satisfied_prereq=" "
+lazily_testable_prereq= lazily_tested_prereq=
+
+# Usage: test_lazy_prereq PREREQ 'script'
+test_lazy_prereq () {
+       lazily_testable_prereq="$lazily_testable_prereq$1 "
+       eval test_prereq_lazily_$1=\$2
+}
+
+test_run_lazy_prereq_ () {
+       script='
+mkdir -p "$TRASH_DIRECTORY/prereq-test-dir" &&
+(
+       cd "$TRASH_DIRECTORY/prereq-test-dir" &&'"$2"'
+)'
+       say >&3 "checking prerequisite: $1"
+       say >&3 "$script"
+       test_eval_ "$script"
+       eval_ret=$?
+       rm -rf "$TRASH_DIRECTORY/prereq-test-dir"
+       if test "$eval_ret" = 0; then
+               say >&3 "prerequisite $1 ok"
+       else
+               say >&3 "prerequisite $1 not satisfied"
+       fi
+       return $eval_ret
 }
-satisfied=" "
 
 test_have_prereq () {
        # prerequisites can be concatenated with ','
@@ -238,8 +264,24 @@ test_have_prereq () {
 
        for prerequisite
        do
+               case " $lazily_tested_prereq " in
+               *" $prerequisite "*)
+                       ;;
+               *)
+                       case " $lazily_testable_prereq " in
+                       *" $prerequisite "*)
+                               eval "script=\$test_prereq_lazily_$prerequisite" &&
+                               if test_run_lazy_prereq_ "$prerequisite" "$script"
+                               then
+                                       test_set_prereq $prerequisite
+                               fi
+                               lazily_tested_prereq="$lazily_tested_prereq$prerequisite "
+                       esac
+                       ;;
+               esac
+
                total_prereq=$(($total_prereq + 1))
-               case $satisfied in
+               case "$satisfied_prereq" in
                *" $prerequisite "*)
                        ok_prereq=$(($ok_prereq + 1))
                        ;;
index bb4f8865b2628665f4adbf9ceef03d5a9081e244..78c428619e99ea0225f61a1fe257e444d464ad0b 100644 (file)
@@ -659,9 +659,29 @@ test_i18ngrep () {
        fi
 }
 
-# test whether the filesystem supports symbolic links
-ln -s x y 2>/dev/null && test -h y 2>/dev/null && test_set_prereq SYMLINKS
-rm -f y
+test_lazy_prereq SYMLINKS '
+       # test whether the filesystem supports symbolic links
+       ln -s x y && test -h y
+'
+
+test_lazy_prereq CASE_INSENSITIVE_FS '
+       echo good >CamelCase &&
+       echo bad >camelcase &&
+       test "$(cat CamelCase)" != good
+'
+
+test_lazy_prereq UTF8_NFD_TO_NFC '
+       # check whether FS converts nfd unicode to nfc
+       auml=$(printf "\303\244")
+       aumlcdiar=$(printf "\141\314\210")
+       >"$auml" &&
+       case "$(echo *)" in
+       "$aumlcdiar")
+               true ;;
+       *)
+               false ;;
+       esac
+'
 
 # When the tests are run as root, permission tests will report that
 # things are writable when they shouldn't be.
diff --git a/test-regex.c b/test-regex.c
new file mode 100644 (file)
index 0000000..b5bfd54
--- /dev/null
@@ -0,0 +1,20 @@
+#include <git-compat-util.h>
+
+int main(int argc, char **argv)
+{
+       char *pat = "[^={} \t]+";
+       char *str = "={}\nfred";
+       regex_t r;
+       regmatch_t m[1];
+
+       if (regcomp(&r, pat, REG_EXTENDED | REG_NEWLINE))
+               die("failed regcomp() for pattern '%s'", pat);
+       if (regexec(&r, str, 1, m, 0))
+               die("no match of pattern '%s' to string '%s'", pat, str);
+
+       /* http://sourceware.org/bugzilla/show_bug.cgi?id=3957  */
+       if (m[0].rm_so == 3) /* matches '\n' when it should not */
+               die("regex bug confirmed: re-build git with NO_REGEX=1");
+
+       exit(0);
+}
index 28ad6db9ffa854c3ef9185ba85108e95edc44d51..ba01563a0241041cb401cfb03495e6067847248e 100644 (file)
@@ -49,12 +49,12 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2,
        if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode1)) {
                if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) {
                        opt->change(opt, mode1, mode2,
-                                   sha1, sha2, base->buf, 0, 0);
+                                   sha1, sha2, 1, 1, base->buf, 0, 0);
                }
                strbuf_addch(base, '/');
                diff_tree_sha1(sha1, sha2, base->buf, opt);
        } else {
-               opt->change(opt, mode1, mode2, sha1, sha2, base->buf, 0, 0);
+               opt->change(opt, mode1, mode2, sha1, sha2, 1, 1, base->buf, 0, 0);
        }
        strbuf_setlen(base, old_baselen);
        return 0;
@@ -100,7 +100,7 @@ static void show_entry(struct diff_options *opt, const char *prefix,
                        die("corrupt tree sha %s", sha1_to_hex(sha1));
 
                if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE))
-                       opt->add_remove(opt, *prefix, mode, sha1, base->buf, 0);
+                       opt->add_remove(opt, *prefix, mode, sha1, 1, base->buf, 0);
 
                strbuf_addch(base, '/');
 
@@ -108,7 +108,7 @@ static void show_entry(struct diff_options *opt, const char *prefix,
                show_tree(opt, prefix, &inner, base);
                free(tree);
        } else
-               opt->add_remove(opt, prefix[0], mode, sha1, base->buf, 0);
+               opt->add_remove(opt, prefix[0], mode, sha1, 1, base->buf, 0);
 
        strbuf_setlen(base, old_baselen);
 }
@@ -212,8 +212,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co
        diff_opts.rename_score = opt->rename_score;
        paths[0] = NULL;
        diff_tree_setup_paths(paths, &diff_opts);
-       if (diff_setup_done(&diff_opts) < 0)
-               die("unable to set up diff options to follow renames");
+       diff_setup_done(&diff_opts);
        diff_tree(t1, t2, base, &diff_opts);
        diffcore_std(&diff_opts);
        diff_tree_release_paths(&diff_opts);
index bb08e2eb0dc52f68807a83b671fa61a2c2224f41..2e90ccb74fe45e6335ee6a76451da40d7d3f5a09 100644 (file)
@@ -11,6 +11,7 @@
 #include "list-objects.h"
 #include "run-command.h"
 #include "sigchain.h"
+#include "version.h"
 
 static const char upload_pack_usage[] = "git upload-pack [--strict] [--timeout=<n>] <dir>";
 
@@ -734,9 +735,11 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
        }
 
        if (capabilities)
-               packet_write(1, "%s %s%c%s%s\n", sha1_to_hex(sha1), refname_nons,
+               packet_write(1, "%s %s%c%s%s agent=%s\n",
+                            sha1_to_hex(sha1), refname_nons,
                             0, capabilities,
-                            stateless_rpc ? " no-done" : "");
+                            stateless_rpc ? " no-done" : "",
+                            git_user_agent_sanitized());
        else
                packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname_nons);
        capabilities = NULL;
index f98d5a654d4a17a9d85157b33f161afe6951a6e8..6106a8098c8a46575f9afae5da9909b5c196f754 100644 (file)
--- a/version.c
+++ b/version.c
@@ -1,5 +1,6 @@
 #include "git-compat-util.h"
 #include "version.h"
+#include "strbuf.h"
 
 const char git_version_string[] = GIT_VERSION;
 
@@ -15,3 +16,23 @@ const char *git_user_agent(void)
 
        return agent;
 }
+
+const char *git_user_agent_sanitized(void)
+{
+       static const char *agent = NULL;
+
+       if (!agent) {
+               struct strbuf buf = STRBUF_INIT;
+               int i;
+
+               strbuf_addstr(&buf, git_user_agent());
+               strbuf_trim(&buf);
+               for (i = 0; i < buf.len; i++) {
+                       if (buf.buf[i] <= 32 || buf.buf[i] >= 127)
+                               buf.buf[i] = '.';
+               }
+               agent = buf.buf;
+       }
+
+       return agent;
+}
index fd9cdd6316a17d3dfdc0976e668d26f7854fb181..6911a4f1558de0c0d0b880a5b859925869a3e86e 100644 (file)
--- a/version.h
+++ b/version.h
@@ -4,5 +4,6 @@
 extern const char git_version_string[];
 
 const char *git_user_agent(void);
+const char *git_user_agent_sanitized(void);
 
 #endif /* VERSION_H */
index b5e33e49c77bdf1d19292971b63ff5221b013f33..68739aaa3b9e9e1a1bbbd43c75c9b5c244fb6c3e 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -403,6 +403,19 @@ int remove_or_warn(unsigned int mode, const char *file)
        return S_ISGITLINK(mode) ? rmdir_or_warn(file) : unlink_or_warn(file);
 }
 
+void warn_on_inaccessible(const char *path)
+{
+       warning(_("unable to access '%s': %s"), path, strerror(errno));
+}
+
+int access_or_warn(const char *path, int mode)
+{
+       int ret = access(path, mode);
+       if (ret && errno != ENOENT)
+               warn_on_inaccessible(path);
+       return ret;
+}
+
 struct passwd *xgetpwuid_self(void)
 {
        struct passwd *pw;