Merge branch 'nd/maint-diffstat-summary' into maint
authorJunio C Hamano <gitster@pobox.com>
Thu, 20 Sep 2012 22:55:31 +0000 (15:55 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 20 Sep 2012 22:55:31 +0000 (15:55 -0700)
* nd/maint-diffstat-summary:
Revert diffstat back to English

148 files changed:
.gitignore
Documentation/CodingGuidelines
Documentation/Makefile
Documentation/RelNotes/1.7.11.6.txt [new file with mode: 0644]
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-commit.txt
Documentation/git-config.txt
Documentation/git-credential-cache--daemon.txt
Documentation/git-credential-cache.txt
Documentation/git-credential-store.txt
Documentation/git-describe.txt
Documentation/git-fast-import.txt
Documentation/git-filter-branch.txt
Documentation/git-for-each-ref.txt
Documentation/git-format-patch.txt
Documentation/git-fsck.txt
Documentation/git-log.txt
Documentation/git-lost-found.txt
Documentation/git-ls-remote.txt
Documentation/git-pack-refs.txt
Documentation/git-pull.txt
Documentation/git-remote.txt
Documentation/git-replace.txt
Documentation/git-shortlog.txt
Documentation/git-submodule.txt
Documentation/git-tag.txt
Documentation/git.txt
Documentation/gitcli.txt
Documentation/gitcore-tutorial.txt
Documentation/gittutorial.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
Documentation/user-manual.txt
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/mailinfo.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/ciabot/INSTALL [new file with mode: 0644]
contrib/ciabot/README
contrib/ciabot/ciabot.py
contrib/ciabot/ciabot.sh
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/perf/perf-lib.sh
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 45577117c2a02dd4a4f9e63e78139b3df665b8f2..57da6aadeb8b4d65037035afaa269f391e989c38 100644 (file)
@@ -76,11 +76,19 @@ For shell scripts specifically (not exhaustive):
 
  - We do not use Process Substitution <(list) or >(list).
 
+ - Do not write control structures on a single line with semicolon.
+   "then" should be on the next line for if statements, and "do"
+   should be on the next line for "while" and "for".
+
  - We prefer "test" over "[ ... ]".
 
  - We do not write the noiseword "function" in front of shell
    functions.
 
+ - We prefer a space between the function name and the parentheses. The
+   opening "{" should also be on the same line.
+   E.g.: my_function () {
+
  - As to use of grep, stick to a subset of BRE (namely, no \{m,n\},
    [::], [==], nor [..]) for portability.
 
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
diff --git a/Documentation/RelNotes/1.7.11.6.txt b/Documentation/RelNotes/1.7.11.6.txt
new file mode 100644 (file)
index 0000000..ba7d3c3
--- /dev/null
@@ -0,0 +1,84 @@
+Git v1.7.11.6 Release Notes
+===========================
+
+Fixes since v1.7.11.5
+---------------------
+
+ * "ciabot" script (in contrib/) has been updated with extensive
+   documentation.
+
+ * "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.
+
+ * 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.
+
+ * 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
+   file in .git/refs/ hierarchy were the only way to have branches and
+   tags, which is not true for quite some time.
+
+ * 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 "--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
+   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 4622297ec98cddc2e1f2e4417b9eeec11a3c91b1..9594ac8e9de9645be71b1528dcb94705f1695283 100644 (file)
@@ -389,8 +389,10 @@ DISCUSSION
 Though not required, it's a good idea to begin the commit message
 with a single short (less than 50 character) line summarizing the
 change, followed by a blank line and then a more thorough description.
-Tools that turn commits into email, for example, use the first line
-on the Subject: line and the rest of the commit in the body.
+The text up to the first blank line in a commit message is treated
+as the commit title, and that title is used throughout git.
+For example, linkgit:git-format-patch[1] turns a commit into email, and it uses
+the title on the Subject line and the rest of the commit in the body.
 
 include::i18n.txt[]
 
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 039cce2e98367fdbff6f7c0ea68f8f4f77b8a107..72d6bb612ba8890a7f2a8c3ff13820a53918c74a 100644 (file)
@@ -36,12 +36,12 @@ OPTIONS
 
 --all::
        Instead of using only the annotated tags, use any ref
-       found in `.git/refs/`.  This option enables matching
+       found in `refs/` namespace.  This option enables matching
        any known branch, remote-tracking branch, or lightweight tag.
 
 --tags::
        Instead of using only the annotated tags, use any tag
-       found in `.git/refs/tags`.  This option enables matching
+       found in `refs/tags` namespace.  This option enables matching
        a lightweight (non-annotated) tag.
 
 --contains::
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 81f58234a79a94ef5e9b60e1985b096cff6fcb5c..e2301f5c0106a35e5fa14d63944abeea2cb09e9b 100644 (file)
@@ -32,7 +32,8 @@ changes, which would normally have no effect.  Nevertheless, this may be
 useful in the future for compensating for some git bugs or such,
 therefore such a usage is permitted.
 
-*NOTE*: This command honors `.git/info/grafts` and `.git/refs/replace/`.
+*NOTE*: This command honors `.git/info/grafts` file and refs in
+the `refs/replace/` namespace.
 If you have any grafts or replacement refs defined, running this command
 will make them permanent.
 
@@ -303,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:
@@ -313,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:
 
@@ -328,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 c872b883ba25144457eccb9967bc68003a3332ea..db55a4e0bbc524c20f08e6862daaa97dd1785b71 100644 (file)
@@ -102,9 +102,10 @@ Fields that have name-email-date tuple as its value (`author`,
 and `date` to extract the named component.
 
 The complete message in a commit and tag object is `contents`.
-Its first line is `contents:subject`, the remaining lines
-are `contents:body` and the optional GPG signature
-is `contents:signature`.
+Its first line is `contents:subject`, where subject is the concatenation
+of all lines of the commit message up to the first blank line.  The next
+line is 'contents:body', where body is all of the lines after the first
+blank line.  Finally, the optional GPG signature is `contents:signature`.
 
 For sorting purposes, fields with numeric values sort in numeric
 order (`objectsize`, `authordate`, `committerdate`, `taggerdate`).
index 04c7346e3e8ba12465e71ad1197ed6a109a473b1..6d43f56279fe7a0d42510035e33424df0bc584f1 100644 (file)
@@ -58,10 +58,13 @@ output, unless the `--stdout` option is specified.
 If `-o` is specified, output files are created in <dir>.  Otherwise
 they are created in the current working directory.
 
-By default, the subject of a single patch is "[PATCH] First Line" and
-the subject when multiple patches are output is "[PATCH n/m] First
-Line". To force 1/1 to be added for a single patch, use `-n`.  To omit
-patch numbers from the subject, use `-N`.
+By default, the subject of a single patch is "[PATCH] " followed by
+the concatenation of lines from the commit message up to the first blank
+line (see the DISCUSSION section of linkgit:git-commit[1]).
+
+When multiple patches are output, the subject prefix will instead be
+"[PATCH n/m] ".  To force 1/1 to be added for a single patch, use `-n`.
+To omit patch numbers from the subject, use `-N`.
 
 If given `--thread`, `git-format-patch` will generate `In-Reply-To` and
 `References` headers to make the second and subsequent patch mails appear
index bbb25da2dd601cd9ddcdbeae525c82a08fbfde4a..da348fc9427d144335acc9d4d2c20549f850fa32 100644 (file)
@@ -23,8 +23,8 @@ OPTIONS
        An object to treat as the head of an unreachability trace.
 +
 If no objects are given, 'git fsck' defaults to using the
-index file, all SHA1 references in .git/refs/*, and all reflogs (unless
---no-reflogs is given) as heads.
+index file, all SHA1 references in `refs` namespace, and all reflogs
+(unless --no-reflogs is given) as heads.
 
 --unreachable::
        Print out objects that exist but that aren't reachable from any
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 c406a1100159471cf904629b5d4afc0469c382c0..d54932889f3d5b3c59f403920203911d52227365 100644 (file)
@@ -48,7 +48,8 @@ $ gitk $(cd .git/lost-found/commit && echo ??*)
 ------------
 
 After making sure you know which the object is the tag you are looking
-for, you can reconnect it to your regular .git/refs hierarchy.
+for, you can reconnect it to your regular `refs` hierarchy by using
+the `update-ref` command.
 
 ------------
 $ git cat-file -t 1ef2b196
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 10afd4edfe515013bd92ad18d842536a537142a5..f131677478e91f8ab6611a6e45dda56ff48a9e2a 100644 (file)
@@ -14,7 +14,8 @@ DESCRIPTION
 -----------
 
 Traditionally, tips of branches and tags (collectively known as
-'refs') were stored one file per ref under `$GIT_DIR/refs`
+'refs') were stored one file per ref in a (sub)directory
+under `$GIT_DIR/refs`
 directory.  While many branch tips tend to be updated often,
 most tags and some branch tips are never updated.  When a
 repository has hundreds or thousands of tags, this
@@ -22,13 +23,14 @@ one-file-per-ref format both wastes storage and hurts
 performance.
 
 This command is used to solve the storage and performance
-problem by stashing the refs in a single file,
+problem by storing the refs in a single file,
 `$GIT_DIR/packed-refs`.  When a ref is missing from the
-traditional `$GIT_DIR/refs` hierarchy, it is looked up in this
+traditional `$GIT_DIR/refs` directory hierarchy, it is looked
+up in this
 file and used if found.
 
 Subsequent updates to branches always create new files under
-`$GIT_DIR/refs` hierarchy.
+`$GIT_DIR/refs` directory hierarchy.
 
 A recommended practice to deal with a repository with too many
 refs is to pack its refs with `--all --prune` once, and
@@ -57,6 +59,15 @@ a repository with many branches of historical interests.
 The command usually removes loose refs under `$GIT_DIR/refs`
 hierarchy after packing them.  This option tells it not to.
 
+
+BUGS
+----
+
+Older documentation written before the packed-refs mechanism was
+introduced may still say things like ".git/refs/heads/<branch> file
+exists" when it means "branch <branch> exists".
+
+
 GIT
 ---
 Part of the linkgit:git[1] suite
index defb544ed0af407a2e6360355bad34b1cb43fed9..67fa5ee19520a113bceb1a704ee84f40e8eb7693 100644 (file)
@@ -101,6 +101,7 @@ include::merge-options.txt[]
 
 :git-pull: 1
 
+-r::
 --rebase::
        Rebase the current branch on top of the upstream branch after
        fetching.  If there is a remote-tracking branch corresponding to
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 17df525275493f5bdcdd912ad56581ffa8a97fa2..51131d0858bf5a7519b8759e2ee081b3b5f27b48 100644 (file)
@@ -14,14 +14,13 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Adds a 'replace' reference in `.git/refs/replace/`
+Adds a 'replace' reference in `refs/replace/` namespace.
 
 The name of the 'replace' reference is the SHA1 of the object that is
 replaced. The content of the 'replace' reference is the SHA1 of the
 replacement object.
 
-Unless `-f` is given, the 'replace' reference must not yet exist in
-`.git/refs/replace/` directory.
+Unless `-f` is given, the 'replace' reference must not yet exist.
 
 Replacement references will be used by default by all git commands
 except those doing reachability traversal (prune, pack transfer and
index 01d8417316e23bc74f2c86df9004091710437ba7..afeb4cdf16df91f63197d390fdbf1540eff66837 100644 (file)
@@ -14,8 +14,7 @@ git log --pretty=short | 'git shortlog' [-h] [-n] [-s] [-e] [-w]
 DESCRIPTION
 -----------
 Summarizes 'git log' output in a format suitable for inclusion
-in release announcements. Each commit will be grouped by author and
-the first line of the commit message will be shown.
+in release announcements. Each commit will be grouped by author and title.
 
 Additionally, "[PATCH]" will be stripped from the commit description.
 
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 e36a7c3d1e11e38950c74b32ab4f1ac9a4683a41..247534e908d9f5b804a60b6707d1962eccc9bb1a 100644 (file)
@@ -20,11 +20,10 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-Add a tag reference in `.git/refs/tags/`, unless `-d/-l/-v` is given
+Add a tag reference in `refs/tags/`, unless `-d/-l/-v` is given
 to delete, list or verify tags.
 
-Unless `-f` is given, the tag to be created must not yet exist in the
-`.git/refs/tags/` directory.
+Unless `-f` is given, the named tag must not yet exist.
 
 If one of `-a`, `-s`, or `-u <key-id>` is passed, the command
 creates a 'tag' object, and requires a tag message.  Unless
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 ea17f7a53b664d5e9e86ceb814c5cc7430035125..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:
 
@@ -62,6 +79,14 @@ scripting git:
    `git log -1 HEAD` but write `git log -1 HEAD --`; the former will not work
    if you happen to have a file called `HEAD` in the work tree.
 
+ * many commands allow a long option "--option" to be abbreviated
+   only to their unique prefix (e.g. if there is no other option
+   whose name begins with "opt", you may be able to spell "--opt" to
+   invoke the "--option" flag), but you should fully spell them out
+   when writing your scripts; later versions of Git may introduce a
+   new option whose name shares the same prefix, e.g. "--optimize",
+   to make a short prefix that used to be unique no longer unique.
+
 
 ENHANCED OPTION PARSER
 ----------------------
index 9d893369a00b6a924876fb234c1082db2021abf3..5325c5a7d5cab3f74c3866319a60d35e4299da2e 100644 (file)
@@ -956,12 +956,11 @@ $ git show-branch --topo-order --more=1 master mybranch
 ------------------------------------------------
 
 The first two lines indicate that it is showing the two branches
-and the first line of the commit log message from their
-top-of-the-tree commits, you are currently on `master` branch
-(notice the asterisk `*` character), and the first column for
-the later output lines is used to show commits contained in the
+with the titles of their top-of-the-tree commits, you are currently on
+`master` branch (notice the asterisk `*` character), and the first
+column for the later output lines is used to show commits contained in the
 `master` branch, and the second column for the `mybranch`
-branch. Three commits are shown along with their log messages.
+branch. Three commits are shown along with their titles.
 All of them have non blank characters in the first column (`*`
 shows an ordinary commit on the current branch, `-` is a merge commit), which
 means they are now part of the `master` branch. Only the "Some
index dee050567e65301066629c566613b84c6c065169..f1cb6f3be67fbb03583a35601791f0db839fbe1b 100644 (file)
@@ -139,9 +139,11 @@ them to the index, and commit, all in one step.
 A note on commit messages: Though not required, it's a good idea to
 begin the commit message with a single short (less than 50 character)
 line summarizing the change, followed by a blank line and then a more
-thorough description.  Tools that turn commits into email, for
-example, use the first line on the Subject: line and the rest of the
-commit in the body.
+thorough description. The text up to the first blank line in a commit
+message is treated as the commit title, and that title is used
+throughout git.  For example, linkgit:git-format-patch[1] turns a
+commit into email, and it uses the title on the Subject line and the
+rest of the commit in the body.
 
 Git tracks content not files
 ----------------------------
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 d9b2b5b2e07827ff0a8a276d2593f5e197e029b3..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.
@@ -578,16 +579,33 @@ Commit Ordering
 
 By default, the commits are shown in reverse chronological order.
 
---topo-order::
+--date-order::
+       Show no parents before all of its children are shown, but
+       otherwise show commits in the commit timestamp order.
 
-       This option makes them appear in topological order (i.e.
-       descendant commits are shown before their parents).
+--topo-order::
+       Show no parents before all of its children are shown, and
+       avoid showing commits on multiple lines of history
+       intermixed.
++
+For example, in a commit history like this:
++
+----------------------------------------------------------------
 
---date-order::
+    ---1----2----4----7
+       \              \
+        3----5----6----8---
 
-       This option is similar to '--topo-order' in the sense that no
-       parent comes before all of its children, but otherwise things
-       are still ordered in the commit timestamp order.
+----------------------------------------------------------------
++
+where the numbers denote the order of commit timestamps, `git
+rev-list` and friends with `--date-order` show the commits in the
+timestamp order: 8 7 6 5 4 3 2 1.
++
+With `--topo-order`, they would show 8 6 5 3 7 4 2 1 (or 8 7 4 2 6 5
+3 1); some older commits are shown before newer ones in order to
+avoid showing the commits from two parallel development track mixed
+together.
 
 --reverse::
 
@@ -619,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 03d95dc290cecd2223116be90b591f75d40ced2b..85651b57ae466496e98e9c2507072f9fa8125c4d 100644 (file)
@@ -1136,9 +1136,12 @@ Creating good commit messages
 Though not required, it's a good idea to begin the commit message
 with a single short (less than 50 character) line summarizing the
 change, followed by a blank line and then a more thorough
-description.  Tools that turn commits into email, for example, use
-the first line on the Subject line and the rest of the commit in the
-body.
+description.  The text up to the first blank line in a commit
+message is treated as the commit title, and that title is used
+throughout git.  For example, linkgit:git-format-patch[1] turns a
+commit into email, and it uses the title on the Subject line and the
+rest of the commit in the body.
+
 
 [[ignoring-files]]
 Ignoring files
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 eaf9e157a3897c2442756911b906ff9d3ee2be90..18895ee4d9c987ec97d6781a5ffe5ec935bf19c7 100644 (file)
@@ -232,7 +232,9 @@ static void cleanup_subject(struct strbuf *subject)
                case 'r': case 'R':
                        if (subject->len <= at + 3)
                                break;
-                       if (!memcmp(subject->buf + at + 1, "e:", 2)) {
+                       if ((subject->buf[at + 1] == 'e' ||
+                            subject->buf[at + 1] == 'E') &&
+                           subject->buf[at + 2] == ':') {
                                strbuf_remove(subject, at, 3);
                                continue;
                        }
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,
diff --git a/contrib/ciabot/INSTALL b/contrib/ciabot/INSTALL
new file mode 100644 (file)
index 0000000..7222961
--- /dev/null
@@ -0,0 +1,54 @@
+= Installation instructions =
+
+Two scripts are included.  The Python one (ciabot.py) is faster and
+more capable; the shell one (ciabot.sh) is a fallback in case Python
+gives your git hosting site indigestion. (I know of no such sites.)
+
+It is no longer necessary to modify the script in order to put it
+in place; in fact, this is now discouraged. It is entirely
+configurable with the following git config variables:
+
+ciabot.project = name of the project
+ciabot.repo = name of the project repo for gitweb/cgit purposes
+ciabot.xmlrpc  = if true, ship notifications via XML-RPC
+ciabot.revformat = format in which the revision is shown
+
+The revformat variable may have the following values
+raw -> full hex ID of commit
+short -> first 12 chars of hex ID
+describe -> describe relative to last tag, falling back to short
+
+ciabot.project defaults to the directory name of the repository toplevel.
+ciabot.repo defaults to ciabot.project lowercased.
+ciabot.xmlrpc defaults to True
+ciabot.revformat defaults to 'describe'.
+
+This means that in the normal case you need not do any configuration at all,
+however setting ciabot.project will allow the hook to run slightly faster.
+
+Once you've set these variables, try your script with -n to see the
+notification message dumped to stdout and verify that it looks sane.
+
+To live-test these scripts, your project needs to have been registered with
+the CIA site.  Here are the steps:
+
+1. Open an IRC window on irc://freenode/commits or your registered
+   project IRC channel.
+
+2. Run ciabot.py and/or ciabot.sh from any directory under git
+   control.
+
+You should see a notification on the channel for your most recent commit.
+
+After verifying correct function, install one of these scripts either
+in a post-commit hook or in an update hook.
+
+In post-commit, run it without arguments. It will query for
+current HEAD and the latest commit ID to get the information it
+needs.
+
+In update, call it with a refname followed by a list of commits:
+You want to reverse the order git rev-list emits because it lists
+from most recent to oldest.
+
+/path/to/ciabot.py ${refname} $(git rev-list ${oldhead}..${newhead} | tac)
index 3b916acece20d521a9fbefea6089b9a9173adbf1..2dfe1f91f5f0ace6b8e190979ee604d13d1861b5 100644 (file)
@@ -8,5 +8,4 @@ You probably want the Python version; it's faster, more capable, and
 better documented.  The shell version is maintained only as a fallback
 for use on hosting sites that don't permit Python hook scripts.
 
-You will find installation instructions for each script in its comment
-header.
+See the file INSTALL for installation instructions.
index 9775dffb5d49521a7078643104762cd136edffcc..bd24395d4cf404f886803892d0be98c964a43ce7 100755 (executable)
 # usage: ciabot.py [-V] [-n] [-p projectname]  [refname [commits...]]
 #
 # This script is meant to be run either in a post-commit hook or in an
-# update hook.  If there's nothing unusual about your hosting setup,
-# you can specify the project name with a -p option and avoid having
-# to modify this script.  Try it with -n to see the notification mail
-# dumped to stdout and verify that it looks sane. With -V it dumps its
-# version and exits.
+# update hook. Try it with -n to see the notification mail dumped to
+# stdout and verify that it looks sane. With -V it dumps its version
+# and exits.
 #
-# In post-commit, run it without arguments (other than possibly a -p
-# option). It will query for current HEAD and the latest commit ID to
-# get the information it needs.
+# In post-commit, run it without arguments. It will query for
+# current HEAD and the latest commit ID to get the information it
+# needs.
 #
 # In update, call it with a refname followed by a list of commits:
-# You want to reverse the order git rev-list emits becxause it lists
+# You want to reverse the order git rev-list emits because it lists
 # from most recent to oldest.
 #
 # /path/to/ciabot.py ${refname} $(git rev-list ${oldhead}..${newhead} | tac)
 #
-# Note: this script uses mail, not XML-RPC, in order to avoid stalling
-# until timeout when the CIA XML-RPC server is down.
+# Configuration variables affecting this script:
 #
-
+# ciabot.project = name of the project
+# ciabot.repo = name of the project repo for gitweb/cgit purposes
+# ciabot.xmlrpc  = if true (default), ship notifications via XML-RPC
+# ciabot.revformat = format in which the revision is shown
 #
-# The project as known to CIA. You will either want to change this
-# or invoke the script with a -p option to set it.
+# ciabot.project defaults to the directory name of the repository toplevel.
+# ciabot.repo defaults to ciabot.project lowercased.
 #
-project=None
-
+# This means that in the normal case you need not do any configuration at all,
+# but setting the project name will speed it up slightly.
 #
-# You may not need to change these:
+# The revformat variable may have the following values
+# raw -> full hex ID of commit
+# short -> first 12 chars of hex ID
+# describe = -> describe relative to last tag, falling back to short
+# The default is 'describe'.
+#
+# Note: the CIA project now says only XML-RPC is reliable, so
+# we default to that.
 #
-import os, sys, commands, socket, urllib
-
-# Name of the repository.
-# You can hardwire this to make the script faster.
-repo = os.path.basename(os.getcwd())
 
-# Fully-qualified domain name of this host.
-# You can hardwire this to make the script faster.
-host = socket.getfqdn()
+import os, sys, commands, socket, urllib
+from xml.sax.saxutils import escape
 
 # Changeset URL prefix for your repo: when the commit ID is appended
 # to this, it should point at a CGI that will display the commit
@@ -72,7 +73,7 @@
 <message>
   <generator>
     <name>CIA Python client for Git</name>
-    <version>%(gitver)s</version>
+    <version>%(version)s</version>
     <url>%(generator)s</url>
   </generator>
   <source>
 # No user-serviceable parts below this line:
 #
 
-# Addresses for the e-mail. The from address is a dummy, since CIA
-# will never reply to this mail.
-fromaddr = "CIABOT-NOREPLY@" + host
-toaddr = "cia@cia.navi.cx"
+# Where to ship e-mail notifications.
+toaddr = "cia@cia.vc"
 
 # Identify the generator script.
 # Should only change when the script itself gets a new home and maintainer.
-generator="http://www.catb.org/~esr/ciabot.py"
+generator = "http://www.catb.org/~esr/ciabot.py"
+version = "3.6"
 
 def do(command):
     return commands.getstatusoutput(command)[1]
 
-def report(refname, merged):
+def report(refname, merged, xmlrpc=True):
     "Generate a commit notification to be reported to CIA"
 
     # Try to tinyfy a reference to a web view for this commit.
@@ -121,32 +121,27 @@ def report(refname, merged):
 
     branch = os.path.basename(refname)
 
-    # Compute a shortnane for the revision
-    rev = do("git describe '"+ merged +"' 2>/dev/null") or merged[:12]
-
-    # Extract the neta-information for the commit
-    rawcommit = do("git cat-file commit " + merged)
+    # Compute a description for the revision
+    if revformat == 'raw':
+        rev = merged
+    elif revformat == 'short':
+        rev = ''
+    else: # revformat == 'describe'
+        rev = do("git describe %s 2>/dev/null" % merged)
+    if not rev:
+        rev = merged[:12]
+
+    # Extract the meta-information for the commit
     files=do("git diff-tree -r --name-only '"+ merged +"' | sed -e '1d' -e 's-.*-<file>&</file>-'")
-    inheader = True
-    headers = {}
-    logmsg = ""
-    for line in rawcommit.split("\n"):
-        if inheader:
-            if line:
-                fields = line.split()
-                headers[fields[0]] = " ".join(fields[1:])
-            else:
-                inheader = False
-        else:
-            logmsg = line
-            break
-    (author, ts) = headers["author"].split(">")
+    metainfo = do("git log -1 '--pretty=format:%an <%ae>%n%at%n%s' " + merged)
+    (author, ts, logmsg) = metainfo.split("\n")
+    logmsg = escape(logmsg)
 
-    # This discards the part of the authors addrsss after @.
-    # Might be bnicece to ship the full email address, if not
+    # This discards the part of the author's address after @.
+    # Might be be nice to ship the full email address, if not
     # for spammers' address harvesters - getting this wrong
     # would make the freenode #commits channel into harvester heaven.
-    author = author.replace("<", "").split("@")[0].split()[-1]
+    author = escape(author.replace("<", "").split("@")[0].split()[-1])
 
     # This ignores the timezone.  Not clear what to do with it...
     ts = ts.strip().split()[0]
@@ -155,8 +150,7 @@ def report(refname, merged):
     context.update(globals())
 
     out = xml % context
-
-    message = '''\
+    mail = '''\
 Message-ID: <%(merged)s.%(author)s@%(project)s>
 From: %(fromaddr)s
 To: %(toaddr)s
@@ -165,34 +159,56 @@ def report(refname, merged):
 
 %(out)s''' % locals()
 
-    return message
+    if xmlrpc:
+        return out
+    else:
+        return mail
 
 if __name__ == "__main__":
     import getopt
 
+    # Get all config variables
+    revformat = do("git config --get ciabot.revformat")
+    project = do("git config --get ciabot.project")
+    repo = do("git config --get ciabot.repo")
+    xmlrpc = do("git config --get ciabot.xmlrpc")
+    xmlrpc = not (xmlrpc and xmlrpc == "false")
+
+    host = socket.getfqdn()
+    fromaddr = "CIABOT-NOREPLY@" + host
+
     try:
-        (options, arguments) = getopt.getopt(sys.argv[1:], "np:V")
+        (options, arguments) = getopt.getopt(sys.argv[1:], "np:xV")
     except getopt.GetoptError, msg:
         print "ciabot.py: " + str(msg)
         raise SystemExit, 1
 
-    mailit = True
+    notify = True
     for (switch, val) in options:
         if switch == '-p':
             project = val
         elif switch == '-n':
-            mailit = False
+            notify = False
+        elif switch == '-x':
+            xmlrpc = True
         elif switch == '-V':
-            print "ciabot.py: version 3.2"
+            print "ciabot.py: version", version
             sys.exit(0)
 
-    # Cough and die if user has not specified a project
+    # The project variable defaults to the name of the repository toplevel.
     if not project:
-        sys.stderr.write("ciabot.py: no project specified, bailing out.\n")
-        sys.exit(1)
-
-    # We'll need the git version number.
-    gitver = do("git --version").split()[0]
+        here = os.getcwd()
+        while True:
+            if os.path.exists(os.path.join(here, ".git")):
+                project = os.path.basename(here)
+                break
+            elif here == '/':
+                sys.stderr.write("ciabot.py: no .git below root!\n")
+                sys.exit(1)
+            here = os.path.dirname(here)
+
+    if not repo:
+        repo = project.lower()
 
     urlprefix = urlprefix % globals()
 
@@ -205,18 +221,29 @@ def report(refname, merged):
         refname = arguments[0]
         merges = arguments[1:]
 
-    if mailit:
-        import smtplib
-        server = smtplib.SMTP('localhost')
+    if notify:
+        if xmlrpc:
+            import xmlrpclib
+            server = xmlrpclib.Server('http://cia.vc/RPC2');
+        else:
+            import smtplib
+            server = smtplib.SMTP('localhost')
 
     for merged in merges:
-        message = report(refname, merged)
-        if mailit:
-            server.sendmail(fromaddr, [toaddr], message)
-        else:
+        message = report(refname, merged, xmlrpc)
+        if not notify:
             print message
+        elif xmlrpc:
+            try:
+                # RPC server is flaky, this can fail due to timeout.
+                server.hub.deliver(message)
+            except socket.error, e:
+                sys.stderr.write("%s\n" % e)
+        else:
+            server.sendmail(fromaddr, [toaddr], message)
 
-    if mailit:
-        server.quit()
+    if notify:
+        if not xmlrpc:
+            server.quit()
 
 #End
index eb87bba38e941f0d8996c17b324180337a8a2b03..3fbbc534ae668b979132f6df60c936314917d1f0 100755 (executable)
@@ -3,6 +3,8 @@
 # Copyright (c) 2006 Fernando J. Pereda <ferdy@gentoo.org>
 # Copyright (c) 2008 Natanael Copa <natanael.copa@gmail.com>
 # Copyright (c) 2010 Eric S. Raymond <esr@thyrsus.com>
+# Assistance and review by Petr Baudis, author of ciabot.pl,
+# is gratefully acknowledged.
 #
 # This is a version 3.x of ciabot.sh; use -V to find the exact
 # version.  Versions 1 and 2 were shipped in 2006 and 2008 and are not
@@ -11,6 +13,7 @@
 # Note: This script should be considered obsolete.
 # There is a faster, better-documented rewrite in Python: find it as ciabot.py
 # Use this only if your hosting site forbids Python hooks.
+# It requires: git(1), hostname(1), cut(1), sendmail(1), and wget(1).
 #
 # Originally based on Git ciabot.pl by Petr Baudis.
 # This script contains porcelain and porcelain byproducts.
 # usage: ciabot.sh [-V] [-n] [-p projectname] [refname commit]
 #
 # This script is meant to be run either in a post-commit hook or in an
-# update hook.  If there's nothing unusual about your hosting setup,
-# you can specify the project name with a -p option and avoid having
-# to modify this script.  Try it with -n first to see the notification
-# mail dumped to stdout and verify that it looks sane.  Use -V to dump
-# the version and exit.
+# update hook. Try it with -n to see the notification mail dumped to
+# stdout and verify that it looks sane. With -V it dumps its version
+# and exits.
 #
-# In post-commit, run it without arguments (other than possibly a -p
-# option). It will query for current HEAD and the latest commit ID to
-# get the information it needs.
+# In post-commit, run it without arguments. It will query for
+# current HEAD and the latest commit ID to get the information it
+# needs.
 #
 # In update, you have to call it once per merged commit:
 #
 #       oldhead=$2
 #       newhead=$3
 #       for merged in $(git rev-list ${oldhead}..${newhead} | tac) ; do
-#               /path/to/ciabot.bash ${refname} ${merged}
+#               /path/to/ciabot.sh ${refname} ${merged}
 #       done
 #
-# The reason for the tac call ids that git rev-list emits commits from
+# The reason for the tac call is that git rev-list emits commits from
 # most recent to least - better to ship notifactions from oldest to newest.
 #
-# Note: this script uses mail, not XML-RPC, in order to avoid stalling
-# until timeout when the CIA XML-RPC server is down.
+# Configuration variables affecting this script:
 #
-
+# ciabot.project = name of the project
+# ciabot.repo = name of the project repo for gitweb/cgit purposes
+# ciabot.revformat = format in which the revision is shown
 #
-# The project as known to CIA. You will either want to change this
-# or set the project name with a -p option.
+# ciabot.project defaults to the directory name of the repository toplevel.
+# ciabot.repo defaults to ciabot.project lowercased.
 #
-project=
-
+# This means that in the normal case you need not do any configuration at all,
+# but setting the project name will speed it up slightly.
 #
-# You may not need to change these:
+# The revformat variable may have the following values
+# raw -> full hex ID of commit
+# short -> first 12 chars of hex ID
+# describe = -> describe relative to last tag, falling back to short
+# The default is 'describe'.
 #
+# Note: the shell ancestors of this script used mail, not XML-RPC, in
+# order to avoid stalling until timeout when the CIA XML-RPC server is
+# down. It is unknown whether this is still an issue in 2010, but
+# XML-RPC would be annoying to do from sh in any case. (XML-RPC does
+# have the advantage that it guarantees notification of multiple commits
+# shpped from an update in their actual order.)
+#
+
+# The project as known to CIA. You can set this with a -p option,
+# or let it default to the directory name of the repo toplevel.
+project=$(git config --get ciabot.project)
+
+if [ -z $project ]
+then
+    here=`pwd`;
+    while :; do
+       if [ -d $here/.git ]
+       then
+           project=`basename $here`
+           break
+       elif [ $here = '/' ]
+       then
+           echo "ciabot.sh: no .git below root!"
+           exit 1
+       fi
+       here=`dirname $here`
+    done
+fi
 
-# Name of the repository.
-# You can hardwire this to make the script faster.
-repo="`basename ${PWD}`"
+# Name of the repo for gitweb/cgit purposes
+repo=$(git config --get ciabot.repo)
+[ -z $repo] && repo=$(echo "${project}" | tr '[A-Z]' '[a-z]')
 
-# Fully qualified domain name of the repo host.
-# You can hardwire this to make the script faster.
-host=`hostname --fqdn`
+# What revision format do we want in the summary?
+revformat=$(git config --get ciabot.revformat)
+
+# Fully qualified domain name of the repo host.  You can hardwire this
+# to make the script faster. The -f option works under Linux and FreeBSD,
+# but not OpenBSD and NetBSD. But under OpenBSD and NetBSD,
+# hostname without options gives the FQDN.
+if hostname -f >/dev/null 2>&1
+then
+    hostname=`hostname -f`
+else
+    hostname=`hostname`
+fi
 
 # Changeset URL prefix for your repo: when the commit ID is appended
 # to this, it should point at a CGI that will display the commit
@@ -73,13 +117,14 @@ urlprefix="http://${host}/cgi-bin/cgit.cgi/${repo}/commit/?id="
 # You probably will not need to change the following:
 #
 
-# Identify the script. Should change only when the script itself
-# gets a new home and maintainer.
+# Identify the script. The 'generator' variable should change only
+# when the script itself gets a new home and maintainer.
 generator="http://www.catb.org/~esr/ciabot/ciabot.sh"
+version=3.5
 
 # Addresses for the e-mail
-from="CIABOT-NOREPLY@${host}"
-to="cia@cia.navi.cx"
+from="CIABOT-NOREPLY@${hostname}"
+to="cia@cia.vc"
 
 # SMTP client to use - may need to edit the absolute pathname for your system
 sendmail="sendmail -t -f ${from}"
@@ -97,7 +142,7 @@ do
     case $opt in
        p) project=$2; shift ; shift ;;
        n) mode=dumpit; shift ;;
-       V) echo "ciabot.sh: version 3.2"; exit 0; shift ;;
+       V) echo "ciabot.sh: version $version"; exit 0; shift ;;
     esac
 done
 
@@ -128,33 +173,29 @@ fi
 
 refname=${refname##refs/heads/}
 
-gitver=$(git --version)
-gitver=${gitver##* }
-
-rev=$(git describe ${merged} 2>/dev/null)
-# ${merged:0:12} was the only bashism left in the 2008 version of this
-# script, according to checkbashisms.  Replace it with ${merged} here
-# because it was just a fallback anyway, and it's worth accepting a
-# longer fallback for faster execution and removing the bash
-# dependency.
-[ -z ${rev} ] && rev=${merged}
+case $revformat in
+raw) rev=$merged ;;
+short) rev='' ;;
+*) rev=$(git describe ${merged} 2>/dev/null) ;;
+esac
+[ -z ${rev} ] && rev=$(echo "$merged" | cut -c 1-12)
 
-# This discards the part of the author's address after @.
+# We discard the part of the author's address after @.
 # Might be nice to ship the full email address, if not
 # for spammers' address harvesters - getting this wrong
 # would make the freenode #commits channel into harvester heaven.
-rawcommit=$(git cat-file commit ${merged})
-author=$(echo "$rawcommit" | sed -n -e '/^author .*<\([^@]*\).*$/s--\1-p')
-logmessage=$(echo "$rawcommit" | sed -e '1,/^$/d' | head -n 1)
-logmessage=$(echo "$logmessage" | sed 's/\&/&amp\;/g; s/</&lt\;/g; s/>/&gt\;/g')
-ts=$(echo "$rawcommit" | sed -n -e '/^author .*> \([0-9]\+\).*$/s--\1-p')
+author=$(git log -1 '--pretty=format:%an <%ae>' $merged)
+author=$(echo "$author" | sed -n -e '/^.*<\([^@]*\).*$/s--\1-p')
+
+logmessage=$(git log -1 '--pretty=format:%s' $merged)
+ts=$(git log -1 '--pretty=format:%at' $merged)
 files=$(git diff-tree -r --name-only ${merged} | sed -e '1d' -e 's-.*-<file>&</file>-')
 
 out="
 <message>
   <generator>
     <name>CIA Shell client for Git</name>
-    <version>${gitver}</version>
+    <version>${version}</version>
     <url>${generator}</url>
   </generator>
   <source>
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 1d9783c951218fa3da82e40dce1fe8dd00dce4b1..32142dba64e0a6e926101c38b6efd95d21e0dc82 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));
        }
@@ -2539,12 +2540,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;
        }
 }
 
@@ -3185,7 +3186,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;
 
@@ -3284,8 +3285,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)
@@ -4691,6 +4690,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;
@@ -4722,9 +4722,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;
        }
 
@@ -4737,6 +4737,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)
 {
@@ -4751,6 +4752,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;
        }
@@ -4761,8 +4764,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..1101ef72378a502b1681a8e1bc306f38027974ae 100644 (file)
@@ -53,13 +53,14 @@ static void mark_child_for_cleanup(pid_t pid)
 
 static void clear_child_for_cleanup(pid_t pid)
 {
-       struct child_to_clean **last, *p;
+       struct child_to_clean **pp;
 
-       last = &children_to_clean;
-       for (p = children_to_clean; p; p = p->next) {
-               if (p->pid == pid) {
-                       *last = p->next;
-                       free(p);
+       for (pp = &children_to_clean; *pp; pp = &(*pp)->next) {
+               struct child_to_clean *clean_me = *pp;
+
+               if (clean_me->pid == pid) {
+                       *pp = clean_me->next;
+                       free(clean_me);
                        return;
                }
        }
@@ -139,6 +140,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 5580c22812be1cadd6b70974eb85ce7cda1b8df3..a1361e530c60609a52948dd0fd35642d57f84486 100644 (file)
@@ -163,7 +163,7 @@ test_perf () {
                else
                        echo "perf $test_count - $1:"
                fi
-               for i in $(seq 1 $GIT_PERF_REPEAT_COUNT); do
+               for i in $(test_seq 1 $GIT_PERF_REPEAT_COUNT); do
                        say >&3 "running: $2"
                        if test_run_perf_ "$2"
                        then
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 fadf2f258ea5305fb52d418a6409fb07889bc205..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,12 +111,30 @@ 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' '
        (
        cd "$HTTPD_DOCUMENT_ROOT_PATH/repo.git" &&
-       for i in `seq 50000`
+       for i in `test_seq 50000`
        do
                echo "commit refs/heads/too-many-refs"
                echo "mark :$i"
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 80daaca7806cbe1a6de0ddeba40400c8a811328e..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))
                        ;;
@@ -530,6 +572,27 @@ test_cmp() {
        $GIT_TEST_CMP "$@"
 }
 
+# Print a sequence of numbers or letters in increasing order.  This is
+# similar to GNU seq(1), but the latter might not be available
+# everywhere (and does not do letters).  It may be used like:
+#
+#      for i in `test_seq 100`; do
+#              for j in `test_seq 10 20`; do
+#                      for k in `test_seq a z`; do
+#                              echo $i-$j-$k
+#                      done
+#              done
+#      done
+
+test_seq () {
+       case $# in
+       1)      set 1 "$@" ;;
+       2)      ;;
+       *)      error "bug in the test script: not 1 or 2 parameters to test_seq" ;;
+       esac
+       "$PERL_PATH" -le 'print for $ARGV[0]..$ARGV[1]' -- "$@"
+}
+
 # This function can be used to schedule some commands to be run
 # unconditionally at the end of the test to restore sanity:
 #
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;