Merge branch 'maint'
authorJunio C Hamano <gitster@pobox.com>
Wed, 7 Jan 2015 21:28:29 +0000 (13:28 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 7 Jan 2015 21:28:29 +0000 (13:28 -0800)
* maint:
is_hfs_dotgit: loosen over-eager match of \u{..47}

165 files changed:
Documentation/RelNotes/2.3.0.txt [new file with mode: 0644]
Documentation/SubmittingPatches
Documentation/config.txt
Documentation/git-am.txt
Documentation/git-check-ignore.txt
Documentation/git-clone.txt
Documentation/git-imap-send.txt
Documentation/git-mailinfo.txt
Documentation/git-notes.txt
Documentation/git-send-email.txt
Documentation/git-stripspace.txt
Documentation/git-update-index.txt
Documentation/git.txt
Documentation/gitignore.txt
Documentation/technical/api-credentials.txt
Documentation/technical/api-string-list.txt
Documentation/technical/index-format.txt
GIT-VERSION-GEN
INSTALL
Makefile
RelNotes
archive.c
bisect.c
builtin/add.c
builtin/apply.c
builtin/branch.c
builtin/checkout.c
builtin/clone.c
builtin/commit.c
builtin/config.c
builtin/fmt-merge-msg.c
builtin/for-each-ref.c
builtin/help.c
builtin/index-pack.c
builtin/init-db.c
builtin/log.c
builtin/ls-tree.c
builtin/mailinfo.c
builtin/merge-base.c
builtin/merge.c
builtin/notes.c
builtin/push.c
builtin/receive-pack.c
builtin/remote.c
builtin/repack.c
builtin/rev-parse.c
builtin/unpack-objects.c
builtin/update-ref.c
cache.h
color.c
color.h
commit.c
commit.h
compat/stat.c [new file with mode: 0644]
configure.ac
connect.c
contrib/completion/git-completion.bash
contrib/completion/git-completion.zsh
contrib/completion/git-prompt.sh
contrib/diff-highlight/README
contrib/diff-highlight/diff-highlight
contrib/workdir/git-new-workdir
credential.c
credential.h
csum-file.h
date.c
diffcore-break.c
exec_cmd.c
exec_cmd.h
fsck.c
git-add--interactive.perl
git-am.sh
git-compat-util.h
git-difftool--helper.sh
git-mergetool--lib.sh
git-mergetool.sh
git-rebase--interactive.sh
git-send-email.perl
git-sh-setup.sh
git-svn.perl
git.c
imap-send.c
lockfile.c
mailmap.c
merge-recursive.c
mergetools/diffmerge
mergetools/emerge
mergetools/kdiff3
notes-merge.c
notes-utils.c
notes.c
pack-bitmap-write.c
pack-bitmap.c
pack-bitmap.h
perl/Git/SVN/Editor.pm
pkt-line.c
prompt.c
quote.c
quote.h
refs.c
refs.h
remote.c
revision.c
run-command.c
run-command.h
sequencer.c
sequencer.h
sha1_file.c
sha1_name.c
strbuf.c
string-list.c
string-list.h
submodule.c
t/README
t/lib-gpg.sh
t/lib-gpg/keyring.gpg [new file with mode: 0644]
t/lib-gpg/ownertrust [new file with mode: 0644]
t/lib-gpg/pubring.gpg [deleted file]
t/lib-gpg/random_seed [deleted file]
t/lib-gpg/secring.gpg [deleted file]
t/lib-gpg/trustdb.gpg [deleted file]
t/lib-httpd/apache.conf
t/t0006-date.sh
t/t0027-auto-crlf.sh
t/t0030-stripspace.sh
t/t0050-filesystem.sh
t/t0090-cache-tree.sh
t/t0300-credentials.sh
t/t1400-update-ref.sh
t/t1410-reflog.sh
t/t1450-fsck.sh
t/t2024-checkout-dwim.sh
t/t2107-update-index-basic.sh
t/t3102-ls-tree-wildcards.sh
t/t3200-branch.sh
t/t3301-notes.sh
t/t3507-cherry-pick-conflict.sh
t/t3700-add.sh
t/t4008-diff-break-rewrite.sh
t/t4023-diff-rename-typechange.sh
t/t4026-color.sh
t/t4150-am.sh
t/t5000-tar-tree.sh
t/t5100-mailinfo.sh
t/t5100/info0012--message-id [new file with mode: 0644]
t/t5100/msg0012--message-id [new file with mode: 0644]
t/t5100/patch0012--message-id [new file with mode: 0644]
t/t5400-send-pack.sh
t/t5516-fetch-push.sh
t/t5527-fetch-odd-refs.sh
t/t5700-clone-reference.sh
t/t7004-tag.sh
t/t7513-interpret-trailers.sh
t/t9001-send-email.sh
t/t9148-git-svn-propset.sh [new file with mode: 0755]
t/test-lib.sh
templates/hooks--pre-push.sample
test-hashmap.c
trace.c
trailer.c
tree.c
tree.h
unpack-trees.c
update_unicode.sh
wt-status.c
diff --git a/Documentation/RelNotes/2.3.0.txt b/Documentation/RelNotes/2.3.0.txt
new file mode 100644 (file)
index 0000000..1b1dcbb
--- /dev/null
@@ -0,0 +1,165 @@
+Git v2.3 Release Notes
+======================
+
+Updates since v2.2
+------------------
+
+Ports
+
+ * Recent gcc toolchain on Cygwin started throwing compilation warning,
+   which has been squelched.
+
+
+UI, Workflows & Features
+
+ * It was cumbersome to use "GIT_SSH" mechanism when the user wanted
+   to pass an extra set of arguments to the underlying ssh.  A new
+   environment variable GIT_SSH_COMMAND can be used for this.
+
+ * A request to store an empty note via "git notes" meant to remove
+   note from the object but with --allow-empty we will store a
+   (surprise!)  note that is empty.
+
+ * "git interpret-trailers" learned to properly handle the
+   "Conflicts:" block at the end.
+
+ * "git am" learned "--message-id" option to copy the message ID of
+   the incoming e-mail to the log message of resulting commit.
+
+ * "git send-email" learned "--transfer-encoding" option to force a
+   non-fault Content-Transfer-Encoding header (e.g. base64).
+
+ * "git push" into a repository with a working tree normally refuses
+   to modify the branch that is checked out.  The command learned to
+   optionally do an equivalent of "git reset --hard" only when there
+   is no change to the working tree and the index instead, which would
+   be useful to "deploy" by pushing into a repository.
+
+ * "git new-workdir" (in contrib/) can be used to populate an empty
+   and existing directory now.
+
+ * Credential helpers are asked in turn until one of them give
+   positive response, which is cumbersome to turn off when you need to
+   run Git in an automated setting.  The credential helper interface
+   learned to allow a helper to say "stop, don't ask other helpers."
+   Also GIT_TERMINAL_PROMPT environment can be set to false to disable
+   our built-in prompt mechanism for passwords.
+
+ * "git branch -d" (delete) and "git branch -m" (move) learned to
+   honor "-f" (force) flag; unlike many other subcommands, the way to
+   force these have been with separate "-D/-M" options, which was
+   inconsistent.
+
+ * "diff-highlight" filter (in contrib/) allows its color output to be
+   customized via configuration variables.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Some filesystems assign filemodes in a strange way, fooling then
+   automatic "filemode trustability" check done during a new
+   repository creation.  The initialization codepath has been hardened
+   against this issue.
+
+ * The codepath in "git remote update --prune" to drop many refs has
+   been optimized.
+
+ * Long overdue departure from the assumption that S_IFMT is shared by
+   everybody made in 2005, which was necessary to port to z/OS.
+
+ * "git push" and "git fetch" did not communicate an overlong refname
+   correctly.  Now it uses 64kB sideband to accommodate longer ones.
+
+ * Recent GPG changes the keyring format and drops support for RFC1991
+   formatted signatures, breaking our existing tests.
+
+ * "git-prompt" (in contrib/) used a variable from the global scope,
+   possibly contaminating end-user's namespace.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.2
+----------------
+
+Unless otherwise noted, all the fixes since v2.2 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * Recent update to "git commit" broke amending an existing commit
+   with bogus author/committer lines without a valid e-mail address.
+   (merge c83a509 jk/commit-date-approxidate later to maint).
+
+ * Git did not correctly read an overlong refname from a packed refs
+   file.
+   (merge ea41783 jk/read-packed-refs-without-path-max later to maint).
+
+ * "git apply" was described in the documentation to take --ignore-date
+   option, which it does not.
+   (merge 0cef4e7 rw/apply-does-not-take-ignore-date later to maint).
+
+ * New tag object format validation added in 2.2 showed garbage after
+   a tagname it reported in its error message.
+   (merge a1e920a js/fsck-tag-validation later to maint).
+
+ * The code that reads the reflog from the newer to the older entries
+   did not handle an entry that crosses a boundary of block it uses to
+   read them correctly.
+   (merge 69216bf jk/for-each-reflog-ent-reverse later to maint).
+
+ * "git ls-tree" does not support path selection based on negative
+   pathspecs, but did not error out when negative pathspecs are given.
+   (merge f1f6224 nd/ls-tree-pathspec later to maint).
+
+ * The function sometimes returned a non-freeable memory and some
+   other times returned a piece of memory that must be freed, leading
+   to inevitable leaks.
+   (merge 59362e5 jc/exec-cmd-system-path-leak-fix later to maint).
+
+ * The code to abbreviate an object name to its short unique prefix
+   has been optimized when no abbreviation was requested.
+   (merge 61e704e mh/find-uniq-abbrev later to maint).
+
+ * "git add --ignore-errors ..." did not ignore an error to
+   give a file that did not exist.
+   (merge 1d31e5a mg/add-ignore-errors later to maint).
+
+ * "git checkout $treeish $path", when $path in the index and the
+   working tree already matched what is in $treeish at the $path,
+   still overwrote the $path unnecessarily.
+   (merge c5326bd jk/checkout-from-tree later to maint).
+
+ * "git config --get-color" did not parse its command line arguments
+   carefully.
+   (merge cb35722 jk/colors-fix later to maint).
+
+ * open() emulated on Windows platforms did not give EISDIR upon
+   an attempt to open a directory for writing.
+   (merge ba6fad0 js/windows-open-eisdir-error later to maint).
+
+ * A few code paths used abs() when they should have used labs() on
+   long integers.
+   (merge 83915ba rs/maint-config-use-labs later to maint).
+   (merge 31a8aa1 rs/receive-pack-use-labs later to maint).
+
+ * "gitweb" used to depend on a behaviour recent CGI.pm deprecated.
+   (merge 13dbf46 jk/gitweb-with-newer-cgi-multi-param later to maint).
+
+ * "git init" (hence "git clone") initialized the per-repository
+   configuration file .git/config with x-bit by mistake.
+   (merge 1f32ecf mh/config-flip-xbit-back-after-checking later to maint).
+
+ * Git 2.0 was supposed to make the "simple" mode for the default of
+   "git push", but it didn't.
+   (merge 00a6fa0 jk/push-simple later to maint).
+
+ * "Everyday" document had a broken link.
+   (merge 366c8d4 po/everyday-doc later to maint).
+
+ * A few test fixes.
+   (merge 880ef58 jk/no-perl-tests later to maint).
+
+ * The build procedure did not bother fixing perl and python scripts
+   when NO_PERL and NO_PYTHON build-time configuration changed.
+   (merge ca2051d jk/rebuild-perl-scripts-with-no-perl-seting-change later to maint).
index fa71b5f0b62f43483d02c24d809e6282fa49576a..16d5d2be0880621741e7100e3cd87fdfb8fd5f38 100644 (file)
@@ -57,7 +57,8 @@ change, the approach taken by the change, and if relevant how this
 differs substantially from the prior version, are all good things
 to have.
 
-Make sure that you have tests for the bug you are fixing.
+Make sure that you have tests for the bug you are fixing.  See
+t/README for guidance.
 
 When adding a new feature, make sure that you have new tests to show
 the feature triggers the new behaviour when it should, and to show the
@@ -254,15 +255,15 @@ pretty simple: if you can certify the below:
             person who certified (a), (b) or (c) and I have not modified
             it.
 
-       (d) I understand and agree that this project and the contribution
-           are public and that a record of the contribution (including all
-           personal information I submit with it, including my sign-off) is
-           maintained indefinitely and may be redistributed consistent with
-           this project or the open source license(s) involved.
+        (d) I understand and agree that this project and the contribution
+            are public and that a record of the contribution (including all
+            personal information I submit with it, including my sign-off) is
+            maintained indefinitely and may be redistributed consistent with
+            this project or the open source license(s) involved.
 
 then you just add a line saying
 
-       Signed-off-by: Random J Developer <random@developer.example.org>
+        Signed-off-by: Random J Developer <random@developer.example.org>
 
 This line can be automatically added by Git if you run the git-commit
 command with the -s option.
index 9335ff2ae29c532f82bbb18220a3a2ea3531b8b4..cc887b1279cb04c33cc2e67c373c6ed61daff520 100644 (file)
@@ -849,11 +849,13 @@ accepted are `normal`, `black`, `red`, `green`, `yellow`, `blue`,
 `magenta`, `cyan` and `white`; the attributes are `bold`, `dim`, `ul`,
 `blink` and `reverse`.  The first color given is the foreground; the
 second is the background.  The position of the attribute, if any,
-doesn't matter.
+doesn't matter. Attributes may be turned off specifically by prefixing
+them with `no` (e.g., `noreverse`, `noul`, etc).
 +
 Colors (foreground and background) may also be given as numbers between
 0 and 255; these use ANSI 256-color mode (but note that not all
-terminals may support this).
+terminals may support this).  If your terminal supports it, you may also
+specify 24-bit RGB values as hex, like `#ff0ab3`.
 
 color.diff::
        Whether to use ANSI escape sequences to add color to patches.
@@ -2144,6 +2146,13 @@ receive.denyCurrentBranch::
        print a warning of such a push to stderr, but allow the push to
        proceed. If set to false or "ignore", allow such pushes with no
        message. Defaults to "refuse".
++
+Another option is "updateInstead" which will update the working
+directory (must be clean) if pushing into the current branch. This option is
+intended for synchronizing working directories when one side is not easily
+accessible via interactive ssh (e.g. a live web site, hence the requirement
+that the working directory be clean). This mode also comes in handy when
+developing inside a VM to test and fix code on different Operating Systems.
 
 receive.denyNonFastForwards::
        If set to true, git-receive-pack will deny a ref update which is
@@ -2318,7 +2327,9 @@ sendemail.smtpserverport::
 sendemail.smtpserveroption::
 sendemail.smtpuser::
 sendemail.thread::
+sendemail.transferencoding::
 sendemail.validate::
+sendemail.xmailer::
        See linkgit:git-send-email[1] for description.
 
 sendemail.signedoffcc::
index 9adce372ec6e6ec0d371c411da1e5002baea5f51..f4eea28dc4d03e02f9af3eedba5d15743b8553f6 100644 (file)
@@ -57,6 +57,17 @@ OPTIONS
 --no-scissors::
        Ignore scissors lines (see linkgit:git-mailinfo[1]).
 
+-m::
+--message-id::
+       Pass the `-m` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]),
+       so that the Message-ID header is added to the commit message.
+       The `am.messageid` configuration variable can be used to specify
+       the default behaviour.
+
+--no-message-id::
+       Do not add the Message-ID header to the commit message.
+       `no-message-id` is useful to override `am.messageid`.
+
 -q::
 --quiet::
        Be quiet. Only print error messages.
@@ -83,7 +94,6 @@ default.   You can use `--no-utf8` to override this.
        it is supposed to apply to and we have those blobs
        available locally.
 
---ignore-date::
 --ignore-space-change::
 --ignore-whitespace::
 --whitespace=<option>::
index ee2e0917040909bd62df073e20f1120c23a43a63..788a0115805214f4169c50279d94cd31e5f0becc 100644 (file)
@@ -21,6 +21,9 @@ the exclude mechanism) that decides if the pathname is excluded or
 included.  Later patterns within a file take precedence over earlier
 ones.
 
+By default, tracked files are not shown at all since they are not
+subject to exclude rules; but see `--no-index'.
+
 OPTIONS
 -------
 -q, --quiet::
index 0363d0039b274093e6d230a83fcf99c3ff6700d8..f1f2a3f7ea92282756a0b2b72271469561b442df 100644 (file)
@@ -12,7 +12,7 @@ SYNOPSIS
 'git clone' [--template=<template_directory>]
          [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]
          [-o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>]
-         [--separate-git-dir <git dir>]
+         [--dissociate] [--separate-git-dir <git dir>]
          [--depth <depth>] [--[no-]single-branch]
          [--recursive | --recurse-submodules] [--] <repository>
          [<directory>]
@@ -98,7 +98,14 @@ objects from the source repository into a pack in the cloned repository.
        require fewer objects to be copied from the repository
        being cloned, reducing network and local storage costs.
 +
-*NOTE*: see the NOTE for the `--shared` option.
+*NOTE*: see the NOTE for the `--shared` option, and also the
+`--dissociate` option.
+
+--dissociate::
+       Borrow the objects from reference repositories specified
+       with the `--reference` options only to reduce network
+       transfer and stop borrowing from them after a clone is made
+       by making necessary local copies of borrowed objects.
 
 --quiet::
 -q::
index c7c0d21429bb745d1abcfc775308e8ccac8f499a..77aacf130936435970a945e4d687d01c12b1a0f9 100644 (file)
@@ -9,7 +9,7 @@ git-imap-send - Send a collection of patches from stdin to an IMAP folder
 SYNOPSIS
 --------
 [verse]
-'git imap-send'
+'git imap-send' [-v] [-q] [--[no-]curl]
 
 
 DESCRIPTION
@@ -26,6 +26,27 @@ Typical usage is something like:
 git format-patch --signoff --stdout --attach origin | git imap-send
 
 
+OPTIONS
+-------
+
+-v::
+--verbose::
+       Be verbose.
+
+-q::
+--quiet::
+       Be quiet.
+
+--curl::
+       Use libcurl to communicate with the IMAP server, unless tunneling
+       into it.  Ignored if Git was built without the USE_CURL_FOR_IMAP_SEND
+       option set.
+
+--no-curl::
+       Talk to the IMAP server using git's own IMAP routines instead of
+       using libcurl.
+
+
 CONFIGURATION
 -------------
 
@@ -75,7 +96,9 @@ imap.preformattedHTML::
 
 imap.authMethod::
        Specify authenticate method for authentication with IMAP server.
-       Current supported method is 'CRAM-MD5' only. If this is not set
+       If Git was built with the NO_CURL option, or if your curl version is older
+       than 7.34.0, or if you're running git-imap-send with the `--no-curl`
+       option, the only supported method is 'CRAM-MD5'. If this is not set
        then 'git imap-send' uses the basic IMAP plaintext LOGIN command.
 
 Examples
index 164a3c6ede9be2c3a42cf0ba3612403114d4dde5..0947084140f217a4e7fe1d6fa203e4d7e9a36ffe 100644 (file)
@@ -66,6 +66,11 @@ conversion, even with this flag.
 -n::
        Disable all charset re-coding of the metadata.
 
+-m::
+--message-id::
+       Copy the Message-ID header at the end of the commit message.  This
+       is useful in order to associate commits with mailing list discussions.
+
 --scissors::
        Remove everything in body before a scissors line.  A line that
        mainly consists of scissors (either ">8" or "8<") and perforation
index 310f0a5e8c1819f1f49e00b78aacface36ac21ad..851518d531b53966dc6dca1321c71e8381f50e7b 100644 (file)
@@ -9,10 +9,10 @@ SYNOPSIS
 --------
 [verse]
 'git notes' [list [<object>]]
-'git notes' add [-f] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
+'git notes' add [-f] [--allow-empty] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
 'git notes' copy [-f] ( --stdin | <from-object> <to-object> )
-'git notes' append [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
-'git notes' edit [<object>]
+'git notes' append [--allow-empty] [-F <file> | -m <msg> | (-c | -C) <object>] [<object>]
+'git notes' edit [--allow-empty] [<object>]
 'git notes' show [<object>]
 'git notes' merge [-v | -q] [-s <strategy> ] <notes-ref>
 'git notes' merge --commit [-v | -q]
@@ -155,6 +155,10 @@ OPTIONS
        Like '-C', but with '-c' the editor is invoked, so that
        the user can further edit the note message.
 
+--allow-empty::
+       Allow an empty note object to be stored. The default behavior is
+       to automatically remove empty notes.
+
 --ref <ref>::
        Manipulate the notes tree in <ref>.  This overrides
        'GIT_NOTES_REF' and the "core.notesRef" configuration.  The ref
@@ -287,7 +291,7 @@ arbitrary files using 'git hash-object':
 ------------
 $ cc *.c
 $ blob=$(git hash-object -w a.out)
-$ git notes --ref=built add -C "$blob" HEAD
+$ git notes --ref=built add --allow-empty -C "$blob" HEAD
 ------------
 
 (You cannot simply use `git notes --ref=built add -F a.out HEAD`
index a60776eb579e10507814c643cc292dfa99750aa9..e04849e3961257500f86441611e738e9b4d0f330 100644 (file)
@@ -131,6 +131,21 @@ Note that no attempts whatsoever are made to validate the encoding.
        Specify encoding of compose message. Default is the value of the
        'sendemail.composeencoding'; if that is unspecified, UTF-8 is assumed.
 
+--transfer-encoding=(7bit|8bit|quoted-printable|base64)::
+       Specify the transfer encoding to be used to send the message over SMTP.
+       7bit will fail upon encountering a non-ASCII message.  quoted-printable
+       can be useful when the repository contains files that contain carriage
+       returns, but makes the raw patch email file (as saved from a MUA) much
+       harder to inspect manually.  base64 is even more fool proof, but also
+       even more opaque.  Default is the value of the 'sendemail.transferEncoding'
+       configuration value; if that is unspecified, git will use 8bit and not
+       add a Content-Transfer-Encoding header.
+
+--xmailer::
+--no-xmailer::
+       Add (or prevent adding) the "X-Mailer:" header.  By default,
+       the header is added, but it can be turned off by setting the
+       `sendemail.xmailer` configuration variable to `false`.
 
 Sending
 ~~~~~~~
index c87bfcb674b9a1026ab0d7b8e4907d538c99c7e5..6c6e989074c58840ca1c8c4e6f4cad0b8fdb718d 100644 (file)
@@ -10,6 +10,7 @@ SYNOPSIS
 --------
 [verse]
 'git stripspace' [-s | --strip-comments] < input
+'git stripspace' [-c | --comment-lines] < input
 
 DESCRIPTION
 -----------
index 929869b0a0576b8c60a685af2fd6b236e3b4bf1d..aff01798cdf6b114009eae8dfc4f2866a8a24d17 100644 (file)
@@ -82,20 +82,18 @@ OPTIONS
         Set the execute permissions on the updated files.
 
 --[no-]assume-unchanged::
-       When these flags are specified, the object names recorded
-       for the paths are not updated.  Instead, these options
-       set and unset the "assume unchanged" bit for the
-       paths.  When the "assume unchanged" bit is on, Git stops
-       checking the working tree files for possible
-       modifications, so you need to manually unset the bit to
-       tell Git when you change the working tree file. This is
+       When this flag is specified, the object names recorded
+       for the paths are not updated.  Instead, this option
+       sets/unsets the "assume unchanged" bit for the
+       paths.  When the "assume unchanged" bit is on, the user
+       promises not to change the file and allows Git to assume
+       that the working tree file matches what is recorded in
+       the index.  If you want to change the working tree file,
+       you need to unset the bit to tell Git.  This is
        sometimes helpful when working with a big project on a
        filesystem that has very slow lstat(2) system call
        (e.g. cifs).
 +
-This option can be also used as a coarse file-level mechanism
-to ignore uncommitted changes in tracked files (akin to what
-`.gitignore` does for untracked files).
 Git will fail (gracefully) in case it needs to modify this file
 in the index e.g. when merging in a commit;
 thus, in case the assumed-untracked file is changed upstream,
index db4e407bb16a3233cc5c57c05f73ecee9b49b588..179615195fd260d4d6d87bc1cda6f5c8a699719d 100644 (file)
@@ -886,19 +886,21 @@ other
        and the `core.editor` option in linkgit:git-config[1].
 
 'GIT_SSH'::
-       If this environment variable is set then 'git fetch'
-       and 'git push' will use this command instead
-       of 'ssh' when they need to connect to a remote system.
-       The '$GIT_SSH' command will be given exactly two or
-       four arguments: the 'username@host' (or just 'host')
-       from the URL and the shell command to execute on that
-       remote system, optionally preceded by '-p' (literally) and
-       the 'port' from the URL when it specifies something other
-       than the default SSH port.
+'GIT_SSH_COMMAND'::
+       If either of these environment variables is set then 'git fetch'
+       and 'git push' will use the specified command instead of 'ssh'
+       when they need to connect to a remote system.
+       The command will be given exactly two or four arguments: the
+       'username@host' (or just 'host') from the URL and the shell
+       command to execute on that remote system, optionally preceded by
+       '-p' (literally) and the 'port' from the URL when it specifies
+       something other than the default SSH port.
 +
-To pass options to the program that you want to list in GIT_SSH
-you will need to wrap the program and options into a shell script,
-then set GIT_SSH to refer to the shell script.
+`$GIT_SSH_COMMAND` takes precedence over `$GIT_SSH`, and is interpreted
+by the shell, which allows additional arguments to be included.
+`$GIT_SSH` on the other hand must be just the path to a program
+(which can be a wrapper shell script, if additional arguments are
+needed).
 +
 Usually it is easier to configure any desired options through your
 personal `.ssh/config` file.  Please consult your ssh documentation
@@ -911,6 +913,10 @@ for further details.
        and read the password from its STDOUT. See also the 'core.askpass'
        option in linkgit:git-config[1].
 
+'GIT_TERMINAL_PROMPT'::
+       If this environment variable is set to `0`, git will not prompt
+       on the terminal (e.g., when asking for HTTP authentication).
+
 'GIT_CONFIG_NOSYSTEM'::
        Whether to skip reading settings from the system-wide
        `$(prefix)/etc/gitconfig` file.  This environment variable can
index 09e82c31bd320a162689a7f2d919de439d05375a..4fd04423e9342e05d34b4a72a4e1af802b8c10c8 100644 (file)
@@ -138,9 +138,6 @@ NOTES
 The purpose of gitignore files is to ensure that certain files
 not tracked by Git remain untracked.
 
-To ignore uncommitted changes in a file that is already tracked,
-use 'git update-index {litdd}assume-unchanged'.
-
 To stop tracking a file that is currently tracked, use
 'git rm --cached'.
 
@@ -203,7 +200,6 @@ everything within `foo/bar`):
 SEE ALSO
 --------
 linkgit:git-rm[1],
-linkgit:git-update-index[1],
 linkgit:gitrepository-layout[5],
 linkgit:git-check-ignore[1]
 
index c1b42a40d3c0c297994cd2966b60cd48629e57fa..e44426dd041516b8d9220ce9f1b2413be0319703 100644 (file)
@@ -248,7 +248,10 @@ FORMAT` in linkgit:git-credential[7] for a detailed specification).
 For a `get` operation, the helper should produce a list of attributes
 on stdout in the same format. A helper is free to produce a subset, or
 even no values at all if it has nothing useful to provide. Any provided
-attributes will overwrite those already known about by Git.
+attributes will overwrite those already known about by Git.  If a helper
+outputs a `quit` attribute with a value of `true` or `1`, no further
+helpers will be consulted, nor will the user be prompted (if no
+credential has been provided, the operation will then fail).
 
 For a `store` or `erase` operation, the helper's output is ignored.
 If it fails to perform the requested operation, it may complain to
index d51a6579c85f7417708f918cf9807447b1508e3c..c08402b12e88930ca37cce6d3b4537d7f360852f 100644 (file)
@@ -29,7 +29,7 @@ member (you need this if you add things later) and you should set the
   `unsorted_string_list_has_string` and get it from the list using
   `string_list_lookup` for sorted lists.
 
-. Can sort an unsorted list using `sort_string_list`.
+. Can sort an unsorted list using `string_list_sort`.
 
 . Can remove duplicate items from a sorted list using
   `string_list_remove_duplicates`.
@@ -146,7 +146,7 @@ write `string_list_insert(...)->util = ...;`.
        ownership of a malloc()ed string to a `string_list` that has
        `strdup_string` set.
 
-`sort_string_list`::
+`string_list_sort`::
 
        Sort the list's entries by string value in `strcmp()` order.
 
index 1250b5ca8b8abc0d1da0bb94d8391fb14f155693..35112e4966f9b021b0889d734d5cb945b8943003 100644 (file)
@@ -207,7 +207,7 @@ Git index format
   in a separate file. This extension records the changes to be made on
   top of that to produce the final index.
 
-  The signature for this extension is { 'l', 'i, 'n', 'k' }.
+  The signature for this extension is { 'l', 'i', 'n', 'k' }.
 
   The extension consists of:
 
index 495ddb7d25026d5c8e6c95766b3023f58b3f4355..53dd6b328563c143181a932c119754c62b4dc9b3 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.2.1
+DEF_VER=v2.2.0.GIT
 
 LF='
 '
diff --git a/INSTALL b/INSTALL
index 6ec7a24e1a7ff1d9bb380e6c9bdb1c16dbf5d1c1..ffb071e9f03a79a052beaa4372fa790ecbabbb7b 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -108,18 +108,21 @@ Issues of note:
          so you might need to install additional packages other than Perl
          itself, e.g. Time::HiRes.
 
-       - "openssl" library is used by git-imap-send to use IMAP over SSL.
-         If you don't need it, use NO_OPENSSL.
+       - git-imap-send needs the OpenSSL library to talk IMAP over SSL if
+         you are using libcurl older than 7.34.0.  Otherwise you can use
+         NO_OPENSSL without losing git-imap-send.
 
          By default, git uses OpenSSL for SHA1 but it will use its own
          library (inspired by Mozilla's) with either NO_OPENSSL or
          BLK_SHA1.  Also included is a version optimized for PowerPC
          (PPC_SHA1).
 
-       - "libcurl" library is used by git-http-fetch and git-fetch.  You
-         might also want the "curl" executable for debugging purposes.
-         If you do not use http:// or https:// repositories, you do not
-         have to have them (use NO_CURL).
+       - "libcurl" library is used by git-http-fetch, git-fetch, and, if
+         the curl version >= 7.34.0, for git-imap-send.  You might also
+         want the "curl" executable for debugging purposes. If you do not
+         use http:// or https:// repositories, and do not want to put
+         patches into an IMAP mailbox, you do not have to have them
+         (use NO_CURL).
 
        - "expat" library; git-http-push uses it for remote lock
          management over DAV.  Similar to "curl" above, this is optional
index 7482a4dbab458b1b82a7cb683ce7dc6f41fd4145..06e5d24312e47e9a6e7e33def74c70f54c21f2e1 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -191,6 +191,10 @@ all::
 # Define NO_TRUSTABLE_FILEMODE if your filesystem may claim to support
 # the executable mode bit, but doesn't really do so.
 #
+# Define NEEDS_MODE_TRANSLATION if your OS strays from the typical file type
+# bits in mode values (e.g. z/OS defines I_SFMT to 0xFF000000 as opposed to the
+# usual 0xF000).
+#
 # Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
 #
 # Define NO_UNIX_SOCKETS if your system does not offer unix sockets.
@@ -995,6 +999,9 @@ ifdef HAVE_ALLOCA_H
        BASIC_CFLAGS += -DHAVE_ALLOCA_H
 endif
 
+IMAP_SEND_BUILDDEPS =
+IMAP_SEND_LDFLAGS = $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)
+
 ifdef NO_CURL
        BASIC_CFLAGS += -DNO_CURL
        REMOTE_CURL_PRIMARY =
@@ -1029,6 +1036,15 @@ else
                        PROGRAM_OBJS += http-push.o
                endif
        endif
+       curl_check := $(shell (echo 072200; curl-config --vernum) 2>/dev/null | sort -r | sed -ne 2p)
+       ifeq "$(curl_check)" "072200"
+               USE_CURL_FOR_IMAP_SEND = YesPlease
+       endif
+       ifdef USE_CURL_FOR_IMAP_SEND
+               BASIC_CFLAGS += -DUSE_CURL_FOR_IMAP_SEND
+               IMAP_SEND_BUILDDEPS = http.o
+               IMAP_SEND_LDFLAGS += $(CURL_LIBCURL)
+       endif
        ifndef NO_EXPAT
                ifdef EXPATDIR
                        BASIC_CFLAGS += -I$(EXPATDIR)/include
@@ -1230,6 +1246,10 @@ endif
 ifdef NO_TRUSTABLE_FILEMODE
        BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE
 endif
+ifdef NEEDS_MODE_TRANSLATION
+       COMPAT_CFLAGS += -DNEEDS_MODE_TRANSLATION
+       COMPAT_OBJS += compat/stat.o
+endif
 ifdef NO_IPV6
        BASIC_CFLAGS += -DNO_IPV6
 endif
@@ -1880,7 +1900,7 @@ gettext.sp gettext.s gettext.o: GIT-PREFIX
 gettext.sp gettext.s gettext.o: EXTRA_CPPFLAGS = \
        -DGIT_LOCALE_PATH='"$(localedir_SQ)"'
 
-http-push.sp http.sp http-walker.sp remote-curl.sp: SPARSE_FLAGS += \
+http-push.sp http.sp http-walker.sp remote-curl.sp imap-send.sp: SPARSE_FLAGS += \
        -DCURL_DISABLE_TYPECHECK
 
 ifdef NO_EXPAT
@@ -1901,9 +1921,9 @@ endif
 git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 
-git-imap-send$X: imap-send.o GIT-LDFLAGS $(GITLIBS)
+git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
-               $(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)
+               $(LIBS) $(IMAP_SEND_LDFLAGS)
 
 git-http-fetch$X: http.o http-walker.o http-fetch.o GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
index c5fa3efb98246d99bdf736237b7cf759f01a1657..9257c74b5cff52da962e55a4f96d0b9d974cf362 120000 (symlink)
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.2.2.txt
\ No newline at end of file
+Documentation/RelNotes/2.3.0.txt
\ No newline at end of file
index 94a9981adf72c437f8660c66b67506b50ed8d3a9..9e30246b6402454e8d92fb6aa24a1a07c534b0ef 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -157,18 +157,26 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
        return write_entry(args, sha1, path.buf, path.len, mode);
 }
 
+static int write_archive_entry_buf(const unsigned char *sha1, struct strbuf *base,
+               const char *filename, unsigned mode, int stage,
+               void *context)
+{
+       return write_archive_entry(sha1, base->buf, base->len,
+                                    filename, mode, stage, context);
+}
+
 static void queue_directory(const unsigned char *sha1,
-               const char *base, int baselen, const char *filename,
+               struct strbuf *base, const char *filename,
                unsigned mode, int stage, struct archiver_context *c)
 {
        struct directory *d;
-       d = xmallocz(sizeof(*d) + baselen + 1 + strlen(filename));
+       d = xmallocz(sizeof(*d) + base->len + 1 + strlen(filename));
        d->up      = c->bottom;
-       d->baselen = baselen;
+       d->baselen = base->len;
        d->mode    = mode;
        d->stage   = stage;
        c->bottom  = d;
-       d->len = sprintf(d->path, "%.*s%s/", baselen, base, filename);
+       d->len = sprintf(d->path, "%.*s%s/", (int)base->len, base->buf, filename);
        hashcpy(d->sha1, sha1);
 }
 
@@ -191,28 +199,28 @@ static int write_directory(struct archiver_context *c)
 }
 
 static int queue_or_write_archive_entry(const unsigned char *sha1,
-               const char *base, int baselen, const char *filename,
+               struct strbuf *base, const char *filename,
                unsigned mode, int stage, void *context)
 {
        struct archiver_context *c = context;
 
        while (c->bottom &&
-              !(baselen >= c->bottom->len &&
-                !strncmp(base, c->bottom->path, c->bottom->len))) {
+              !(base->len >= c->bottom->len &&
+                !strncmp(base->buf, c->bottom->path, c->bottom->len))) {
                struct directory *next = c->bottom->up;
                free(c->bottom);
                c->bottom = next;
        }
 
        if (S_ISDIR(mode)) {
-               queue_directory(sha1, base, baselen, filename,
+               queue_directory(sha1, base, filename,
                                mode, stage, c);
                return READ_TREE_RECURSIVE;
        }
 
        if (write_directory(c))
                return -1;
-       return write_archive_entry(sha1, base, baselen, filename, mode,
+       return write_archive_entry(sha1, base->buf, base->len, filename, mode,
                                   stage, context);
 }
 
@@ -260,7 +268,7 @@ int write_archive_entries(struct archiver_args *args,
        err = read_tree_recursive(args->tree, "", 0, 0, &args->pathspec,
                                  args->pathspec.has_wildcard ?
                                  queue_or_write_archive_entry :
-                                 write_archive_entry,
+                                 write_archive_entry_buf,
                                  &context);
        if (err == READ_TREE_RECURSIVE)
                err = 0;
@@ -286,14 +294,14 @@ static const struct archiver *lookup_archiver(const char *name)
        return NULL;
 }
 
-static int reject_entry(const unsigned char *sha1, const char *base,
-                       int baselen, const char *filename, unsigned mode,
+static int reject_entry(const unsigned char *sha1, struct strbuf *base,
+                       const char *filename, unsigned mode,
                        int stage, void *context)
 {
        int ret = -1;
        if (S_ISDIR(mode)) {
                struct strbuf sb = STRBUF_INIT;
-               strbuf_addstr(&sb, base);
+               strbuf_addbuf(&sb, base);
                strbuf_addstr(&sb, filename);
                if (!match_pathspec(context, sb.buf, sb.len, 0, NULL, 1))
                        ret = READ_TREE_RECURSIVE;
index df09cbc8cabe9dcb87a0023445babcf14c3d7691..8c6d843699ab04bc0fe952268d14965943446a17 100644 (file)
--- a/bisect.c
+++ b/bisect.c
@@ -777,7 +777,7 @@ static void check_merge_bases(int no_checkout)
        int rev_nr;
        struct commit **rev = get_bad_and_good_commits(&rev_nr);
 
-       result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1, 0);
+       result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1);
 
        for (; result; result = result->next) {
                const unsigned char *mb = result->item->object.sha1;
index ae6d3e262bcbb3dc57c0ddf146791380259b31be..1074e3234964deb279c3a487e9efd164afdb9c6c 100644 (file)
@@ -284,7 +284,7 @@ static int add_files(struct dir_struct *dir, int flags)
                for (i = 0; i < dir->ignored_nr; i++)
                        fprintf(stderr, "%s\n", dir->ignored[i]->name);
                fprintf(stderr, _("Use -f if you really want to add them.\n"));
-               die(_("no files added"));
+               exit_status = 1;
        }
 
        for (i = 0; i < dir->nr; i++)
index 6696ea4c3ffd4f7af04f3f56609a78a74a0a0b55..0aad91283959bce51aba596c6f3d2d0925e5ba92 100644 (file)
@@ -3728,7 +3728,7 @@ static void build_fake_ancestor(struct patch *list, const char *filename)
                        if (!preimage_sha1_in_gitlink_patch(patch, sha1))
                                ; /* ok, the textual part looks sane */
                        else
-                               die("sha1 information is lacking or useless for submoule %s",
+                               die("sha1 information is lacking or useless for submodule %s",
                                    name);
                } else if (!get_sha1_blob(patch->old_sha1_prefix, sha1)) {
                        ; /* ok */
@@ -4180,7 +4180,7 @@ static int write_out_results(struct patch *list)
        if (cpath.nr) {
                struct string_list_item *item;
 
-               sort_string_list(&cpath);
+               string_list_sort(&cpath);
                for_each_string_list_item(item, &cpath)
                        fprintf(stderr, "U %s\n", item->string);
                string_list_clear(&cpath, 0);
index 3b79c5087fbf1157d1bdfa2cccc99547f8abdb09..dc6f0b266c9cf621486b9dba111c2e7b37d3bc1b 100644 (file)
@@ -800,7 +800,7 @@ static int edit_branch_description(const char *branch_name)
 
 int cmd_branch(int argc, const char **argv, const char *prefix)
 {
-       int delete = 0, rename = 0, force_create = 0, list = 0;
+       int delete = 0, rename = 0, force = 0, list = 0;
        int verbose = 0, abbrev = -1, detached = 0;
        int reflog = 0, edit_description = 0;
        int quiet = 0, unset_upstream = 0;
@@ -848,7 +848,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                OPT_BOOL('l', "create-reflog", &reflog, N_("create the branch's reflog")),
                OPT_BOOL(0, "edit-description", &edit_description,
                         N_("edit the description for the branch")),
-               OPT__FORCE(&force_create, N_("force creation (when already exists)")),
+               OPT__FORCE(&force, N_("force creation, move/rename, deletion")),
                {
                        OPTION_CALLBACK, 0, "no-merged", &merge_filter_ref,
                        N_("commit"), N_("print only not merged branches"),
@@ -891,7 +891,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
        if (with_commit || merge_filter != NO_FILTER)
                list = 1;
 
-       if (!!delete + !!rename + !!force_create + !!new_upstream +
+       if (!!delete + !!rename + !!new_upstream +
            list + unset_upstream > 1)
                usage_with_options(builtin_branch_usage, options);
 
@@ -904,6 +904,11 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
                colopts = 0;
        }
 
+       if (force) {
+               delete *= 2;
+               rename *= 2;
+       }
+
        if (delete) {
                if (!argc)
                        die(_("branch name required"));
@@ -1020,7 +1025,7 @@ int cmd_branch(int argc, const char **argv, const char *prefix)
 
                branch_existed = ref_exists(branch->refname);
                create_branch(head, argv[0], (argc == 2) ? argv[1] : head,
-                             force_create, reflog, 0, quiet, track);
+                             force, reflog, 0, quiet, track);
 
                /*
                 * We only show the instructions if the user gave us
index 5a787580368bd3e6410128ff300853a10e4a50ee..52d6cbb0a84e2693fc53c88ca1fb4cd899b26a91 100644 (file)
@@ -62,7 +62,7 @@ static int post_checkout_hook(struct commit *old, struct commit *new,
 
 }
 
-static int update_some(const unsigned char *sha1, const char *base, int baselen,
+static int update_some(const unsigned char *sha1, struct strbuf *base,
                const char *pathname, unsigned mode, int stage, void *context)
 {
        int len;
@@ -72,11 +72,11 @@ static int update_some(const unsigned char *sha1, const char *base, int baselen,
        if (S_ISDIR(mode))
                return READ_TREE_RECURSIVE;
 
-       len = baselen + strlen(pathname);
+       len = base->len + strlen(pathname);
        ce = xcalloc(1, cache_entry_size(len));
        hashcpy(ce->sha1, sha1);
-       memcpy(ce->name, base, baselen);
-       memcpy(ce->name + baselen, pathname, len - baselen);
+       memcpy(ce->name, base->buf, base->len);
+       memcpy(ce->name + base->len, pathname, len - base->len);
        ce->ce_flags = create_ce_flags(0) | CE_UPDATE;
        ce->ce_namelen = len;
        ce->ce_mode = create_ce_mode(mode);
index d5e7532105aa66c5b7e04e170489cf905928b5bb..316c75d0b342d039696608c18adfabaa3366b0e7 100644 (file)
@@ -49,6 +49,7 @@ static int option_verbosity;
 static int option_progress = -1;
 static struct string_list option_config;
 static struct string_list option_reference;
+static int option_dissociate;
 
 static int opt_parse_reference(const struct option *opt, const char *arg, int unset)
 {
@@ -94,6 +95,8 @@ static struct option builtin_clone_options[] = {
                    N_("create a shallow clone of that depth")),
        OPT_BOOL(0, "single-branch", &option_single_branch,
                    N_("clone only one branch, HEAD or --branch")),
+       OPT_BOOL(0, "dissociate", &option_dissociate,
+                N_("use --reference only while cloning")),
        OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
                   N_("separate git dir from working tree")),
        OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
@@ -735,6 +738,16 @@ static void write_refspec_config(const char *src_ref_prefix,
        strbuf_release(&value);
 }
 
+static void dissociate_from_references(void)
+{
+       static const char* argv[] = { "repack", "-a", "-d", NULL };
+
+       if (run_command_v_opt(argv, RUN_GIT_CMD|RUN_COMMAND_NO_STDIN))
+               die(_("cannot repack to clean up"));
+       if (unlink(git_path("objects/info/alternates")) && errno != ENOENT)
+               die_errno(_("cannot unlink temporary alternates file"));
+}
+
 int cmd_clone(int argc, const char **argv, const char *prefix)
 {
        int is_bundle = 0, is_local;
@@ -880,6 +893,10 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 
        if (option_reference.nr)
                setup_reference();
+       else if (option_dissociate) {
+               warning(_("--dissociate given, but there is no --reference"));
+               option_dissociate = 0;
+       }
 
        fetch_pattern = value.buf;
        refspec = parse_fetch_refspec(1, &fetch_pattern);
@@ -993,6 +1010,9 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        transport_unlock_pack(transport);
        transport_disconnect(transport);
 
+       if (option_dissociate)
+               dissociate_from_references();
+
        junk_mode = JUNK_LEAVE_REPO;
        err = checkout();
 
index e108c5301564a86d396d72169f40cd24a9916a1f..7d90c3591567d10f9a075ec38048b93923f707d4 100644 (file)
@@ -522,6 +522,12 @@ static int is_a_merge(const struct commit *current_head)
        return !!(current_head->parents && current_head->parents->next);
 }
 
+static void assert_split_ident(struct ident_split *id, const struct strbuf *buf)
+{
+       if (split_ident_line(id, buf->buf, buf->len) || !id->date_begin)
+               die("BUG: unable to parse our own ident: %s", buf->buf);
+}
+
 static void export_one(const char *var, const char *s, const char *e, int hack)
 {
        struct strbuf buf = STRBUF_INIT;
@@ -532,20 +538,6 @@ 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 int parse_force_date(const char *in, struct strbuf *out)
 {
        strbuf_addch(out, '@');
@@ -623,25 +615,15 @@ static void determine_author_info(struct strbuf *author_ident)
        }
 
        strbuf_addstr(author_ident, fmt_ident(name, email, date, IDENT_STRICT));
-       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, '@');
-       }
-
+       assert_split_ident(&author, author_ident);
+       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, '@');
        free(name);
        free(email);
        free(date);
 }
 
-static void split_ident_or_die(struct ident_split *id, const struct strbuf *buf)
-{
-       if (split_ident_line(id, buf->buf, buf->len) ||
-           !sane_ident_split(id))
-               die(_("Malformed ident string: '%s'"), buf->buf);
-}
-
 static int author_date_is_interesting(void)
 {
        return author_message || force_date;
@@ -800,32 +782,8 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
        if (clean_message_contents)
                stripspace(&sb, 0);
 
-       if (signoff) {
-               /*
-                * See if we have a Conflicts: block at the end. If yes, count
-                * its size, so we can ignore it.
-                */
-               int ignore_footer = 0;
-               int i, eol, previous = 0;
-               const char *nl;
-
-               for (i = 0; i < sb.len; i++) {
-                       nl = memchr(sb.buf + i, '\n', sb.len - i);
-                       if (nl)
-                               eol = nl - sb.buf;
-                       else
-                               eol = sb.len;
-                       if (starts_with(sb.buf + previous, "\nConflicts:\n")) {
-                               ignore_footer = sb.len - previous;
-                               break;
-                       }
-                       while (i < eol)
-                               i++;
-                       previous = eol;
-               }
-
-               append_signoff(&sb, ignore_footer, 0);
-       }
+       if (signoff)
+               append_signoff(&sb, ignore_non_trailer(&sb), 0);
 
        if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
                die_errno(_("could not write commit template"));
@@ -880,8 +838,14 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                        status_printf_ln(s, GIT_COLOR_NORMAL,
                                        "%s", only_include_assumed);
 
-               split_ident_or_die(&ai, author_ident);
-               split_ident_or_die(&ci, &committer_ident);
+               /*
+                * These should never fail because they come from our own
+                * fmt_ident. They may fail the sane_ident test, but we know
+                * that the name and mail pointers will at least be valid,
+                * which is enough for our tests and printing here.
+                */
+               assert_split_ident(&ai, author_ident);
+               assert_split_ident(&ci, &committer_ident);
 
                if (ident_cmp(&ai, &ci))
                        status_printf_ln(s, GIT_COLOR_NORMAL,
index fddafbba368fa377d7a968081b696e606592dbdb..15a7bea936d667042cef27f83c86a863df2caa8f 100644 (file)
@@ -565,8 +565,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                }
        }
        else if (actions == ACTION_EDIT) {
-               const char *config_file = given_config_source.file ?
-                       given_config_source.file : git_path("config");
+               char *config_file;
+
                check_argc(argc, 0, 0);
                if (!given_config_source.file && nongit)
                        die("not in a git directory");
@@ -575,6 +575,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                if (given_config_source.blob)
                        die("editing blobs is not supported");
                git_config(git_default_config, NULL);
+               config_file = xstrdup(given_config_source.file ?
+                                     given_config_source.file : git_path("config"));
                if (use_global_config) {
                        int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666);
                        if (fd) {
@@ -587,6 +589,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                                die_errno(_("cannot create configuration file %s"), config_file);
                }
                launch_editor(config_file, NULL, NULL);
+               free(config_file);
        }
        else if (actions == ACTION_SET) {
                int ret;
index 37177c6c2928b926cf55cacfdcfcf033bf012e80..af7919e51e717923260080f8be3305bbe1b56d39 100644 (file)
@@ -216,8 +216,7 @@ static void add_branch_desc(struct strbuf *out, const char *name)
                        strbuf_addf(out, "  : %.*s", (int)(ep - bp), bp);
                        bp = ep;
                }
-               if (out->buf[out->len - 1] != '\n')
-                       strbuf_addch(out, '\n');
+               strbuf_complete_line(out);
        }
        strbuf_release(&desc);
 }
index 603a90e29b808a86fa39f031d13a1ca94f5d236e..f3ce004d53c55e3f53d6a90d21d2877368676f08 100644 (file)
@@ -1075,7 +1075,7 @@ int cmd_for_each_ref(int argc, const char **argv, const char *prefix)
                OPT_BIT(0 , "python", &quote_style,
                        N_("quote placeholders suitably for python"), QUOTE_PYTHON),
                OPT_BIT(0 , "tcl",  &quote_style,
-                       N_("quote placeholders suitably for tcl"), QUOTE_TCL),
+                       N_("quote placeholders suitably for Tcl"), QUOTE_TCL),
 
                OPT_GROUP(""),
                OPT_INTEGER( 0 , "count", &maxcount, N_("show only <n> matched refs")),
index b3c818ee01b6f64c7cf00f2e58d372f4dc8f0250..e78c135e010afa3f9447992ae85a7cc404d0192b 100644 (file)
@@ -321,16 +321,18 @@ static void setup_man_path(void)
 {
        struct strbuf new_path = STRBUF_INIT;
        const char *old_path = getenv("MANPATH");
+       char *git_man_path = system_path(GIT_MAN_PATH);
 
        /* We should always put ':' after our path. If there is no
         * old_path, the ':' at the end will let 'man' to try
         * system-wide paths after ours to find the manual page. If
         * there is old_path, we need ':' as delimiter. */
-       strbuf_addstr(&new_path, system_path(GIT_MAN_PATH));
+       strbuf_addstr(&new_path, git_man_path);
        strbuf_addch(&new_path, ':');
        if (old_path)
                strbuf_addstr(&new_path, old_path);
 
+       free(git_man_path);
        setenv("MANPATH", new_path.buf, 1);
 
        strbuf_release(&new_path);
@@ -380,8 +382,10 @@ static void show_info_page(const char *git_cmd)
 static void get_html_page_path(struct strbuf *page_path, const char *page)
 {
        struct stat st;
+       char *to_free = NULL;
+
        if (!html_path)
-               html_path = system_path(GIT_HTML_PATH);
+               html_path = to_free = system_path(GIT_HTML_PATH);
 
        /* Check that we have a git documentation directory. */
        if (!strstr(html_path, "://")) {
@@ -392,6 +396,7 @@ static void get_html_page_path(struct strbuf *page_path, const char *page)
 
        strbuf_init(page_path, 0);
        strbuf_addf(page_path, "%s/%s.html", html_path, page);
+       free(to_free);
 }
 
 /*
index a369f5535351645f15b08efb9d592be4257cdeff..46321176719808dd53a38675dd0d9c558ae336dd 100644 (file)
@@ -447,7 +447,7 @@ static void *unpack_entry_data(unsigned long offset, unsigned long size,
        if (type == OBJ_BLOB && size > big_file_threshold)
                buf = fixed_buf;
        else
-               buf = xmalloc(size);
+               buf = xmallocz(size);
 
        memset(&stream, 0, sizeof(stream));
        git_inflate_init(&stream);
@@ -552,7 +552,7 @@ static void *unpack_data(struct object_entry *obj,
        git_zstream stream;
        int status;
 
-       data = xmalloc(consume ? 64*1024 : obj->size);
+       data = xmallocz(consume ? 64*1024 : obj->size);
        inbuf = xmalloc((len < 64*1024) ? len : 64*1024);
 
        memset(&stream, 0, sizeof(stream));
index aab44d2e451b1b6a2c764a5d62464ae690ab5566..9966522b4a97a0d1ae430e581125fbfd1d5609ac 100644 (file)
@@ -119,15 +119,18 @@ static void copy_templates(const char *template_dir)
        DIR *dir;
        const char *git_dir = get_git_dir();
        int len = strlen(git_dir);
+       char *to_free = NULL;
 
        if (!template_dir)
                template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT);
        if (!template_dir)
                template_dir = init_db_template_dir;
        if (!template_dir)
-               template_dir = system_path(DEFAULT_GIT_TEMPLATE_DIR);
-       if (!template_dir[0])
+               template_dir = to_free = system_path(DEFAULT_GIT_TEMPLATE_DIR);
+       if (!template_dir[0]) {
+               free(to_free);
                return;
+       }
        template_len = strlen(template_dir);
        if (PATH_MAX <= (template_len+strlen("/config")))
                die(_("insanely long template path %s"), template_dir);
@@ -139,7 +142,7 @@ static void copy_templates(const char *template_dir)
        dir = opendir(template_path);
        if (!dir) {
                warning(_("templates not found %s"), template_dir);
-               return;
+               goto free_return;
        }
 
        /* Make sure that template is from the correct vintage */
@@ -155,8 +158,7 @@ static void copy_templates(const char *template_dir)
                        "a wrong format version %d from '%s'"),
                        repository_format_version,
                        template_dir);
-               closedir(dir);
-               return;
+               goto close_free_return;
        }
 
        memcpy(path, git_dir, len);
@@ -166,7 +168,10 @@ static void copy_templates(const char *template_dir)
        copy_templates_1(path, len,
                         template_path, template_len,
                         dir);
+close_free_return:
        closedir(dir);
+free_return:
+       free(to_free);
 }
 
 static int git_init_db_config(const char *k, const char *v, void *cb)
@@ -256,6 +261,8 @@ static int create_default_files(const char *template_path)
                                !lstat(path, &st2) &&
                                st1.st_mode != st2.st_mode &&
                                !chmod(path, st1.st_mode));
+               if (filemode && !reinit && (st1.st_mode & S_IXUSR))
+                       filemode = 0;
        }
        git_config_set("core.filemode", filemode ? "true" : "false");
 
index 734aab3a73185964d18c82fe5eb31008bbc409b7..f2a9f0156d8a8b15c7c879355b137b669dea8cf2 100644 (file)
@@ -489,7 +489,7 @@ static int show_tag_object(const unsigned char *sha1, struct rev_info *rev)
 }
 
 static int show_tree_object(const unsigned char *sha1,
-               const char *base, int baselen,
+               struct strbuf *base,
                const char *pathname, unsigned mode, int stage, void *context)
 {
        printf("%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
index 51184dfa2efa46323e79c4504121bf5fe948a6d2..3b04a0f082a48c7b9c16f57a5bf4be94c159204c 100644 (file)
@@ -61,10 +61,11 @@ static int show_recursive(const char *base, int baselen, const char *pathname)
        }
 }
 
-static int show_tree(const unsigned char *sha1, const char *base, int baselen,
+static int show_tree(const unsigned char *sha1, struct strbuf *base,
                const char *pathname, unsigned mode, int stage, void *context)
 {
        int retval = 0;
+       int baselen;
        const char *type = blob_type;
 
        if (S_ISGITLINK(mode)) {
@@ -79,7 +80,7 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
                 */
                type = commit_type;
        } else if (S_ISDIR(mode)) {
-               if (show_recursive(base, baselen, pathname)) {
+               if (show_recursive(base->buf, base->len, pathname)) {
                        retval = READ_TREE_RECURSIVE;
                        if (!(ls_options & LS_SHOW_TREES))
                                return retval;
@@ -89,10 +90,6 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
        else if (ls_options & LS_TREE_ONLY)
                return 0;
 
-       if (chomp_prefix &&
-           (baselen < chomp_prefix || memcmp(ls_tree_prefix, base, chomp_prefix)))
-               return 0;
-
        if (!(ls_options & LS_NAME_ONLY)) {
                if (ls_options & LS_SHOW_SIZE) {
                        char size_text[24];
@@ -112,8 +109,12 @@ static int show_tree(const unsigned char *sha1, const char *base, int baselen,
                        printf("%06o %s %s\t", mode, type,
                               find_unique_abbrev(sha1, abbrev));
        }
-       write_name_quotedpfx(base + chomp_prefix, baselen - chomp_prefix,
-                         pathname, stdout, line_termination);
+       baselen = base->len;
+       strbuf_addstr(base, pathname);
+       write_name_quoted_relative(base->buf,
+                                  chomp_prefix ? ls_tree_prefix : NULL,
+                                  stdout, line_termination);
+       strbuf_setlen(base, baselen);
        return retval;
 }
 
@@ -173,7 +174,8 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
         * cannot be lifted until it is converted to use
         * match_pathspec() or tree_entry_interesting()
         */
-       parse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE,
+       parse_pathspec(&pathspec, PATHSPEC_GLOB | PATHSPEC_ICASE |
+                                 PATHSPEC_EXCLUDE,
                       PATHSPEC_PREFER_CWD,
                       prefix, argv + 1);
        for (i = 0; i < pathspec.nr; i++)
index 6a14d2985d12394d343cb91290111d6a8c0a5d06..c8a47c173d011713a57dc744a5f5e5ea5434eefa 100644 (file)
@@ -15,6 +15,7 @@ static const char *metainfo_charset;
 static struct strbuf line = STRBUF_INIT;
 static struct strbuf name = STRBUF_INIT;
 static struct strbuf email = STRBUF_INIT;
+static char *message_id;
 
 static enum  {
        TE_DONTCARE, TE_QP, TE_BASE64
@@ -24,6 +25,7 @@ static struct strbuf charset = STRBUF_INIT;
 static int patch_lines;
 static struct strbuf **p_hdr_data, **s_hdr_data;
 static int use_scissors;
+static int add_message_id;
 static int use_inbody_headers = 1;
 
 #define MAX_HDR_PARSED 10
@@ -198,6 +200,12 @@ static void handle_content_type(struct strbuf *line)
        }
 }
 
+static void handle_message_id(const struct strbuf *line)
+{
+       if (add_message_id)
+               message_id = strdup(line->buf);
+}
+
 static void handle_content_transfer_encoding(const struct strbuf *line)
 {
        if (strcasestr(line->buf, "base64"))
@@ -342,6 +350,14 @@ static int check_header(const struct strbuf *line,
                ret = 1;
                goto check_header_out;
        }
+       if (cmp_header(line, "Message-Id")) {
+               len = strlen("Message-Id: ");
+               strbuf_add(&sb, line->buf + len, line->len - len);
+               decode_header(&sb);
+               handle_message_id(&sb);
+               ret = 1;
+               goto check_header_out;
+       }
 
        /* for inbody stuff */
        if (starts_with(line->buf, ">From") && isspace(line->buf[5])) {
@@ -816,6 +832,8 @@ static int handle_commit_msg(struct strbuf *line)
        }
 
        if (patchbreak(line)) {
+               if (message_id)
+                       fprintf(cmitmsg, "Message-Id: %s\n", message_id);
                fclose(cmitmsg);
                cmitmsg = NULL;
                return 1;
@@ -1013,7 +1031,7 @@ static int git_mailinfo_config(const char *var, const char *value, void *unused)
 }
 
 static const char mailinfo_usage[] =
-       "git mailinfo [-k|-b] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] msg patch < mail >info";
+       "git mailinfo [-k|-b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] msg patch < mail >info";
 
 int cmd_mailinfo(int argc, const char **argv, const char *prefix)
 {
@@ -1032,6 +1050,8 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)
                        keep_subject = 1;
                else if (!strcmp(argv[1], "-b"))
                        keep_non_patch_brackets_in_subject = 1;
+               else if (!strcmp(argv[1], "-m") || !strcmp(argv[1], "--message-id"))
+                       add_message_id = 1;
                else if (!strcmp(argv[1], "-u"))
                        metainfo_charset = def_charset;
                else if (!strcmp(argv[1], "-n"))
index 0ecde8da30615996f54563014e4774b67812c531..fdebef6fa157e920a4560e68c1215665f1e20baf 100644 (file)
@@ -10,7 +10,7 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
 {
        struct commit_list *result;
 
-       result = get_merge_bases_many(rev[0], rev_nr - 1, rev + 1, 0);
+       result = get_merge_bases_many_dirty(rev[0], rev_nr - 1, rev + 1);
 
        if (!result)
                return 1;
@@ -176,7 +176,7 @@ static int handle_fork_point(int argc, const char **argv)
        for (i = 0; i < revs.nr; i++)
                revs.commit[i]->object.flags &= ~TMP_MARK;
 
-       bases = get_merge_bases_many(derived, revs.nr, revs.commit, 0);
+       bases = get_merge_bases_many_dirty(derived, revs.nr, revs.commit);
 
        /*
         * There should be one and only one merge base, when we found
index bebbe5b3081ebe2602abaf0dc9508a1342f01086..9effed7ff15d087a6d6768044ffaa70db1ddac73 100644 (file)
@@ -29,6 +29,7 @@
 #include "remote.h"
 #include "fmt-merge-msg.h"
 #include "gpg-interface.h"
+#include "sequencer.h"
 
 #define DEFAULT_TWOHEAD (1<<0)
 #define DEFAULT_OCTOPUS (1<<1)
@@ -880,28 +881,19 @@ static int finish_automerge(struct commit *head,
        return 0;
 }
 
-static int suggest_conflicts(int renormalizing)
+static int suggest_conflicts(void)
 {
        const char *filename;
        FILE *fp;
-       int pos;
+       struct strbuf msgbuf = STRBUF_INIT;
 
        filename = git_path("MERGE_MSG");
        fp = fopen(filename, "a");
        if (!fp)
                die_errno(_("Could not open '%s' for writing"), filename);
-       fprintf(fp, "\nConflicts:\n");
-       for (pos = 0; pos < active_nr; pos++) {
-               const struct cache_entry *ce = active_cache[pos];
-
-               if (ce_stage(ce)) {
-                       fprintf(fp, "\t%s\n", ce->name);
-                       while (pos + 1 < active_nr &&
-                                       !strcmp(ce->name,
-                                               active_cache[pos + 1]->name))
-                               pos++;
-               }
-       }
+
+       append_conflicts_hint(&msgbuf);
+       fputs(msgbuf.buf, fp);
        fclose(fp);
        rerere(allow_rerere_auto);
        printf(_("Automatic merge failed; "
@@ -1320,7 +1312,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
        if (!remoteheads)
                ; /* already up-to-date */
        else if (!remoteheads->next)
-               common = get_merge_bases(head_commit, remoteheads->item, 1);
+               common = get_merge_bases(head_commit, remoteheads->item);
        else {
                struct commit_list *list = remoteheads;
                commit_list_insert(head_commit, &list);
@@ -1417,7 +1409,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                         * merge_bases again, otherwise "git merge HEAD^
                         * HEAD^^" would be missed.
                         */
-                       common_one = get_merge_bases(head_commit, j->item, 1);
+                       common_one = get_merge_bases(head_commit, j->item);
                        if (hashcmp(common_one->item->object.sha1,
                                j->item->object.sha1)) {
                                up_to_date = 0;
@@ -1550,7 +1542,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                fprintf(stderr, _("Automatic merge went well; "
                        "stopped before committing as requested\n"));
        else
-               ret = suggest_conflicts(option_renormalize);
+               ret = suggest_conflicts();
 
 done:
        free(branch_to_free);
index 68b6cd8cc1ded390df592e1c6536d70bf1ffc8a0..a9f37d045641236ee910f3eb22be6ac8d04e386a 100644 (file)
 
 static const char * const git_notes_usage[] = {
        N_("git notes [--ref <notes_ref>] [list [<object>]]"),
-       N_("git notes [--ref <notes_ref>] add [-f] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+       N_("git notes [--ref <notes_ref>] add [-f] [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
        N_("git notes [--ref <notes_ref>] copy [-f] <from-object> <to-object>"),
-       N_("git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
-       N_("git notes [--ref <notes_ref>] edit [<object>]"),
+       N_("git notes [--ref <notes_ref>] append [--allow-empty] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]"),
+       N_("git notes [--ref <notes_ref>] edit [--allow-empty] [<object>]"),
        N_("git notes [--ref <notes_ref>] show [<object>]"),
        N_("git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>"),
        N_("git notes merge --commit [-v | -q]"),
@@ -92,12 +92,22 @@ static const char * const git_notes_get_ref_usage[] = {
 static const char note_template[] =
        "\nWrite/edit the notes for the following object:\n";
 
-struct msg_arg {
+struct note_data {
        int given;
        int use_editor;
+       char *edit_path;
        struct strbuf buf;
 };
 
+static void free_note_data(struct note_data *d)
+{
+       if (d->edit_path) {
+               unlink_or_warn(d->edit_path);
+               free(d->edit_path);
+       }
+       strbuf_release(&d->buf);
+}
+
 static int list_each_note(const unsigned char *object_sha1,
                const unsigned char *note_sha1, char *note_path,
                void *cb_data)
@@ -106,7 +116,7 @@ static int list_each_note(const unsigned char *object_sha1,
        return 0;
 }
 
-static void write_note_data(int fd, const unsigned char *sha1)
+static void copy_obj_to_fd(int fd, const unsigned char *sha1)
 {
        unsigned long size;
        enum object_type type;
@@ -149,26 +159,23 @@ static void write_commented_object(int fd, const unsigned char *object)
                    sha1_to_hex(object));
 }
 
-static void create_note(const unsigned char *object, struct msg_arg *msg,
-                       int append_only, const unsigned char *prev,
-                       unsigned char *result)
+static void prepare_note_data(const unsigned char *object, struct note_data *d,
+               const unsigned char *old_note)
 {
-       char *path = NULL;
-
-       if (msg->use_editor || !msg->given) {
+       if (d->use_editor || !d->given) {
                int fd;
                struct strbuf buf = STRBUF_INIT;
 
                /* write the template message before editing: */
-               path = git_pathdup("NOTES_EDITMSG");
-               fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+               d->edit_path = git_pathdup("NOTES_EDITMSG");
+               fd = open(d->edit_path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
                if (fd < 0)
-                       die_errno(_("could not create file '%s'"), path);
+                       die_errno(_("could not create file '%s'"), d->edit_path);
 
-               if (msg->given)
-                       write_or_die(fd, msg->buf.buf, msg->buf.len);
-               else if (prev && !append_only)
-                       write_note_data(fd, prev);
+               if (d->given)
+                       write_or_die(fd, d->buf.buf, d->buf.len);
+               else if (old_note)
+                       copy_obj_to_fd(fd, old_note);
 
                strbuf_addch(&buf, '\n');
                strbuf_add_commented_lines(&buf, note_template, strlen(note_template));
@@ -179,94 +186,71 @@ static void create_note(const unsigned char *object, struct msg_arg *msg,
 
                close(fd);
                strbuf_release(&buf);
-               strbuf_reset(&(msg->buf));
-
-               if (launch_editor(path, &(msg->buf), NULL)) {
-                       die(_("Please supply the note contents using either -m" \
-                           " or -F option"));
-               }
-               stripspace(&(msg->buf), 1);
-       }
-
-       if (prev && append_only) {
-               /* Append buf to previous note contents */
-               unsigned long size;
-               enum object_type type;
-               char *prev_buf = read_sha1_file(prev, &type, &size);
+               strbuf_reset(&d->buf);
 
-               strbuf_grow(&(msg->buf), size + 1);
-               if (msg->buf.len && prev_buf && size)
-                       strbuf_insert(&(msg->buf), 0, "\n", 1);
-               if (prev_buf && size)
-                       strbuf_insert(&(msg->buf), 0, prev_buf, size);
-               free(prev_buf);
-       }
-
-       if (!msg->buf.len) {
-               fprintf(stderr, _("Removing note for object %s\n"),
-                       sha1_to_hex(object));
-               hashclr(result);
-       } else {
-               if (write_sha1_file(msg->buf.buf, msg->buf.len, blob_type, result)) {
-                       error(_("unable to write note object"));
-                       if (path)
-                               error(_("The note contents have been left in %s"),
-                                     path);
-                       exit(128);
+               if (launch_editor(d->edit_path, &d->buf, NULL)) {
+                       die(_("Please supply the note contents using either -m or -F option"));
                }
+               stripspace(&d->buf, 1);
        }
+}
 
-       if (path) {
-               unlink_or_warn(path);
-               free(path);
+static void write_note_data(struct note_data *d, unsigned char *sha1)
+{
+       if (write_sha1_file(d->buf.buf, d->buf.len, blob_type, sha1)) {
+               error(_("unable to write note object"));
+               if (d->edit_path)
+                       error(_("The note contents have been left in %s"),
+                               d->edit_path);
+               exit(128);
        }
 }
 
 static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
 {
-       struct msg_arg *msg = opt->value;
+       struct note_data *d = opt->value;
 
-       strbuf_grow(&(msg->buf), strlen(arg) + 2);
-       if (msg->buf.len)
-               strbuf_addch(&(msg->buf), '\n');
-       strbuf_addstr(&(msg->buf), arg);
-       stripspace(&(msg->buf), 0);
+       strbuf_grow(&d->buf, strlen(arg) + 2);
+       if (d->buf.len)
+               strbuf_addch(&d->buf, '\n');
+       strbuf_addstr(&d->buf, arg);
+       stripspace(&d->buf, 0);
 
-       msg->given = 1;
+       d->given = 1;
        return 0;
 }
 
 static int parse_file_arg(const struct option *opt, const char *arg, int unset)
 {
-       struct msg_arg *msg = opt->value;
+       struct note_data *d = opt->value;
 
-       if (msg->buf.len)
-               strbuf_addch(&(msg->buf), '\n');
+       if (d->buf.len)
+               strbuf_addch(&d->buf, '\n');
        if (!strcmp(arg, "-")) {
-               if (strbuf_read(&(msg->buf), 0, 1024) < 0)
+               if (strbuf_read(&d->buf, 0, 1024) < 0)
                        die_errno(_("cannot read '%s'"), arg);
-       } else if (strbuf_read_file(&(msg->buf), arg, 1024) < 0)
+       } else if (strbuf_read_file(&d->buf, arg, 1024) < 0)
                die_errno(_("could not open or read '%s'"), arg);
-       stripspace(&(msg->buf), 0);
+       stripspace(&d->buf, 0);
 
-       msg->given = 1;
+       d->given = 1;
        return 0;
 }
 
 static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)
 {
-       struct msg_arg *msg = opt->value;
+       struct note_data *d = opt->value;
        char *buf;
        unsigned char object[20];
        enum object_type type;
        unsigned long len;
 
-       if (msg->buf.len)
-               strbuf_addch(&(msg->buf), '\n');
+       if (d->buf.len)
+               strbuf_addch(&d->buf, '\n');
 
        if (get_sha1(arg, object))
                die(_("Failed to resolve '%s' as a valid ref."), arg);
-       if (!(buf = read_sha1_file(object, &type, &len)) || !len) {
+       if (!(buf = read_sha1_file(object, &type, &len))) {
                free(buf);
                die(_("Failed to read object '%s'."), arg);
        }
@@ -274,17 +258,17 @@ static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)
                free(buf);
                die(_("Cannot read note data from non-blob object '%s'."), arg);
        }
-       strbuf_add(&(msg->buf), buf, len);
+       strbuf_add(&d->buf, buf, len);
        free(buf);
 
-       msg->given = 1;
+       d->given = 1;
        return 0;
 }
 
 static int parse_reedit_arg(const struct option *opt, const char *arg, int unset)
 {
-       struct msg_arg *msg = opt->value;
-       msg->use_editor = 1;
+       struct note_data *d = opt->value;
+       d->use_editor = 1;
        return parse_reuse_arg(opt, arg, unset);
 }
 
@@ -397,26 +381,27 @@ static int append_edit(int argc, const char **argv, const char *prefix);
 
 static int add(int argc, const char **argv, const char *prefix)
 {
-       int retval = 0, force = 0;
+       int force = 0, allow_empty = 0;
        const char *object_ref;
        struct notes_tree *t;
        unsigned char object[20], new_note[20];
-       char logmsg[100];
        const unsigned char *note;
-       struct msg_arg msg = { 0, 0, STRBUF_INIT };
+       struct note_data d = { 0, 0, NULL, STRBUF_INIT };
        struct option options[] = {
-               { OPTION_CALLBACK, 'm', "message", &msg, N_("message"),
+               { OPTION_CALLBACK, 'm', "message", &d, N_("message"),
                        N_("note contents as a string"), PARSE_OPT_NONEG,
                        parse_msg_arg},
-               { OPTION_CALLBACK, 'F', "file", &msg, N_("file"),
+               { OPTION_CALLBACK, 'F', "file", &d, N_("file"),
                        N_("note contents in a file"), PARSE_OPT_NONEG,
                        parse_file_arg},
-               { OPTION_CALLBACK, 'c', "reedit-message", &msg, N_("object"),
+               { OPTION_CALLBACK, 'c', "reedit-message", &d, N_("object"),
                        N_("reuse and edit specified note object"), PARSE_OPT_NONEG,
                        parse_reedit_arg},
-               { OPTION_CALLBACK, 'C', "reuse-message", &msg, N_("object"),
+               { OPTION_CALLBACK, 'C', "reuse-message", &d, N_("object"),
                        N_("reuse specified note object"), PARSE_OPT_NONEG,
                        parse_reuse_arg},
+               OPT_BOOL(0, "allow-empty", &allow_empty,
+                       N_("allow storing empty note")),
                OPT__FORCE(&force, N_("replace existing notes")),
                OPT_END()
        };
@@ -439,41 +424,44 @@ static int add(int argc, const char **argv, const char *prefix)
 
        if (note) {
                if (!force) {
-                       if (!msg.given) {
-                               /*
-                                * Redirect to "edit" subcommand.
-                                *
-                                * We only end up here if none of -m/-F/-c/-C
-                                * or -f are given. The original args are
-                                * therefore still in argv[0-1].
-                                */
-                               argv[0] = "edit";
-                               free_notes(t);
-                               return append_edit(argc, argv, prefix);
+                       free_notes(t);
+                       if (d.given) {
+                               free_note_data(&d);
+                               return error(_("Cannot add notes. "
+                                       "Found existing notes for object %s. "
+                                       "Use '-f' to overwrite existing notes"),
+                                       sha1_to_hex(object));
                        }
-                       retval = error(_("Cannot add notes. Found existing notes "
-                                      "for object %s. Use '-f' to overwrite "
-                                      "existing notes"), sha1_to_hex(object));
-                       goto out;
+                       /*
+                        * Redirect to "edit" subcommand.
+                        *
+                        * We only end up here if none of -m/-F/-c/-C or -f are
+                        * given. The original args are therefore still in
+                        * argv[0-1].
+                        */
+                       argv[0] = "edit";
+                       return append_edit(argc, argv, prefix);
                }
                fprintf(stderr, _("Overwriting existing notes for object %s\n"),
                        sha1_to_hex(object));
        }
 
-       create_note(object, &msg, 0, note, new_note);
-
-       if (is_null_sha1(new_note))
+       prepare_note_data(object, &d, note);
+       if (d.buf.len || allow_empty) {
+               write_note_data(&d, new_note);
+               if (add_note(t, object, new_note, combine_notes_overwrite))
+                       die("BUG: combine_notes_overwrite failed");
+               commit_notes(t, "Notes added by 'git notes add'");
+       } else {
+               fprintf(stderr, _("Removing note for object %s\n"),
+                       sha1_to_hex(object));
                remove_note(t, object);
-       else if (add_note(t, object, new_note, combine_notes_overwrite))
-               die("BUG: combine_notes_overwrite failed");
+               commit_notes(t, "Notes removed by 'git notes add'");
+       }
 
-       snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'",
-                is_null_sha1(new_note) ? "removed" : "added", "add");
-       commit_notes(t, logmsg);
-out:
+       free_note_data(&d);
        free_notes(t);
-       strbuf_release(&(msg.buf));
-       return retval;
+       return 0;
 }
 
 static int copy(int argc, const char **argv, const char *prefix)
@@ -554,26 +542,29 @@ static int copy(int argc, const char **argv, const char *prefix)
 
 static int append_edit(int argc, const char **argv, const char *prefix)
 {
+       int allow_empty = 0;
        const char *object_ref;
        struct notes_tree *t;
        unsigned char object[20], new_note[20];
        const unsigned char *note;
        char logmsg[100];
        const char * const *usage;
-       struct msg_arg msg = { 0, 0, STRBUF_INIT };
+       struct note_data d = { 0, 0, NULL, STRBUF_INIT };
        struct option options[] = {
-               { OPTION_CALLBACK, 'm', "message", &msg, N_("message"),
+               { OPTION_CALLBACK, 'm', "message", &d, N_("message"),
                        N_("note contents as a string"), PARSE_OPT_NONEG,
                        parse_msg_arg},
-               { OPTION_CALLBACK, 'F', "file", &msg, N_("file"),
+               { OPTION_CALLBACK, 'F', "file", &d, N_("file"),
                        N_("note contents in a file"), PARSE_OPT_NONEG,
                        parse_file_arg},
-               { OPTION_CALLBACK, 'c', "reedit-message", &msg, N_("object"),
+               { OPTION_CALLBACK, 'c', "reedit-message", &d, N_("object"),
                        N_("reuse and edit specified note object"), PARSE_OPT_NONEG,
                        parse_reedit_arg},
-               { OPTION_CALLBACK, 'C', "reuse-message", &msg, N_("object"),
+               { OPTION_CALLBACK, 'C', "reuse-message", &d, N_("object"),
                        N_("reuse specified note object"), PARSE_OPT_NONEG,
                        parse_reuse_arg},
+               OPT_BOOL(0, "allow-empty", &allow_empty,
+                       N_("allow storing empty note")),
                OPT_END()
        };
        int edit = !strcmp(argv[0], "edit");
@@ -587,7 +578,7 @@ static int append_edit(int argc, const char **argv, const char *prefix)
                usage_with_options(usage, options);
        }
 
-       if (msg.given && edit)
+       if (d.given && edit)
                fprintf(stderr, _("The -m/-F/-c/-C options have been deprecated "
                        "for the 'edit' subcommand.\n"
                        "Please use 'git notes add -f -m/-F/-c/-C' instead.\n"));
@@ -600,18 +591,39 @@ static int append_edit(int argc, const char **argv, const char *prefix)
        t = init_notes_check(argv[0]);
        note = get_note(t, object);
 
-       create_note(object, &msg, !edit, note, new_note);
+       prepare_note_data(object, &d, edit ? note : NULL);
 
-       if (is_null_sha1(new_note))
-               remove_note(t, object);
-       else if (add_note(t, object, new_note, combine_notes_overwrite))
-               die("BUG: combine_notes_overwrite failed");
+       if (note && !edit) {
+               /* Append buf to previous note contents */
+               unsigned long size;
+               enum object_type type;
+               char *prev_buf = read_sha1_file(note, &type, &size);
+
+               strbuf_grow(&d.buf, size + 1);
+               if (d.buf.len && prev_buf && size)
+                       strbuf_insert(&d.buf, 0, "\n", 1);
+               if (prev_buf && size)
+                       strbuf_insert(&d.buf, 0, prev_buf, size);
+               free(prev_buf);
+       }
 
-       snprintf(logmsg, sizeof(logmsg), "Notes %s by 'git notes %s'",
-                is_null_sha1(new_note) ? "removed" : "added", argv[0]);
+       if (d.buf.len || allow_empty) {
+               write_note_data(&d, new_note);
+               if (add_note(t, object, new_note, combine_notes_overwrite))
+                       die("BUG: combine_notes_overwrite failed");
+               snprintf(logmsg, sizeof(logmsg), "Notes added by 'git notes %s'",
+                       argv[0]);
+       } else {
+               fprintf(stderr, _("Removing note for object %s\n"),
+                       sha1_to_hex(object));
+               remove_note(t, object);
+               snprintf(logmsg, sizeof(logmsg), "Notes removed by 'git notes %s'",
+                       argv[0]);
+       }
        commit_notes(t, logmsg);
+
+       free_note_data(&d);
        free_notes(t);
-       strbuf_release(&(msg.buf));
        return 0;
 }
 
index 7aedf6f533690593a0ee0e438b3565daa73966f7..12f5e69393bc2981dd5ff1433e34bc4932c0ee22 100644 (file)
@@ -503,7 +503,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
                  0, CAS_OPT_NAME, &cas, N_("refname>:<expect"),
                  N_("require old value of ref to be at this value"),
                  PARSE_OPT_OPTARG, parseopt_push_cas_option },
-               { OPTION_CALLBACK, 0, "recurse-submodules", &flags, N_("check"),
+               { OPTION_CALLBACK, 0, "recurse-submodules", &flags, "check|on-demand",
                        N_("control recursive pushing of submodules"),
                        PARSE_OPT_OPTARG, option_parse_recurse_submodules },
                OPT_BOOL( 0 , "thin", &thin, N_("use thin pack")),
index e908d079bae83884cc218cf6a39d3ed705cf439b..8266c1fccf0c0b5908c14a726d443dec36a22d58 100644 (file)
@@ -26,7 +26,8 @@ enum deny_action {
        DENY_UNCONFIGURED,
        DENY_IGNORE,
        DENY_WARN,
-       DENY_REFUSE
+       DENY_REFUSE,
+       DENY_UPDATE_INSTEAD
 };
 
 static int deny_deletes;
@@ -76,6 +77,8 @@ static enum deny_action parse_deny_action(const char *var, const char *value)
                        return DENY_WARN;
                if (!strcasecmp(value, "refuse"))
                        return DENY_REFUSE;
+               if (!strcasecmp(value, "updateinstead"))
+                       return DENY_UPDATE_INSTEAD;
        }
        if (git_config_bool(var, value))
                return DENY_REFUSE;
@@ -730,11 +733,89 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
        return 0;
 }
 
+static const char *update_worktree(unsigned char *sha1)
+{
+       const char *update_refresh[] = {
+               "update-index", "-q", "--ignore-submodules", "--refresh", NULL
+       };
+       const char *diff_files[] = {
+               "diff-files", "--quiet", "--ignore-submodules", "--", NULL
+       };
+       const char *diff_index[] = {
+               "diff-index", "--quiet", "--cached", "--ignore-submodules",
+               "HEAD", "--", NULL
+       };
+       const char *read_tree[] = {
+               "read-tree", "-u", "-m", NULL, NULL
+       };
+       const char *work_tree = git_work_tree_cfg ? git_work_tree_cfg : "..";
+       struct argv_array env = ARGV_ARRAY_INIT;
+       struct child_process child = CHILD_PROCESS_INIT;
+
+       if (is_bare_repository())
+               return "denyCurrentBranch = updateInstead needs a worktree";
+
+       argv_array_pushf(&env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+
+       child.argv = update_refresh;
+       child.env = env.argv;
+       child.dir = work_tree;
+       child.no_stdin = 1;
+       child.stdout_to_stderr = 1;
+       child.git_cmd = 1;
+       if (run_command(&child)) {
+               argv_array_clear(&env);
+               return "Up-to-date check failed";
+       }
+
+       /* run_command() does not clean up completely; reinitialize */
+       child_process_init(&child);
+       child.argv = diff_files;
+       child.env = env.argv;
+       child.dir = work_tree;
+       child.no_stdin = 1;
+       child.stdout_to_stderr = 1;
+       child.git_cmd = 1;
+       if (run_command(&child)) {
+               argv_array_clear(&env);
+               return "Working directory has unstaged changes";
+       }
+
+       child_process_init(&child);
+       child.argv = diff_index;
+       child.env = env.argv;
+       child.no_stdin = 1;
+       child.no_stdout = 1;
+       child.stdout_to_stderr = 0;
+       child.git_cmd = 1;
+       if (run_command(&child)) {
+               argv_array_clear(&env);
+               return "Working directory has staged changes";
+       }
+
+       read_tree[3] = sha1_to_hex(sha1);
+       child_process_init(&child);
+       child.argv = read_tree;
+       child.env = env.argv;
+       child.dir = work_tree;
+       child.no_stdin = 1;
+       child.no_stdout = 1;
+       child.stdout_to_stderr = 0;
+       child.git_cmd = 1;
+       if (run_command(&child)) {
+               argv_array_clear(&env);
+               return "Could not update working tree to new HEAD";
+       }
+
+       argv_array_clear(&env);
+       return NULL;
+}
+
 static const char *update(struct command *cmd, struct shallow_info *si)
 {
        const char *name = cmd->ref_name;
        struct strbuf namespaced_name_buf = STRBUF_INIT;
-       const char *namespaced_name;
+       const char *namespaced_name, *ret;
        unsigned char *old_sha1 = cmd->old_sha1;
        unsigned char *new_sha1 = cmd->new_sha1;
 
@@ -760,6 +841,11 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                        if (deny_current_branch == DENY_UNCONFIGURED)
                                refuse_unconfigured_deny();
                        return "branch is currently checked out";
+               case DENY_UPDATE_INSTEAD:
+                       ret = update_worktree(new_sha1);
+                       if (ret)
+                               return ret;
+                       break;
                }
        }
 
@@ -784,10 +870,13 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                                break;
                        case DENY_REFUSE:
                        case DENY_UNCONFIGURED:
+                       case DENY_UPDATE_INSTEAD:
                                if (deny_delete_current == DENY_UNCONFIGURED)
                                        refuse_unconfigured_deny_delete_current();
                                rp_error("refusing to delete the current branch: %s", name);
                                return "deletion of the current branch prohibited";
+                       default:
+                               return "Invalid denyDeleteCurrent setting";
                        }
                }
        }
@@ -964,7 +1053,7 @@ static void check_aliased_updates(struct command *commands)
                        string_list_append(&ref_list, cmd->ref_name);
                item->util = (void *)cmd;
        }
-       sort_string_list(&ref_list);
+       string_list_sort(&ref_list);
 
        for (cmd = commands; cmd; cmd = cmd->next) {
                if (!cmd->error_string)
index 7f28f92a378a4e89d8c938beac23cbe053f1ce33..46ecfd9f7b0dd0b28169341d14132df376e509bc 100644 (file)
@@ -352,9 +352,9 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
        free_refs(stale_refs);
        free_refs(fetch_map);
 
-       sort_string_list(&states->new);
-       sort_string_list(&states->tracked);
-       sort_string_list(&states->stale);
+       string_list_sort(&states->new);
+       string_list_sort(&states->tracked);
+       string_list_sort(&states->stale);
 
        return 0;
 }
@@ -750,16 +750,11 @@ static int mv(int argc, const char **argv)
 static int remove_branches(struct string_list *branches)
 {
        struct strbuf err = STRBUF_INIT;
-       const char **branch_names;
        int i, result = 0;
 
-       branch_names = xmalloc(branches->nr * sizeof(*branch_names));
-       for (i = 0; i < branches->nr; i++)
-               branch_names[i] = branches->items[i].string;
-       if (repack_without_refs(branch_names, branches->nr, &err))
+       if (repack_without_refs(branches, &err))
                result |= error("%s", err.buf);
        strbuf_release(&err);
-       free(branch_names);
 
        for (i = 0; i < branches->nr; i++) {
                struct string_list_item *item = branches->items + i;
@@ -914,7 +909,7 @@ static int get_remote_ref_states(const char *name,
                        get_push_ref_states(remote_refs, states);
        } else {
                for_each_ref(append_ref_to_tracked_list, states);
-               sort_string_list(&states->tracked);
+               string_list_sort(&states->tracked);
                get_push_ref_states_noquery(states);
        }
 
@@ -1133,7 +1128,7 @@ static int show_all(void)
        if (!result) {
                int i;
 
-               sort_string_list(&list);
+               string_list_sort(&list);
                for (i = 0; i < list.nr; i++) {
                        struct string_list_item *item = list.items + i;
                        if (verbose)
@@ -1314,10 +1309,10 @@ static int set_head(int argc, const char **argv)
 
 static int prune_remote(const char *remote, int dry_run)
 {
-       int result = 0, i;
+       int result = 0;
        struct ref_states states;
-       struct string_list delete_refs_list = STRING_LIST_INIT_NODUP;
-       const char **delete_refs;
+       struct string_list refs_to_prune = STRING_LIST_INIT_NODUP;
+       struct string_list_item *item;
        const char *dangling_msg = dry_run
                ? _(" %s will become dangling!")
                : _(" %s has become dangling!");
@@ -1325,30 +1320,30 @@ static int prune_remote(const char *remote, int dry_run)
        memset(&states, 0, sizeof(states));
        get_remote_ref_states(remote, &states, GET_REF_STATES);
 
-       if (states.stale.nr) {
-               printf_ln(_("Pruning %s"), remote);
-               printf_ln(_("URL: %s"),
-                      states.remote->url_nr
-                      ? states.remote->url[0]
-                      : _("(no URL)"));
-
-               delete_refs = xmalloc(states.stale.nr * sizeof(*delete_refs));
-               for (i = 0; i < states.stale.nr; i++)
-                       delete_refs[i] = states.stale.items[i].util;
-               if (!dry_run) {
-                       struct strbuf err = STRBUF_INIT;
-                       if (repack_without_refs(delete_refs, states.stale.nr,
-                                               &err))
-                               result |= error("%s", err.buf);
-                       strbuf_release(&err);
-               }
-               free(delete_refs);
+       if (!states.stale.nr) {
+               free_remote_ref_states(&states);
+               return 0;
        }
 
-       for (i = 0; i < states.stale.nr; i++) {
-               const char *refname = states.stale.items[i].util;
+       printf_ln(_("Pruning %s"), remote);
+       printf_ln(_("URL: %s"),
+                 states.remote->url_nr
+                 ? states.remote->url[0]
+                 : _("(no URL)"));
+
+       for_each_string_list_item(item, &states.stale)
+               string_list_append(&refs_to_prune, item->util);
+       string_list_sort(&refs_to_prune);
+
+       if (!dry_run) {
+               struct strbuf err = STRBUF_INIT;
+               if (repack_without_refs(&refs_to_prune, &err))
+                       result |= error("%s", err.buf);
+               strbuf_release(&err);
+       }
 
-               string_list_insert(&delete_refs_list, refname);
+       for_each_string_list_item(item, &states.stale) {
+               const char *refname = item->util;
 
                if (!dry_run)
                        result |= delete_ref(refname, NULL, 0);
@@ -1361,9 +1356,9 @@ static int prune_remote(const char *remote, int dry_run)
                               abbrev_ref(refname, "refs/remotes/"));
        }
 
-       warn_dangling_symrefs(stdout, dangling_msg, &delete_refs_list);
-       string_list_clear(&delete_refs_list, 0);
+       warn_dangling_symrefs(stdout, dangling_msg, &refs_to_prune);
 
+       string_list_clear(&refs_to_prune, 0);
        free_remote_ref_states(&states);
        return result;
 }
index 28456206c5d135adba191c865e49aa75dc201691..3f852f35d1e786b2584d435d640ae830a9f34639 100644 (file)
@@ -135,7 +135,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        };
        struct child_process cmd = CHILD_PROCESS_INIT;
        struct string_list_item *item;
-       struct argv_array cmd_args = ARGV_ARRAY_INIT;
        struct string_list names = STRING_LIST_INIT_DUP;
        struct string_list rollback = STRING_LIST_INIT_NODUP;
        struct string_list existing_packs = STRING_LIST_INIT_DUP;
@@ -202,56 +201,55 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 
        sigchain_push_common(remove_pack_on_signal);
 
-       argv_array_push(&cmd_args, "pack-objects");
-       argv_array_push(&cmd_args, "--keep-true-parents");
+       argv_array_push(&cmd.args, "pack-objects");
+       argv_array_push(&cmd.args, "--keep-true-parents");
        if (!pack_kept_objects)
-               argv_array_push(&cmd_args, "--honor-pack-keep");
-       argv_array_push(&cmd_args, "--non-empty");
-       argv_array_push(&cmd_args, "--all");
-       argv_array_push(&cmd_args, "--reflog");
-       argv_array_push(&cmd_args, "--indexed-objects");
+               argv_array_push(&cmd.args, "--honor-pack-keep");
+       argv_array_push(&cmd.args, "--non-empty");
+       argv_array_push(&cmd.args, "--all");
+       argv_array_push(&cmd.args, "--reflog");
+       argv_array_push(&cmd.args, "--indexed-objects");
        if (window)
-               argv_array_pushf(&cmd_args, "--window=%s", window);
+               argv_array_pushf(&cmd.args, "--window=%s", window);
        if (window_memory)
-               argv_array_pushf(&cmd_args, "--window-memory=%s", window_memory);
+               argv_array_pushf(&cmd.args, "--window-memory=%s", window_memory);
        if (depth)
-               argv_array_pushf(&cmd_args, "--depth=%s", depth);
+               argv_array_pushf(&cmd.args, "--depth=%s", depth);
        if (max_pack_size)
-               argv_array_pushf(&cmd_args, "--max-pack-size=%s", max_pack_size);
+               argv_array_pushf(&cmd.args, "--max-pack-size=%s", max_pack_size);
        if (no_reuse_delta)
-               argv_array_pushf(&cmd_args, "--no-reuse-delta");
+               argv_array_pushf(&cmd.args, "--no-reuse-delta");
        if (no_reuse_object)
-               argv_array_pushf(&cmd_args, "--no-reuse-object");
+               argv_array_pushf(&cmd.args, "--no-reuse-object");
        if (write_bitmaps)
-               argv_array_push(&cmd_args, "--write-bitmap-index");
+               argv_array_push(&cmd.args, "--write-bitmap-index");
 
        if (pack_everything & ALL_INTO_ONE) {
                get_non_kept_pack_filenames(&existing_packs);
 
                if (existing_packs.nr && delete_redundant) {
                        if (unpack_unreachable)
-                               argv_array_pushf(&cmd_args,
+                               argv_array_pushf(&cmd.args,
                                                "--unpack-unreachable=%s",
                                                unpack_unreachable);
                        else if (pack_everything & LOOSEN_UNREACHABLE)
-                               argv_array_push(&cmd_args,
+                               argv_array_push(&cmd.args,
                                                "--unpack-unreachable");
                }
        } else {
-               argv_array_push(&cmd_args, "--unpacked");
-               argv_array_push(&cmd_args, "--incremental");
+               argv_array_push(&cmd.args, "--unpacked");
+               argv_array_push(&cmd.args, "--incremental");
        }
 
        if (local)
-               argv_array_push(&cmd_args,  "--local");
+               argv_array_push(&cmd.args,  "--local");
        if (quiet)
-               argv_array_push(&cmd_args,  "--quiet");
+               argv_array_push(&cmd.args,  "--quiet");
        if (delta_base_offset)
-               argv_array_push(&cmd_args,  "--delta-base-offset");
+               argv_array_push(&cmd.args,  "--delta-base-offset");
 
-       argv_array_push(&cmd_args, packtmp);
+       argv_array_push(&cmd.args, packtmp);
 
-       cmd.argv = cmd_args.argv;
        cmd.git_cmd = 1;
        cmd.out = -1;
        cmd.no_stdin = 1;
@@ -270,7 +268,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
        ret = finish_command(&cmd);
        if (ret)
                return ret;
-       argv_array_clear(&cmd_args);
 
        if (!names.nr && !quiet)
                printf("Nothing new to pack.\n");
@@ -379,7 +376,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
 
        if (delete_redundant) {
                int opts = 0;
-               sort_string_list(&names);
+               string_list_sort(&names);
                for_each_string_list_item(item, &existing_packs) {
                        char *sha1;
                        size_t len = strlen(item->string);
index 35d3c43ed656bf28b78501426f4502c0dff1e7b0..95328b80d930260915ad86a30a21ecd3c1b7d1f4 100644 (file)
@@ -279,7 +279,7 @@ static int try_difference(const char *arg)
                        struct commit *a, *b;
                        a = lookup_commit_reference(sha1);
                        b = lookup_commit_reference(end);
-                       exclude = get_merge_bases(a, b, 1);
+                       exclude = get_merge_bases(a, b);
                        while (exclude) {
                                struct commit_list *n = exclude->next;
                                show_rev(REVERSED,
index 855d94b90ba019ff19832ff49a76d6cc0077e956..ac6667242c562bb7a215982754211a3e035aae8a 100644 (file)
@@ -91,7 +91,7 @@ static void use(int bytes)
 static void *get_data(unsigned long size)
 {
        git_zstream stream;
-       void *buf = xmalloc(size);
+       void *buf = xmallocz(size);
 
        memset(&stream, 0, sizeof(stream));
 
index 6c9be051284a78cbdbe6630dbcaae4846288c667..1993529521c0ef20860795168392d1dd7209c991 100644 (file)
@@ -282,26 +282,22 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
        char *refname;
        unsigned char new_sha1[20];
        unsigned char old_sha1[20];
-       int have_old;
 
        refname = parse_refname(input, &next);
        if (!refname)
                die("verify: missing <ref>");
 
        if (parse_next_sha1(input, &next, old_sha1, "verify", refname,
-                           PARSE_SHA1_OLD)) {
-               hashclr(new_sha1);
-               have_old = 0;
-       } else {
-               hashcpy(new_sha1, old_sha1);
-               have_old = 1;
-       }
+                           PARSE_SHA1_OLD))
+               hashclr(old_sha1);
+
+       hashcpy(new_sha1, old_sha1);
 
        if (*next != line_termination)
                die("verify %s: extra input: %s", refname, next);
 
        if (ref_transaction_update(transaction, refname, new_sha1, old_sha1,
-                                  update_flags, have_old, msg, &err))
+                                  update_flags, 1, msg, &err))
                die("%s", err.buf);
 
        update_flags = 0;
diff --git a/cache.h b/cache.h
index 22b7b8129072f3905c68f02fe19f463bdb738b9e..f704af5df0984e092fe318e535596921c4ea7122 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -65,13 +65,6 @@ unsigned long git_deflate_bound(git_zstream *, unsigned long);
  *
  * The value 0160000 is not normally a valid mode, and
  * also just happens to be S_IFDIR + S_IFLNK
- *
- * NOTE! We *really* shouldn't depend on the S_IFxxx macros
- * always having the same values everywhere. We should use
- * our internal git values for these things, and then we can
- * translate that to the OS-specific value. It just so
- * happens that everybody shares the same bit representation
- * in the UNIX world (and apparently wider too..)
  */
 #define S_IFGITLINK    0160000
 #define S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK)
diff --git a/color.c b/color.c
index 7941e932d2fb7cb0af5d15dcb2754bc8c96ec657..809b359a42d426d61f0452e89725177eadeb54cb 100644 (file)
--- a/color.c
+++ b/color.c
@@ -26,30 +26,109 @@ const char *column_colors_ansi[] = {
 /* Ignore the RESET at the end when giving the size */
 const int column_colors_ansi_max = ARRAY_SIZE(column_colors_ansi) - 1;
 
-static int parse_color(const char *name, int len)
+/* An individual foreground or background color. */
+struct color {
+       enum {
+               COLOR_UNSPECIFIED = 0,
+               COLOR_NORMAL,
+               COLOR_ANSI, /* basic 0-7 ANSI colors */
+               COLOR_256,
+               COLOR_RGB
+       } type;
+       /* The numeric value for ANSI and 256-color modes */
+       unsigned char value;
+       /* 24-bit RGB color values */
+       unsigned char red, green, blue;
+};
+
+/*
+ * "word" is a buffer of length "len"; does it match the NUL-terminated
+ * "match" exactly?
+ */
+static int match_word(const char *word, int len, const char *match)
 {
+       return !strncasecmp(word, match, len) && !match[len];
+}
+
+static int get_hex_color(const char *in, unsigned char *out)
+{
+       unsigned int val;
+       val = (hexval(in[0]) << 4) | hexval(in[1]);
+       if (val & ~0xff)
+               return -1;
+       *out = val;
+       return 0;
+}
+
+static int parse_color(struct color *out, const char *name, int len)
+{
+       /* Positions in array must match ANSI color codes */
        static const char * const color_names[] = {
-               "normal", "black", "red", "green", "yellow",
+               "black", "red", "green", "yellow",
                "blue", "magenta", "cyan", "white"
        };
        char *end;
        int i;
+       long val;
+
+       /* First try the special word "normal"... */
+       if (match_word(name, len, "normal")) {
+               out->type = COLOR_NORMAL;
+               return 0;
+       }
+
+       /* Try a 24-bit RGB value */
+       if (len == 7 && name[0] == '#') {
+               if (!get_hex_color(name + 1, &out->red) &&
+                   !get_hex_color(name + 3, &out->green) &&
+                   !get_hex_color(name + 5, &out->blue)) {
+                       out->type = COLOR_RGB;
+                       return 0;
+               }
+       }
+
+       /* Then pick from our human-readable color names... */
        for (i = 0; i < ARRAY_SIZE(color_names); i++) {
-               const char *str = color_names[i];
-               if (!strncasecmp(name, str, len) && !str[len])
-                       return i - 1;
+               if (match_word(name, len, color_names[i])) {
+                       out->type = COLOR_ANSI;
+                       out->value = i;
+                       return 0;
+               }
+       }
+
+       /* And finally try a literal 256-color-mode number */
+       val = strtol(name, &end, 10);
+       if (end - name == len) {
+               /*
+                * Allow "-1" as an alias for "normal", but other negative
+                * numbers are bogus.
+                */
+               if (val < -1)
+                       ; /* fall through to error */
+               else if (val < 0) {
+                       out->type = COLOR_NORMAL;
+                       return 0;
+               /* Rewrite low numbers as more-portable standard colors. */
+               } else if (val < 8) {
+                       out->type = COLOR_ANSI;
+                       out->value = val;
+               } else if (val < 256) {
+                       out->type = COLOR_256;
+                       out->value = val;
+                       return 0;
+               }
        }
-       i = strtol(name, &end, 10);
-       if (end - name == len && i >= -1 && i <= 255)
-               return i;
-       return -2;
+
+       return -1;
 }
 
 static int parse_attr(const char *name, int len)
 {
-       static const int attr_values[] = { 1, 2, 4, 5, 7 };
+       static const int attr_values[] = { 1, 2, 4, 5, 7,
+                                          22, 22, 24, 25, 27 };
        static const char * const attr_names[] = {
-               "bold", "dim", "ul", "blink", "reverse"
+               "bold", "dim", "ul", "blink", "reverse",
+               "nobold", "nodim", "noul", "noblink", "noreverse"
        };
        int i;
        for (i = 0; i < ARRAY_SIZE(attr_names); i++) {
@@ -65,13 +144,44 @@ int color_parse(const char *value, char *dst)
        return color_parse_mem(value, strlen(value), dst);
 }
 
+/*
+ * Write the ANSI color codes for "c" to "out"; the string should
+ * already have the ANSI escape code in it. "out" should have enough
+ * space in it to fit any color.
+ */
+static char *color_output(char *out, const struct color *c, char type)
+{
+       switch (c->type) {
+       case COLOR_UNSPECIFIED:
+       case COLOR_NORMAL:
+               break;
+       case COLOR_ANSI:
+               *out++ = type;
+               *out++ = '0' + c->value;
+               break;
+       case COLOR_256:
+               out += sprintf(out, "%c8;5;%d", type, c->value);
+               break;
+       case COLOR_RGB:
+               out += sprintf(out, "%c8;2;%d;%d;%d", type,
+                              c->red, c->green, c->blue);
+               break;
+       }
+       return out;
+}
+
+static int color_empty(const struct color *c)
+{
+       return c->type <= COLOR_NORMAL;
+}
+
 int color_parse_mem(const char *value, int value_len, char *dst)
 {
        const char *ptr = value;
        int len = value_len;
        unsigned int attr = 0;
-       int fg = -2;
-       int bg = -2;
+       struct color fg = { COLOR_UNSPECIFIED };
+       struct color bg = { COLOR_UNSPECIFIED };
 
        if (!strncasecmp(value, "reset", len)) {
                strcpy(dst, GIT_COLOR_RESET);
@@ -81,6 +191,7 @@ int color_parse_mem(const char *value, int value_len, char *dst)
        /* [fg [bg]] [attr]... */
        while (len > 0) {
                const char *word = ptr;
+               struct color c;
                int val, wordlen = 0;
 
                while (len > 0 && !isspace(word[wordlen])) {
@@ -94,14 +205,13 @@ int color_parse_mem(const char *value, int value_len, char *dst)
                        len--;
                }
 
-               val = parse_color(word, wordlen);
-               if (val >= -1) {
-                       if (fg == -2) {
-                               fg = val;
+               if (!parse_color(&c, word, wordlen)) {
+                       if (fg.type == COLOR_UNSPECIFIED) {
+                               fg = c;
                                continue;
                        }
-                       if (bg == -2) {
-                               bg = val;
+                       if (bg.type == COLOR_UNSPECIFIED) {
+                               bg = c;
                                continue;
                        }
                        goto bad;
@@ -113,7 +223,7 @@ int color_parse_mem(const char *value, int value_len, char *dst)
                        goto bad;
        }
 
-       if (attr || fg >= 0 || bg >= 0) {
+       if (attr || !color_empty(&fg) || !color_empty(&bg)) {
                int sep = 0;
                int i;
 
@@ -127,27 +237,19 @@ int color_parse_mem(const char *value, int value_len, char *dst)
                        attr &= ~bit;
                        if (sep++)
                                *dst++ = ';';
-                       *dst++ = '0' + i;
+                       dst += sprintf(dst, "%d", i);
                }
-               if (fg >= 0) {
+               if (!color_empty(&fg)) {
                        if (sep++)
                                *dst++ = ';';
-                       if (fg < 8) {
-                               *dst++ = '3';
-                               *dst++ = '0' + fg;
-                       } else {
-                               dst += sprintf(dst, "38;5;%d", fg);
-                       }
+                       /* foreground colors are all in the 3x range */
+                       dst = color_output(dst, &fg, '3');
                }
-               if (bg >= 0) {
+               if (!color_empty(&bg)) {
                        if (sep++)
                                *dst++ = ';';
-                       if (bg < 8) {
-                               *dst++ = '4';
-                               *dst++ = '0' + bg;
-                       } else {
-                               dst += sprintf(dst, "48;5;%d", bg);
-                       }
+                       /* background colors are all in the 4x range */
+                       dst = color_output(dst, &bg, '4');
                }
                *dst++ = 'm';
        }
diff --git a/color.h b/color.h
index f5beab1ed782549eb08ad11392ed8e6331bdd653..7fe77fb55edac6aa8a284f6c6671c54da79e2591 100644 (file)
--- a/color.h
+++ b/color.h
@@ -8,15 +8,15 @@ struct strbuf;
 /*
  * The maximum length of ANSI color sequence we would generate:
  * - leading ESC '['            2
- * - attr + ';'                 2 * 8 (e.g. "1;")
- * - fg color + ';'             9 (e.g. "38;5;2xx;")
- * - fg color + ';'             9 (e.g. "48;5;2xx;")
+ * - attr + ';'                 3 * 10 (e.g. "1;")
+ * - fg color + ';'             17 (e.g. "38;2;255;255;255;")
+ * - bg color + ';'             17 (e.g. "48;2;255;255;255;")
  * - terminating 'm' NUL        2
  *
  * The above overcounts attr (we only use 5 not 8) and one semicolon
  * but it is close enough.
  */
-#define COLOR_MAXLEN 40
+#define COLOR_MAXLEN 70
 
 /*
  * IMPORTANT: Due to the way these color codes are emulated on Windows,
index 19cf8f9c67bd0f4d71172f33424f7d2371a3af68..a8c7577d28a4b2a0b5fc13420f8a141871626087 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -867,7 +867,7 @@ struct commit_list *get_octopus_merge_bases(struct commit_list *in)
 
                for (j = ret; j; j = j->next) {
                        struct commit_list *bases;
-                       bases = get_merge_bases(i->item, j->item, 1);
+                       bases = get_merge_bases(i->item, j->item);
                        if (!new)
                                new = bases;
                        else
@@ -936,10 +936,10 @@ static int remove_redundant(struct commit **array, int cnt)
        return filled;
 }
 
-struct commit_list *get_merge_bases_many(struct commit *one,
-                                        int n,
-                                        struct commit **twos,
-                                        int cleanup)
+static struct commit_list *get_merge_bases_many_0(struct commit *one,
+                                                 int n,
+                                                 struct commit **twos,
+                                                 int cleanup)
 {
        struct commit_list *list;
        struct commit **rslt;
@@ -977,10 +977,23 @@ struct commit_list *get_merge_bases_many(struct commit *one,
        return result;
 }
 
-struct commit_list *get_merge_bases(struct commit *one, struct commit *two,
-                                   int cleanup)
+struct commit_list *get_merge_bases_many(struct commit *one,
+                                        int n,
+                                        struct commit **twos)
 {
-       return get_merge_bases_many(one, 1, &two, cleanup);
+       return get_merge_bases_many_0(one, n, twos, 1);
+}
+
+struct commit_list *get_merge_bases_many_dirty(struct commit *one,
+                                              int n,
+                                              struct commit **twos)
+{
+       return get_merge_bases_many_0(one, n, twos, 0);
+}
+
+struct commit_list *get_merge_bases(struct commit *one, struct commit *two)
+{
+       return get_merge_bases_many_0(one, 1, &two, 1);
 }
 
 /*
@@ -1640,3 +1653,49 @@ const char *find_commit_header(const char *msg, const char *key, size_t *out_len
        }
        return NULL;
 }
+
+/*
+ * Inspect sb and determine the true "end" of the log message, in
+ * order to find where to put a new Signed-off-by: line.  Ignored are
+ * trailing comment lines and blank lines, and also the traditional
+ * "Conflicts:" block that is not commented out, so that we can use
+ * "git commit -s --amend" on an existing commit that forgot to remove
+ * it.
+ *
+ * Returns the number of bytes from the tail to ignore, to be fed as
+ * the second parameter to append_signoff().
+ */
+int ignore_non_trailer(struct strbuf *sb)
+{
+       int boc = 0;
+       int bol = 0;
+       int in_old_conflicts_block = 0;
+
+       while (bol < sb->len) {
+               char *next_line;
+
+               if (!(next_line = memchr(sb->buf + bol, '\n', sb->len - bol)))
+                       next_line = sb->buf + sb->len;
+               else
+                       next_line++;
+
+               if (sb->buf[bol] == comment_line_char || sb->buf[bol] == '\n') {
+                       /* is this the first of the run of comments? */
+                       if (!boc)
+                               boc = bol;
+                       /* otherwise, it is just continuing */
+               } else if (starts_with(sb->buf + bol, "Conflicts:\n")) {
+                       in_old_conflicts_block = 1;
+                       if (!boc)
+                               boc = bol;
+               } else if (in_old_conflicts_block && sb->buf[bol] == '\t') {
+                       ; /* a pathname in the conflicts block */
+               } else if (boc) {
+                       /* the previous was not trailing comment */
+                       boc = 0;
+                       in_old_conflicts_block = 0;
+               }
+               bol = next_line - sb->buf;
+       }
+       return boc ? sb->len - boc : 0;
+}
index bc68ccbe691a28ed9b22fa935c78d2e9640347ea..5cc1e7ec9ee80965d1669e0f96dfeab03f3b0798 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -236,10 +236,13 @@ struct commit_graft *read_graft_line(char *buf, int len);
 int register_commit_graft(struct commit_graft *, int);
 struct commit_graft *lookup_commit_graft(const unsigned char *sha1);
 
-extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup);
-extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos, int cleanup);
+extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2);
+extern struct commit_list *get_merge_bases_many(struct commit *one, int n, struct commit **twos);
 extern struct commit_list *get_octopus_merge_bases(struct commit_list *in);
 
+/* To be used only when object flags after this call no longer matter */
+extern struct commit_list *get_merge_bases_many_dirty(struct commit *one, int n, struct commit **twos);
+
 /* largest positive number a signed 32-bit integer can contain */
 #define INFINITE_DEPTH 0x7fffffff
 
@@ -337,6 +340,9 @@ extern void free_commit_extra_headers(struct commit_extra_header *extra);
 extern const char *find_commit_header(const char *msg, const char *key,
                                      size_t *out_len);
 
+/* Find the end of the log message, the right place for a new trailer. */
+extern int ignore_non_trailer(struct strbuf *sb);
+
 typedef void (*each_mergetag_fn)(struct commit *commit, struct commit_extra_header *extra,
                                 void *cb_data);
 
diff --git a/compat/stat.c b/compat/stat.c
new file mode 100644 (file)
index 0000000..a2d3931
--- /dev/null
@@ -0,0 +1,48 @@
+#define _POSIX_C_SOURCE 200112L
+#include <sys/stat.h>  /* *stat, S_IS* */
+#include <sys/types.h> /* mode_t       */
+
+static inline mode_t mode_native_to_git(mode_t native_mode)
+{
+       mode_t perm_bits = native_mode & 07777;
+       if (S_ISREG(native_mode))
+               return 0100000 | perm_bits;
+       if (S_ISDIR(native_mode))
+               return 0040000 | perm_bits;
+       if (S_ISLNK(native_mode))
+               return 0120000 | perm_bits;
+       if (S_ISBLK(native_mode))
+               return 0060000 | perm_bits;
+       if (S_ISCHR(native_mode))
+               return 0020000 | perm_bits;
+       if (S_ISFIFO(native_mode))
+               return 0010000 | perm_bits;
+       if (S_ISSOCK(native_mode))
+               return 0140000 | perm_bits;
+       /* Non-standard type bits were given. */
+       return perm_bits;
+}
+
+int git_stat(const char *path, struct stat *buf)
+{
+       int rc = stat(path, buf);
+       if (rc == 0)
+               buf->st_mode = mode_native_to_git(buf->st_mode);
+       return rc;
+}
+
+int git_fstat(int fd, struct stat *buf)
+{
+       int rc = fstat(fd, buf);
+       if (rc == 0)
+               buf->st_mode = mode_native_to_git(buf->st_mode);
+       return rc;
+}
+
+int git_lstat(const char *path, struct stat *buf)
+{
+       int rc = lstat(path, buf);
+       if (rc == 0)
+               buf->st_mode = mode_native_to_git(buf->st_mode);
+       return rc;
+}
index 6af964797f7b0ee64deb34bdff40b2a17db067b6..5c1312f24a247fca9bdd7dc9d66aa05f8a7c60d5 100644 (file)
@@ -873,6 +873,29 @@ else
        SNPRINTF_RETURNS_BOGUS=
 fi
 GIT_CONF_SUBST([SNPRINTF_RETURNS_BOGUS])
+#
+# Define NEEDS_MODE_TRANSLATION if your OS strays from the typical file type
+# bits in mode values.
+AC_CACHE_CHECK([whether the platform uses typical file type bits],
+ [ac_cv_sane_mode_bits], [
+AC_EGREP_CPP(yippeeyeswehaveit,
+       AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT],
+[#if S_IFMT == 0170000 && \
+       S_IFREG == 0100000 && S_IFDIR == 0040000 && S_IFLNK == 0120000 && \
+       S_IFBLK == 0060000 && S_IFCHR == 0020000 && \
+       S_IFIFO == 0010000 && S_IFSOCK == 0140000
+yippeeyeswehaveit
+#endif
+]),
+       [ac_cv_sane_mode_bits=yes],
+       [ac_cv_sane_mode_bits=no])
+])
+if test $ac_cv_sane_mode_bits = yes; then
+       NEEDS_MODE_TRANSLATION=
+else
+       NEEDS_MODE_TRANSLATION=UnfortunatelyYes
+fi
+GIT_CONF_SUBST([NEEDS_MODE_TRANSLATION])
 
 
 ## Checks for library functions.
index d47d0ec6040fdb8b07a689e299dac121bb468717..062e133aa39b9e522bf3a03c5e57ac67c03ad88e 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -93,7 +93,7 @@ static void annotate_refs_with_symref_info(struct ref *ref)
                parse_one_symref_info(&symref, val, len);
                feature_list = val + 1;
        }
-       sort_string_list(&symref);
+       string_list_sort(&symref);
 
        for (; ref; ref = ref->next) {
                struct string_list_item *item;
@@ -700,14 +700,23 @@ struct child_process *git_connect(int fd[2], const char *url,
 
                conn->in = conn->out = -1;
                if (protocol == PROTO_SSH) {
-                       const char *ssh = getenv("GIT_SSH");
-                       int putty = ssh && strcasestr(ssh, "plink");
+                       const char *ssh;
+                       int putty;
                        char *ssh_host = hostandport;
                        const char *port = NULL;
                        get_host_and_port(&ssh_host, &port);
                        port = get_port_numeric(port);
 
-                       if (!ssh) ssh = "ssh";
+                       ssh = getenv("GIT_SSH_COMMAND");
+                       if (ssh) {
+                               conn->use_shell = 1;
+                               putty = 0;
+                       } else {
+                               ssh = getenv("GIT_SSH");
+                               if (!ssh)
+                                       ssh = "ssh";
+                               putty = !!strcasestr(ssh, "plink");
+                       }
 
                        argv_array_push(&conn->args, ssh);
                        if (putty && !strcasestr(ssh, "tortoiseplink"))
index 2fece98c603e24ed5ce08156e0e44199a149ba83..cd765795ae42edfdf21a054619b64d5c3800f4f6 100644 (file)
@@ -16,9 +16,9 @@
 #
 # To use these routines:
 #
-#    1) Copy this file to somewhere (e.g. ~/.git-completion.sh).
+#    1) Copy this file to somewhere (e.g. ~/.git-completion.bash).
 #    2) Add the following line to your .bashrc/.zshrc:
-#        source ~/.git-completion.sh
+#        source ~/.git-completion.bash
 #    3) Consider changing your PS1 to also show the current branch,
 #       see git-prompt.sh for details.
 #
@@ -1875,6 +1875,10 @@ _git_config ()
                __gitcomp "$__git_send_email_suppresscc_options"
                return
                ;;
+       sendemail.transferencoding)
+               __gitcomp "7bit 8bit quoted-printable base64"
+               return
+               ;;
        --get|--get-all|--unset|--unset-all)
                __gitcomp_nl "$(__git_config_get_set_variables)"
                return
@@ -2548,6 +2552,16 @@ _git_tag ()
                __gitcomp_nl "$(__git_refs)"
                ;;
        esac
+
+       case "$cur" in
+       --*)
+               __gitcomp "
+                       --list --delete --verify --annotate --message --file
+                       --sign --cleanup --local-user --force --column --sort
+                       --contains --points-at
+                       "
+               ;;
+       esac
 }
 
 _git_whatchanged ()
index 9f6f0fa5581002a2371e062fd5def0978733edc1..e25541308a1c269285a26b205d2d9990a789060a 100644 (file)
@@ -9,7 +9,7 @@
 #
 # If your script is somewhere else, you can configure it on your ~/.zshrc:
 #
-#  zstyle ':completion:*:*:git:*' script ~/.git-completion.sh
+#  zstyle ':completion:*:*:git:*' script ~/.git-completion.zsh
 #
 # The recommended way to install this script is to copy to '~/.zsh/_git', and
 # then add the following to your ~/.zshrc file:
index c5473dc8dba78b372fd95ef2bf5257ff5cdc3baf..3c3fc6d5d94c5dc6a9ec291fc217b590a11c5be3 100644 (file)
@@ -270,7 +270,7 @@ __git_ps1_colorize_gitstring ()
 
 __git_eread ()
 {
-       f="$1"
+       local f="$1"
        shift
        test -r "$f" && read "$@" <"$f"
 }
@@ -288,6 +288,7 @@ __git_eread ()
 # In this mode you can request colored hints using GIT_PS1_SHOWCOLORHINTS=true
 __git_ps1 ()
 {
+       local exit=$?
        local pcmode=no
        local detached=no
        local ps1pc_start='\u@\h:\w '
@@ -511,4 +512,7 @@ __git_ps1 ()
        else
                printf -- "$printf_format" "$gitstring"
        fi
+
+       # preserve exit status
+       return $exit
 }
index 502e03b3058e947835d396540af39c83a45d42aa..836b97a73075a51ef8bc66ba080085a7de4c8f32 100644 (file)
@@ -58,6 +58,47 @@ following in your git configuration:
        diff = diff-highlight | less
 ---------------------------------------------
 
+
+Color Config
+------------
+
+You can configure the highlight colors and attributes using git's
+config. The colors for "old" and "new" lines can be specified
+independently. There are two "modes" of configuration:
+
+  1. You can specify a "highlight" color and a matching "reset" color.
+     This will retain any existing colors in the diff, and apply the
+     "highlight" and "reset" colors before and after the highlighted
+     portion.
+
+  2. You can specify a "normal" color and a "highlight" color. In this
+     case, existing colors are dropped from that line. The non-highlighted
+     bits of the line get the "normal" color, and the highlights get the
+     "highlight" color.
+
+If no "new" colors are specified, they default to the "old" colors. If
+no "old" colors are specified, the default is to reverse the foreground
+and background for highlighted portions.
+
+Examples:
+
+---------------------------------------------
+# Underline highlighted portions
+[color "diff-highlight"]
+oldHighlight = ul
+oldReset = noul
+---------------------------------------------
+
+---------------------------------------------
+# Varying background intensities
+[color "diff-highlight"]
+oldNormal = "black #f8cbcb"
+oldHighlight = "black #ffaaaa"
+newNormal = "black #cbeecb"
+newHighlight = "black #aaffaa"
+---------------------------------------------
+
+
 Bugs
 ----
 
index 69a652e7b2cc4ed2e03ead8aec4b3abeebf20b14..08c88bbc87e51e25cacc5826b26a223f3bfbd382 100755 (executable)
@@ -5,8 +5,18 @@ use strict;
 
 # Highlight by reversing foreground and background. You could do
 # other things like bold or underline if you prefer.
-my $HIGHLIGHT   = "\x1b[7m";
-my $UNHIGHLIGHT = "\x1b[27m";
+my @OLD_HIGHLIGHT = (
+       color_config('color.diff-highlight.oldnormal'),
+       color_config('color.diff-highlight.oldhighlight', "\x1b[7m"),
+       color_config('color.diff-highlight.oldreset', "\x1b[27m")
+);
+my @NEW_HIGHLIGHT = (
+       color_config('color.diff-highlight.newnormal', $OLD_HIGHLIGHT[0]),
+       color_config('color.diff-highlight.newhighlight', $OLD_HIGHLIGHT[1]),
+       color_config('color.diff-highlight.newreset', $OLD_HIGHLIGHT[2])
+);
+
+my $RESET = "\x1b[m";
 my $COLOR = qr/\x1b\[[0-9;]*m/;
 my $BORING = qr/$COLOR|\s/;
 
@@ -57,6 +67,17 @@ show_hunk(\@removed, \@added);
 
 exit 0;
 
+# Ideally we would feed the default as a human-readable color to
+# git-config as the fallback value. But diff-highlight does
+# not otherwise depend on git at all, and there are reports
+# of it being used in other settings. Let's handle our own
+# fallback, which means we will work even if git can't be run.
+sub color_config {
+       my ($key, $default) = @_;
+       my $s = `git config --get-color $key 2>/dev/null`;
+       return length($s) ? $s : $default;
+}
+
 sub show_hunk {
        my ($a, $b) = @_;
 
@@ -132,8 +153,8 @@ sub highlight_pair {
        }
 
        if (is_pair_interesting(\@a, $pa, $sa, \@b, $pb, $sb)) {
-               return highlight_line(\@a, $pa, $sa),
-                      highlight_line(\@b, $pb, $sb);
+               return highlight_line(\@a, $pa, $sa, \@OLD_HIGHLIGHT),
+                      highlight_line(\@b, $pb, $sb, \@NEW_HIGHLIGHT);
        }
        else {
                return join('', @a),
@@ -148,15 +169,30 @@ sub split_line {
 }
 
 sub highlight_line {
-       my ($line, $prefix, $suffix) = @_;
-
-       return join('',
-               @{$line}[0..($prefix-1)],
-               $HIGHLIGHT,
-               @{$line}[$prefix..$suffix],
-               $UNHIGHLIGHT,
-               @{$line}[($suffix+1)..$#$line]
-       );
+       my ($line, $prefix, $suffix, $theme) = @_;
+
+       my $start = join('', @{$line}[0..($prefix-1)]);
+       my $mid = join('', @{$line}[$prefix..$suffix]);
+       my $end = join('', @{$line}[($suffix+1)..$#$line]);
+
+       # If we have a "normal" color specified, then take over the whole line.
+       # Otherwise, we try to just manipulate the highlighted bits.
+       if (defined $theme->[0]) {
+               s/$COLOR//g for ($start, $mid, $end);
+               chomp $end;
+               return join('',
+                       $theme->[0], $start, $RESET,
+                       $theme->[1], $mid, $RESET,
+                       $theme->[0], $end, $RESET,
+                       "\n"
+               );
+       } else {
+               return join('',
+                       $start,
+                       $theme->[1], $mid, $theme->[2],
+                       $end
+               );
+       }
 }
 
 # Pairs are interesting to highlight only if we are going to end up
index 75e8b258177f7f04dadcac125f2bf7ebea4d0f81..888c34a5215258ad7d5715771f92ab58f3efd363 100755 (executable)
@@ -10,6 +10,10 @@ die () {
        exit 128
 }
 
+failed () {
+       die "unable to create new workdir '$new_workdir'!"
+}
+
 if test $# -lt 2 || test $# -gt 3
 then
        usage "$0 <repository> <new_workdir> [<branch>]"
@@ -35,7 +39,7 @@ esac
 
 # don't link to a configured bare repository
 isbare=$(git --git-dir="$git_dir" config --bool --get core.bare)
-if test ztrue = z$isbare
+if test ztrue = "z$isbare"
 then
        die "\"$git_dir\" has core.bare set to true," \
                " remove from \"$git_dir/config\" to use $0"
@@ -48,35 +52,54 @@ then
                "a complete repository."
 fi
 
-# don't recreate a workdir over an existing repository
-if test -e "$new_workdir"
+# make sure the links in the workdir have full paths to the original repo
+git_dir=$(cd "$git_dir" && pwd) || exit 1
+
+# don't recreate a workdir over an existing directory, unless it's empty
+if test -d "$new_workdir"
 then
-       die "destination directory '$new_workdir' already exists."
+       if test $(ls -a1 "$new_workdir/." | wc -l) -ne 2
+       then
+               die "destination directory '$new_workdir' is not empty."
+       fi
+       cleandir="$new_workdir/.git"
+else
+       cleandir="$new_workdir"
 fi
 
-# make sure the links use full paths
-git_dir=$(cd "$git_dir"; pwd)
+mkdir -p "$new_workdir/.git" || failed
+cleandir=$(cd "$cleandir" && pwd) || failed
 
-# create the workdir
-mkdir -p "$new_workdir/.git" || die "unable to create \"$new_workdir\"!"
+cleanup () {
+       rm -rf "$cleandir"
+}
+siglist="0 1 2 15"
+trap cleanup $siglist
 
 # create the links to the original repo.  explicitly exclude index, HEAD and
 # logs/HEAD from the list since they are purely related to the current working
 # directory, and should not be shared.
 for x in config refs logs/refs objects info hooks packed-refs remotes rr-cache svn
 do
+       # create a containing directory if needed
        case $x in
        */*)
-               mkdir -p "$(dirname "$new_workdir/.git/$x")"
+               mkdir -p "$new_workdir/.git/${x%/*}"
                ;;
        esac
-       ln -s "$git_dir/$x" "$new_workdir/.git/$x"
+
+       ln -s "$git_dir/$x" "$new_workdir/.git/$x" || failed
 done
 
-# now setup the workdir
-cd "$new_workdir"
+# commands below this are run in the context of the new workdir
+cd "$new_workdir" || failed
+
 # copy the HEAD from the original repository as a default branch
-cp "$git_dir/HEAD" .git/HEAD
-# checkout the branch (either the same as HEAD from the original repository, or
-# the one that was asked for)
+cp "$git_dir/HEAD" .git/HEAD || failed
+
+# the workdir is set up.  if the checkout fails, the user can fix it.
+trap - $siglist
+
+# checkout the branch (either the same as HEAD from the original repository,
+# or the one that was asked for)
 git checkout -f $branch
index 1886ea50b3b3c2a213e34876de691fa3d0a83b6c..b146ad8481b133892a542691c7e36f5e7974cfdc 100644 (file)
@@ -173,6 +173,8 @@ int credential_read(struct credential *c, FILE *fp)
                        c->path = xstrdup(value);
                } else if (!strcmp(key, "url")) {
                        credential_from_url(c, value);
+               } else if (!strcmp(key, "quit")) {
+                       c->quit = !!git_config_bool("quit", value);
                }
                /*
                 * Ignore other lines; we don't know what they mean, but
@@ -274,6 +276,9 @@ void credential_fill(struct credential *c)
                credential_do(c, c->helpers.items[i].string, "get");
                if (c->username && c->password)
                        return;
+               if (c->quit)
+                       die("credential helper '%s' told us to quit",
+                           c->helpers.items[i].string);
        }
 
        credential_getpass(c);
index 0c3e85e8e4232ad9298372efebf7696a77dc94b1..6b0cd16be2b96b23ae5ce14a07a8ad130af8d5bb 100644 (file)
@@ -7,6 +7,7 @@ struct credential {
        struct string_list helpers;
        unsigned approved:1,
                 configured:1,
+                quit:1,
                 use_http_path:1;
 
        char *username;
index bb543d52f108cf1e976ee644e337f5ccec983790..7530927d774562f82636aa773481ae93600c1756 100644 (file)
@@ -39,4 +39,15 @@ extern void sha1flush(struct sha1file *f);
 extern void crc32_begin(struct sha1file *);
 extern uint32_t crc32_end(struct sha1file *);
 
+static inline void sha1write_u8(struct sha1file *f, uint8_t data)
+{
+       sha1write(f, &data, sizeof(data));
+}
+
+static inline void sha1write_be32(struct sha1file *f, uint32_t data)
+{
+       data = htonl(data);
+       sha1write(f, &data, sizeof(data));
+}
+
 #endif
diff --git a/date.c b/date.c
index 59dfe579c6a0c65abe0a34052cdbf16643afbfb8..3eba2dfe8841cee28850e2f1f4177e1e32f1c8a8 100644 (file)
--- a/date.c
+++ b/date.c
@@ -405,9 +405,9 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now,
        return 0;
 }
 
-static int match_multi_number(unsigned long num, char c, const char *date, char *end, struct tm *tm)
+static int match_multi_number(unsigned long num, char c, const char *date,
+                             char *end, struct tm *tm, time_t now)
 {
-       time_t now;
        struct tm now_tm;
        struct tm *refuse_future;
        long num2, num3;
@@ -433,17 +433,18 @@ static int match_multi_number(unsigned long num, char c, const char *date, char
        case '-':
        case '/':
        case '.':
-               now = time(NULL);
+               if (!now)
+                       now = time(NULL);
                refuse_future = NULL;
                if (gmtime_r(&now, &now_tm))
                        refuse_future = &now_tm;
 
                if (num > 70) {
                        /* yyyy-mm-dd? */
-                       if (is_date(num, num2, num3, refuse_future, now, tm))
+                       if (is_date(num, num2, num3, NULL, now, tm))
                                break;
                        /* yyyy-dd-mm? */
-                       if (is_date(num, num3, num2, refuse_future, now, tm))
+                       if (is_date(num, num3, num2, NULL, now, tm))
                                break;
                }
                /* Our eastern European friends say dd.mm.yy[yy]
@@ -513,7 +514,7 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
        case '/':
        case '-':
                if (isdigit(end[1])) {
-                       int match = match_multi_number(num, *end, date, end, tm);
+                       int match = match_multi_number(num, *end, date, end, tm, 0);
                        if (match)
                                return match;
                }
@@ -1013,7 +1014,8 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, struct tm
        return end;
 }
 
-static const char *approxidate_digit(const char *date, struct tm *tm, int *num)
+static const char *approxidate_digit(const char *date, struct tm *tm, int *num,
+                                    time_t now)
 {
        char *end;
        unsigned long number = strtoul(date, &end, 10);
@@ -1024,7 +1026,8 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num)
        case '/':
        case '-':
                if (isdigit(end[1])) {
-                       int match = match_multi_number(number, *end, date, end, tm);
+                       int match = match_multi_number(number, *end, date, end,
+                                                      tm, now);
                        if (match)
                                return date + match;
                }
@@ -1087,7 +1090,7 @@ static unsigned long approxidate_str(const char *date,
                date++;
                if (isdigit(c)) {
                        pending_number(&tm, &number);
-                       date = approxidate_digit(date-1, &tm, &number);
+                       date = approxidate_digit(date-1, &tm, &number, time_sec);
                        touched = 1;
                        continue;
                }
index 1d9e530a84758e34d616690684c4842cd1af4cfc..5473493e10551633659d0727626ffc2273ef4f73 100644 (file)
@@ -246,6 +246,13 @@ static void merge_broken(struct diff_filepair *p,
 
        dp = diff_queue(outq, d->one, c->two);
        dp->score = p->score;
+       /*
+        * We will be one extra user of the same src side of the
+        * broken pair, if it was used as the rename source for other
+        * paths elsewhere.  Increment to mark that the path stays
+        * in the resulting tree.
+        */
+       d->one->rename_used++;
        diff_free_filespec_data(d->two);
        diff_free_filespec_data(c->one);
        free(d);
index 698e7526c40749fd333367018c192537cf6b4562..8ab37b5f74f360abf8ff4d689b4ff4f3d29cf785 100644 (file)
@@ -6,7 +6,7 @@
 static const char *argv_exec_path;
 static const char *argv0_path;
 
-const char *system_path(const char *path)
+char *system_path(const char *path)
 {
 #ifdef RUNTIME_PREFIX
        static const char *prefix;
@@ -16,7 +16,7 @@ const char *system_path(const char *path)
        struct strbuf d = STRBUF_INIT;
 
        if (is_absolute_path(path))
-               return path;
+               return xstrdup(path);
 
 #ifdef RUNTIME_PREFIX
        assert(argv0_path);
@@ -34,8 +34,7 @@ const char *system_path(const char *path)
 #endif
 
        strbuf_addf(&d, "%s/%s", prefix, path);
-       path = strbuf_detach(&d, NULL);
-       return path;
+       return strbuf_detach(&d, NULL);
 }
 
 const char *git_extract_argv0_path(const char *argv0)
index e4c9702f02858973096f6ef0f41e5a572ff4d0db..93b0c02529a854af4ccb648ea0d0571c5495b63a 100644 (file)
@@ -9,6 +9,6 @@ extern const char **prepare_git_cmd(const char **argv);
 extern int execv_git_cmd(const char **argv); /* NULL terminated */
 LAST_ARG_MUST_BE_NULL
 extern int execl_git_cmd(const char *cmd, ...);
-extern const char *system_path(const char *path);
+extern char *system_path(const char *path);
 
 #endif /* GIT_EXEC_CMD_H */
diff --git a/fsck.c b/fsck.c
index 032419463126234fa855b934bae85fb27d6b26a4..10bcb651516e2c25979f8f5af62f87407289e8e6 100644 (file)
--- a/fsck.c
+++ b/fsck.c
@@ -426,7 +426,8 @@ static int fsck_tag_buffer(struct tag *tag, const char *data,
        }
        strbuf_addf(&sb, "refs/tags/%.*s", (int)(eol - buffer), buffer);
        if (check_refname_format(sb.buf, 0))
-               error_func(&tag->object, FSCK_WARN, "invalid 'tag' name: %s", buffer);
+               error_func(&tag->object, FSCK_WARN, "invalid 'tag' name: %.*s",
+                          (int)(eol - buffer), buffer);
        buffer = eol + 1;
 
        if (!skip_prefix(buffer, "tagger ", &buffer))
index 1fadd69f8809f91337a27b98f244a3cf7183b23f..c7256741cc2a28f333d6a9be5f12e248df99ed5e 100755 (executable)
@@ -1356,6 +1356,7 @@ sub patch_update_file {
                  $patch_mode_flavour{TARGET},
                  " [y,n,q,a,d,/$other,?]? ";
                my $line = prompt_single_character;
+               last unless defined $line;
                if ($line) {
                        if ($line =~ /^y/i) {
                                $hunk[$ix]{USE} = 1;
index ee61a77d717a7210a1cf614914ab62788fd5e4fc..a67d0f98989706fa69df4cf7d6242ad9531eb337 100755 (executable)
--- a/git-am.sh
+++ b/git-am.sh
@@ -17,6 +17,7 @@ s,signoff       add a Signed-off-by line to the commit message
 u,utf8          recode into utf8 (default)
 k,keep          pass -k flag to git-mailinfo
 keep-non-patch  pass -b flag to git-mailinfo
+m,message-id    pass -m flag to git-mailinfo
 keep-cr         pass --keep-cr flag to git-mailsplit for mbox format
 no-keep-cr      do not pass --keep-cr flag to git-mailsplit independent of am.keepcr
 c,scissors      strip everything before a scissors line
@@ -371,13 +372,18 @@ split_patches () {
 prec=4
 dotest="$GIT_DIR/rebase-apply"
 sign= utf8=t keep= keepcr= skip= interactive= resolved= rebasing= abort=
-resolvemsg= resume= scissors= no_inbody_headers=
+messageid= resolvemsg= resume= scissors= no_inbody_headers=
 git_apply_opt=
 committer_date_is_author_date=
 ignore_date=
 allow_rerere_autoupdate=
 gpg_sign_opt=
 
+if test "$(git config --bool --get am.messageid)" = true
+then
+    messageid=t
+fi
+
 if test "$(git config --bool --get am.keepcr)" = true
 then
     keepcr=t
@@ -400,6 +406,10 @@ it will be removed. Please do not use it anymore."
                utf8=t ;; # this is now default
        --no-utf8)
                utf8= ;;
+       -m|--message-id)
+               messageid=t ;;
+       --no-message-id)
+               messageid=f ;;
        -k|--keep)
                keep=t ;;
        --keep-non-patch)
@@ -567,6 +577,7 @@ Use \"git am --abort\" to remove it.")"
        echo "$sign" >"$dotest/sign"
        echo "$utf8" >"$dotest/utf8"
        echo "$keep" >"$dotest/keep"
+       echo "$messageid" >"$dotest/messageid"
        echo "$scissors" >"$dotest/scissors"
        echo "$no_inbody_headers" >"$dotest/no_inbody_headers"
        echo "$GIT_QUIET" >"$dotest/quiet"
@@ -621,6 +632,12 @@ b)
 *)
        keep= ;;
 esac
+case "$(cat "$dotest/messageid")" in
+t)
+       messageid=-m ;;
+f)
+       messageid= ;;
+esac
 case "$(cat "$dotest/scissors")" in
 t)
        scissors=--scissors ;;
@@ -692,7 +709,7 @@ do
                        get_author_ident_from_commit "$commit" >"$dotest/author-script"
                        git diff-tree --root --binary --full-index "$commit" >"$dotest/patch"
                else
-                       git mailinfo $keep $no_inbody_headers $scissors $utf8 "$dotest/msg" "$dotest/patch" \
+                       git mailinfo $keep $no_inbody_headers $messageid $scissors $utf8 "$dotest/msg" "$dotest/patch" \
                                <"$dotest/$msgnum" >"$dotest/info" ||
                                stop_here $this
 
index 400e92108687e31dd16fbcea1a43e04556b98566..dcecd857f159357ff7d79cde218895f43795d944 100644 (file)
@@ -75,7 +75,8 @@
 # endif
 #elif !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__USLC__) && \
       !defined(_M_UNIX) && !defined(__sgi) && !defined(__DragonFly__) && \
-      !defined(__TANDEM) && !defined(__QNX__) && !defined(__MirBSD__)
+      !defined(__TANDEM) && !defined(__QNX__) && !defined(__MirBSD__) && \
+      !defined(__CYGWIN__)
 #define _XOPEN_SOURCE 600 /* glibc2 and AIX 5.3L need 500, OpenBSD needs 600 for S_ISLNK() */
 #define _XOPEN_SOURCE_EXTENDED 1 /* AIX 5.3L needs this */
 #endif
@@ -211,8 +212,12 @@ extern char *gitbasename(char *);
 #endif
 
 #ifndef NO_OPENSSL
+#define __AVAILABILITY_MACROS_USES_AVAILABILITY 0
+#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_6
 #include <openssl/ssl.h>
 #include <openssl/err.h>
+#undef MAC_OS_X_VERSION_MIN_REQUIRED
+#undef __AVAILABILITY_MACROS_USES_AVAILABILITY
 #endif
 
 /* On most systems <netdb.h> would have given us this, but
@@ -474,6 +479,40 @@ extern int git_munmap(void *start, size_t length);
 #define on_disk_bytes(st) ((st).st_blocks * 512)
 #endif
 
+#ifdef NEEDS_MODE_TRANSLATION
+#undef S_IFMT
+#undef S_IFREG
+#undef S_IFDIR
+#undef S_IFLNK
+#undef S_IFBLK
+#undef S_IFCHR
+#undef S_IFIFO
+#undef S_IFSOCK
+#define S_IFMT   0170000
+#define S_IFREG  0100000
+#define S_IFDIR  0040000
+#define S_IFLNK  0120000
+#define S_IFBLK  0060000
+#define S_IFCHR  0020000
+#define S_IFIFO  0010000
+#define S_IFSOCK 0140000
+#ifdef stat
+#undef stat
+#endif
+#define stat(path, buf) git_stat(path, buf)
+extern int git_stat(const char *, struct stat *);
+#ifdef fstat
+#undef fstat
+#endif
+#define fstat(fd, buf) git_fstat(fd, buf)
+extern int git_fstat(int, struct stat *);
+#ifdef lstat
+#undef lstat
+#endif
+#define lstat(path, buf) git_lstat(path, buf)
+extern int git_lstat(const char *, struct stat *);
+#endif
+
 #define DEFAULT_PACKED_GIT_LIMIT \
        ((1024L * 1024L) * (sizeof(void*) >= 8 ? 8192 : 256))
 
index d4fb6dfe138fffd4d000c7d5aeb7787bea9970f4..2b11b1d6fe33cf3f61dd35b8f48d6953f7a25bff 100755 (executable)
@@ -94,3 +94,5 @@ else
                shift 7
        done
 fi
+
+exit 0
index 2b6635130a6c6e80cd8d188ae611bf220d25bc0a..fe61e89f31c44ca90dbfba468cf8b23d3993ba9f 100644 (file)
@@ -92,7 +92,7 @@ translate_merge_tool_path () {
 check_unchanged () {
        if test "$MERGED" -nt "$BACKUP"
        then
-               status=0
+               return 0
        else
                while true
                do
@@ -100,8 +100,8 @@ check_unchanged () {
                        printf "Was the merge successful? [y/n] "
                        read answer || return 1
                        case "$answer" in
-                       y*|Y*) status=0; break ;;
-                       n*|N*) status=1; break ;;
+                       y*|Y*) return 0 ;;
+                       n*|N*) return 1 ;;
                        esac
                done
        fi
@@ -119,8 +119,6 @@ setup_user_tool () {
 
        diff_cmd () {
                ( eval $merge_tool_cmd )
-               status=$?
-               return $status
        }
 
        merge_cmd () {
@@ -130,13 +128,10 @@ setup_user_tool () {
                then
                        touch "$BACKUP"
                        ( eval $merge_tool_cmd )
-                       status=$?
                        check_unchanged
                else
                        ( eval $merge_tool_cmd )
-                       status=$?
                fi
-               return $status
        }
 }
 
@@ -153,13 +148,11 @@ setup_tool () {
        }
 
        diff_cmd () {
-               status=1
-               return $status
+               return 1
        }
 
        merge_cmd () {
-               status=1
-               return $status
+               return 1
        }
 
        translate_merge_tool_path () {
@@ -210,7 +203,6 @@ run_merge_tool () {
 
        merge_tool_path=$(get_merge_tool_path "$1") || exit
        base_present="$2"
-       status=0
 
        # Bring tool-specific functions into scope
        setup_tool "$1" || return 1
@@ -221,8 +213,6 @@ run_merge_tool () {
        else
                run_diff_cmd "$1"
        fi
-       status=$?
-       return $status
 }
 
 # Run a either a configured or built-in diff tool
index ff050e58ff3b752113105ba3ea5e20c6b633aae9..d20581c15c5086b02411cab618cde0a9ff14e7ed 100755 (executable)
@@ -426,8 +426,6 @@ fi
 merge_keep_backup="$(git config --bool mergetool.keepBackup || echo true)"
 merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo false)"
 
-last_status=0
-rollup_status=0
 files=
 
 if test $# -eq 0
@@ -455,19 +453,15 @@ printf "%s\n" "$files"
 
 IFS='
 '
+rc=0
 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
+       if ! merge_file "$i"
        then
-               rollup_status=1
+               rc=1
+               prompt_after_failed_merge || exit 1
        fi
 done
 
-exit $rollup_status
+exit $rc
index b64dd28acf86e0b3075a638ae3419fb3a79a1815..c6a4629cbc2b69d3e6dfabe5e124384fe7fe611c 100644 (file)
@@ -1031,9 +1031,11 @@ test -s "$todo" || echo noop >> "$todo"
 test -n "$autosquash" && rearrange_squash "$todo"
 test -n "$cmd" && add_exec_commands "$todo"
 
+todocount=$(git stripspace --strip-comments <"$todo" | wc -l)
+
 cat >>"$todo" <<EOF
 
-$comment_char Rebase $shortrevisions onto $shortonto
+$comment_char Rebase $shortrevisions onto $shortonto ($todocount TODO item(s))
 EOF
 append_todo_help
 git stripspace --comment-lines >>"$todo" <<\EOF
index 9949db01e11959c81fae75fa018551601e6d5c3b..3092ab356c765cd593d2a988d020665c8b626ea1 100755 (executable)
@@ -54,10 +54,12 @@ sub usage {
     --[no-]bcc              <str>  * Email Bcc:
     --subject               <str>  * Email "Subject:"
     --in-reply-to           <str>  * Email "In-Reply-To:"
+    --[no-]xmailer                 * Add "X-Mailer:" header (default).
     --[no-]annotate                * Review each patch that will be sent in an editor.
     --compose                      * Open an editor for introduction.
     --compose-encoding      <str>  * Encoding to assume for introduction.
     --8bit-encoding         <str>  * Encoding to assume 8bit mails if undeclared
+    --transfer-encoding     <str>  * Transfer encoding to use (quoted-printable, 8bit, base64)
 
   Sending:
     --envelope-sender       <str>  * Email envelope sender.
@@ -145,10 +147,15 @@ sub format_2822_time {
 my $smtp;
 my $auth;
 
+# Regexes for RFC 2047 productions.
+my $re_token = qr/[^][()<>@,;:\\"\/?.= \000-\037\177-\377]+/;
+my $re_encoded_text = qr/[^? \000-\037\177-\377]+/;
+my $re_encoded_word = qr/=\?($re_token)\?($re_token)\?($re_encoded_text)\?=/;
+
 # Variables we fill in automatically, or via prompting:
 my (@to,$no_to,@initial_to,@cc,$no_cc,@initial_cc,@bcclist,$no_bcc,@xh,
        $initial_reply_to,$initial_subject,@files,
-       $author,$sender,$smtp_authpass,$annotate,$compose,$time);
+       $author,$sender,$smtp_authpass,$annotate,$use_xmailer,$compose,$time);
 
 my $envelope_sender;
 
@@ -206,6 +213,7 @@ sub do_edit {
 my (@suppress_cc);
 my ($auto_8bit_encoding);
 my ($compose_encoding);
+my ($target_xfer_encoding);
 
 my ($debug_net_smtp) = 0;              # Net::SMTP, see send_message()
 
@@ -219,7 +227,8 @@ sub do_edit {
     "signedoffcc" => [\$signed_off_by_cc, undef],      # Deprecated
     "validate" => [\$validate, 1],
     "multiedit" => [\$multiedit, undef],
-    "annotate" => [\$annotate, undef]
+    "annotate" => [\$annotate, undef],
+    "xmailer" => [\$use_xmailer, 1]
 );
 
 my %config_settings = (
@@ -242,6 +251,7 @@ sub do_edit {
     "from" => \$sender,
     "assume8bitencoding" => \$auto_8bit_encoding,
     "composeencoding" => \$compose_encoding,
+    "transferencoding" => \$target_xfer_encoding,
 );
 
 my %config_path_settings = (
@@ -314,10 +324,12 @@ sub signal_handler {
                    "envelope-sender=s" => \$envelope_sender,
                    "thread!" => \$thread,
                    "validate!" => \$validate,
+                   "transfer-encoding=s" => \$target_xfer_encoding,
                    "format-patch!" => \$format_patch,
                    "8bit-encoding=s" => \$auto_8bit_encoding,
                    "compose-encoding=s" => \$compose_encoding,
                    "force" => \$force,
+                   "xmailer!" => \$use_xmailer,
         );
 
 usage() if $help;
@@ -913,15 +925,26 @@ sub make_message_id {
 
 sub unquote_rfc2047 {
        local ($_) = @_;
-       my $encoding;
-       s{=\?([^?]+)\?q\?(.*?)\?=}{
-               $encoding = $1;
-               my $e = $2;
-               $e =~ s/_/ /g;
-               $e =~ s/=([0-9A-F]{2})/chr(hex($1))/eg;
-               $e;
+       my $charset;
+       my $sep = qr/[ \t]+/;
+       s{$re_encoded_word(?:$sep$re_encoded_word)*}{
+               my @words = split $sep, $&;
+               foreach (@words) {
+                       m/$re_encoded_word/;
+                       $charset = $1;
+                       my $encoding = $2;
+                       my $text = $3;
+                       if ($encoding eq 'q' || $encoding eq 'Q') {
+                               $_ = $text;
+                               s/_/ /g;
+                               s/=([0-9A-F]{2})/chr(hex($1))/egi;
+                       } else {
+                               # other encodings not supported yet
+                       }
+               }
+               join '', @words;
        }eg;
-       return wantarray ? ($_, $encoding) : $_;
+       return wantarray ? ($_, $charset) : $_;
 }
 
 sub quote_rfc2047 {
@@ -934,10 +957,8 @@ sub quote_rfc2047 {
 
 sub is_rfc2047_quoted {
        my $s = shift;
-       my $token = qr/[^][()<>@,;:"\/?.= \000-\037\177-\377]+/;
-       my $encoded_text = qr/[!->@-~]+/;
        length($s) <= 75 &&
-       $s =~ m/^(?:"[[:ascii:]]*"|=\?$token\?$token\?$encoded_text\?=)$/o;
+       $s =~ m/^(?:"[[:ascii:]]*"|$re_encoded_word)$/o;
 }
 
 sub subject_needs_rfc2047_quoting {
@@ -1163,8 +1184,10 @@ sub send_message {
 Subject: $subject
 Date: $date
 Message-Id: $message_id
-X-Mailer: git-send-email $gitversion
 ";
+       if ($use_xmailer) {
+               $header .= "X-Mailer: git-send-email $gitversion\n";
+       }
        if ($reply_to) {
 
                $header .= "In-Reply-To: $reply_to\n";
@@ -1324,6 +1347,8 @@ sub send_message {
        my $author_encoding;
        my $has_content_type;
        my $body_encoding;
+       my $xfer_encoding;
+       my $has_mime_version;
        @to = ();
        @cc = ();
        @xh = ();
@@ -1394,9 +1419,16 @@ sub send_message {
                                }
                                push @xh, $_;
                        }
+                       elsif (/^MIME-Version/i) {
+                               $has_mime_version = 1;
+                               push @xh, $_;
+                       }
                        elsif (/^Message-Id: (.*)/i) {
                                $message_id = $1;
                        }
+                       elsif (/^Content-Transfer-Encoding: (.*)/i) {
+                               $xfer_encoding = $1 if not defined $xfer_encoding;
+                       }
                        elsif (!/^Date:\s/i && /^[-A-Za-z]+:\s+\S/) {
                                push @xh, $_;
                        }
@@ -1444,10 +1476,9 @@ sub send_message {
                if defined $cc_cmd && !$suppress_cc{'cccmd'};
 
        if ($broken_encoding{$t} && !$has_content_type) {
+               $xfer_encoding = '8bit' if not defined $xfer_encoding;
                $has_content_type = 1;
-               push @xh, "MIME-Version: 1.0",
-                       "Content-Type: text/plain; charset=$auto_8bit_encoding",
-                       "Content-Transfer-Encoding: 8bit";
+               push @xh, "Content-Type: text/plain; charset=$auto_8bit_encoding";
                $body_encoding = $auto_8bit_encoding;
        }
 
@@ -1467,14 +1498,25 @@ sub send_message {
                                }
                        }
                        else {
+                               $xfer_encoding = '8bit' if not defined $xfer_encoding;
                                $has_content_type = 1;
                                push @xh,
-                                 'MIME-Version: 1.0',
-                                 "Content-Type: text/plain; charset=$author_encoding",
-                                 'Content-Transfer-Encoding: 8bit';
+                                 "Content-Type: text/plain; charset=$author_encoding";
                        }
                }
        }
+       if (defined $target_xfer_encoding) {
+               $xfer_encoding = '8bit' if not defined $xfer_encoding;
+               $message = apply_transfer_encoding(
+                       $message, $xfer_encoding, $target_xfer_encoding);
+               $xfer_encoding = $target_xfer_encoding;
+       }
+       if (defined $xfer_encoding) {
+               push @xh, "Content-Transfer-Encoding: $xfer_encoding";
+       }
+       if (defined $xfer_encoding or $has_content_type) {
+               unshift @xh, 'MIME-Version: 1.0' unless $has_mime_version;
+       }
 
        $needs_confirm = (
                $confirm eq "always" or
@@ -1543,6 +1585,32 @@ sub cleanup_compose_files {
 
 $smtp->quit if $smtp;
 
+sub apply_transfer_encoding {
+       my $message = shift;
+       my $from = shift;
+       my $to = shift;
+
+       return $message if ($from eq $to and $from ne '7bit');
+
+       require MIME::QuotedPrint;
+       require MIME::Base64;
+
+       $message = MIME::QuotedPrint::decode($message)
+               if ($from eq 'quoted-printable');
+       $message = MIME::Base64::decode($message)
+               if ($from eq 'base64');
+
+       die "cannot send message as 7bit"
+               if ($to eq '7bit' and $message =~ /[^[:ascii:]]/);
+       return $message
+               if ($to eq '7bit' or $to eq '8bit');
+       return MIME::QuotedPrint::encode($message, "\n", 0)
+               if ($to eq 'quoted-printable');
+       return MIME::Base64::encode($message, "\n")
+               if ($to eq 'base64');
+       die "invalid transfer encoding";
+}
+
 sub unique_email_list {
        my %seen;
        my @emails;
index d968760139b0e7b9219a1602a2e646a3ed398136..c42c6e6365090e22ec7892baa51b919f2898e956 100644 (file)
@@ -81,7 +81,7 @@ if test -n "$OPTIONS_SPEC"; then
                echo exit $?
        )"
 else
-       dashless=$(basename "$0" | sed -e 's/-/ /')
+       dashless=$(basename -- "$0" | sed -e 's/-/ /')
        usage() {
                die "usage: $dashless $USAGE"
        }
index b6e2186cef0fcddc7c7b82378b07941d9f671a92..60f8814cc52fdfea17be989228a56a951cc0e867 100755 (executable)
@@ -115,7 +115,7 @@ sub _req_svn {
        $_before, $_after,
        $_merge, $_strategy, $_preserve_merges, $_dry_run, $_parents, $_local,
        $_prefix, $_no_checkout, $_url, $_verbose,
-       $_commit_url, $_tag, $_merge_info, $_interactive);
+       $_commit_url, $_tag, $_merge_info, $_interactive, $_set_svn_props);
 
 # This is a refactoring artifact so Git::SVN can get at this git-svn switch.
 sub opt_prefix { return $_prefix || '' }
@@ -193,6 +193,7 @@ sub _req_svn {
                          'dry-run|n' => \$_dry_run,
                          'fetch-all|all' => \$_fetch_all,
                          'commit-url=s' => \$_commit_url,
+                         'set-svn-props=s' => \$_set_svn_props,
                          'revision|r=i' => \$_revision,
                          'no-rebase' => \$_no_rebase,
                          'mergeinfo=s' => \$_merge_info,
@@ -228,6 +229,9 @@ sub _req_svn {
         'propget' => [ \&cmd_propget,
                       'Print the value of a property on a file or directory',
                       { 'revision|r=i' => \$_revision } ],
+        'propset' => [ \&cmd_propset,
+                      'Set the value of a property on a file or directory - will be set on commit',
+                      {} ],
         'proplist' => [ \&cmd_proplist,
                       'List all properties of a file or directory',
                       { 'revision|r=i' => \$_revision } ],
@@ -1376,6 +1380,49 @@ sub cmd_propget {
        print $props->{$prop} . "\n";
 }
 
+# cmd_propset (PROPNAME, PROPVAL, PATH)
+# ------------------------
+# Adjust the SVN property PROPNAME to PROPVAL for PATH.
+sub cmd_propset {
+       my ($propname, $propval, $path) = @_;
+       $path = '.' if not defined $path;
+       $path = $cmd_dir_prefix . $path;
+       usage(1) if not defined $propname;
+       usage(1) if not defined $propval;
+       my $file = basename($path);
+       my $dn = dirname($path);
+       my $cur_props = Git::SVN::Editor::check_attr( "svn-properties", $path );
+       my @new_props;
+       if (!$cur_props || $cur_props eq "unset" || $cur_props eq "" || $cur_props eq "set") {
+               push @new_props, "$propname=$propval";
+       } else {
+               # TODO: handle combining properties better
+               my @props = split(/;/, $cur_props);
+               my $replaced_prop;
+               foreach my $prop (@props) {
+                       # Parse 'name=value' syntax and set the property.
+                       if ($prop =~ /([^=]+)=(.*)/) {
+                               my ($n,$v) = ($1,$2);
+                               if ($n eq $propname) {
+                                       $v = $propval;
+                                       $replaced_prop = 1;
+                               }
+                               push @new_props, "$n=$v";
+                       }
+               }
+               if (!$replaced_prop) {
+                       push @new_props, "$propname=$propval";
+               }
+       }
+       my $attrfile = "$dn/.gitattributes";
+       open my $attrfh, '>>', $attrfile or die "Can't open $attrfile: $!\n";
+       # TODO: don't simply append here if $file already has svn-properties
+       my $new_props = join(';', @new_props);
+       print $attrfh "$file svn-properties=$new_props\n" or
+               die "write to $attrfile: $!\n";
+       close $attrfh or die "close $attrfile: $!\n";
+}
+
 # cmd_proplist (PATH)
 # -------------------
 # Print the list of SVN properties for PATH.
diff --git a/git.c b/git.c
index 18fbf79430687a473e9306f2bb65abbaec161bb4..82d7a1cfee806001c2d8b81a9dc822a513c75451 100644 (file)
--- a/git.c
+++ b/git.c
@@ -487,15 +487,20 @@ static struct cmd_struct commands[] = {
        { "write-tree", cmd_write_tree, RUN_SETUP },
 };
 
-int is_builtin(const char *s)
+static struct cmd_struct *get_builtin(const char *s)
 {
        int i;
        for (i = 0; i < ARRAY_SIZE(commands); i++) {
-               struct cmd_struct *p = commands+i;
+               struct cmd_struct *p = commands + i;
                if (!strcmp(s, p->cmd))
-                       return 1;
+                       return p;
        }
-       return 0;
+       return NULL;
+}
+
+int is_builtin(const char *s)
+{
+       return !!get_builtin(s);
 }
 
 static void handle_builtin(int argc, const char **argv)
@@ -503,6 +508,7 @@ static void handle_builtin(int argc, const char **argv)
        const char *cmd = argv[0];
        int i;
        static const char ext[] = STRIP_EXTENSION;
+       struct cmd_struct *builtin;
 
        if (sizeof(ext) > 1) {
                i = strlen(argv[0]) - strlen(ext);
@@ -519,15 +525,12 @@ static void handle_builtin(int argc, const char **argv)
                argv[0] = cmd = "help";
        }
 
-       for (i = 0; i < ARRAY_SIZE(commands); i++) {
-               struct cmd_struct *p = commands+i;
-               if (strcmp(p->cmd, cmd))
-                       continue;
-               if (saved_environment && (p->option & NO_SETUP)) {
+       builtin = get_builtin(cmd);
+       if (builtin) {
+               if (saved_environment && (builtin->option & NO_SETUP))
                        restore_env();
-                       break;
-               }
-               exit(run_builtin(p, argc, argv));
+               else
+                       exit(run_builtin(builtin, argc, argv));
        }
 }
 
index 70bcc7a4e533bb04e8c515e8831a75ec93d2d066..4dfe4c25d76649e982858c69e6bc7ff1ec32f645 100644 (file)
 #include "credential.h"
 #include "exec_cmd.h"
 #include "run-command.h"
+#include "parse-options.h"
 #ifdef NO_OPENSSL
 typedef void *SSL;
 #endif
+#ifdef USE_CURL_FOR_IMAP_SEND
+#include "http.h"
+#endif
+
+static int verbosity;
+static int use_curl; /* strictly opt in */
 
-static const char imap_send_usage[] = "git imap-send < <mbox>";
+static const char * const imap_send_usage[] = { "git imap-send [-v] [-q] [--[no-]curl] < <mbox>", NULL };
+
+static struct option imap_send_options[] = {
+       OPT__VERBOSITY(&verbosity),
+       OPT_BOOL(0, "curl", &use_curl, "use libcurl to communicate with the IMAP server"),
+       OPT_END()
+};
 
 #undef DRV_OK
 #define DRV_OK          0
@@ -38,8 +51,6 @@ static const char imap_send_usage[] = "git imap-send < <mbox>";
 #define DRV_BOX_BAD     -2
 #define DRV_STORE_BAD   -3
 
-static int Verbose, Quiet;
-
 __attribute__((format (printf, 1, 2)))
 static void imap_info(const char *, ...);
 __attribute__((format (printf, 1, 2)))
@@ -418,7 +429,7 @@ static int buffer_gets(struct imap_buffer *b, char **s)
                        if (b->buf[b->offset + 1] == '\n') {
                                b->buf[b->offset] = 0;  /* terminate the string */
                                b->offset += 2; /* next line */
-                               if (Verbose)
+                               if (0 < verbosity)
                                        puts(*s);
                                return 0;
                        }
@@ -433,7 +444,7 @@ static void imap_info(const char *msg, ...)
 {
        va_list va;
 
-       if (!Quiet) {
+       if (0 <= verbosity) {
                va_start(va, msg);
                vprintf(msg, va);
                va_end(va);
@@ -445,7 +456,7 @@ static void imap_warn(const char *msg, ...)
 {
        va_list va;
 
-       if (Quiet < 2) {
+       if (-2 < verbosity) {
                va_start(va, msg);
                vfprintf(stderr, msg, va);
                va_end(va);
@@ -522,7 +533,7 @@ static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx,
                                  cmd->tag, cmd->cmd, cmd->cb.dlen,
                                  CAP(LITERALPLUS) ? "+" : "");
 
-       if (Verbose) {
+       if (0 < verbosity) {
                if (imap->num_in_progress)
                        printf("(%d in progress) ", imap->num_in_progress);
                if (!starts_with(cmd->cmd, "LOGIN"))
@@ -1338,26 +1349,166 @@ static void git_imap_config(void)
        git_config_get_string("imap.authmethod", &server.auth_method);
 }
 
-int main(int argc, char **argv)
+static int append_msgs_to_imap(struct imap_server_conf *server,
+                              struct strbuf* all_msgs, int total)
 {
-       struct strbuf all_msgs = STRBUF_INIT;
        struct strbuf msg = STRBUF_INIT;
        struct imap_store *ctx = NULL;
        int ofs = 0;
        int r;
-       int total, n = 0;
+       int n = 0;
+
+       ctx = imap_open_store(server, server->folder);
+       if (!ctx) {
+               fprintf(stderr, "failed to open store\n");
+               return 1;
+       }
+       ctx->name = server->folder;
+
+       fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
+       while (1) {
+               unsigned percent = n * 100 / total;
+
+               fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total);
+
+               if (!split_msg(all_msgs, &msg, &ofs))
+                       break;
+               if (server->use_html)
+                       wrap_in_html(&msg);
+               r = imap_store_msg(ctx, &msg);
+               if (r != DRV_OK)
+                       break;
+               n++;
+       }
+       fprintf(stderr, "\n");
+
+       imap_close_store(ctx);
+
+       return 0;
+}
+
+#ifdef USE_CURL_FOR_IMAP_SEND
+static CURL *setup_curl(struct imap_server_conf *srvc)
+{
+       CURL *curl;
+       struct strbuf path = STRBUF_INIT;
+
+       if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
+               die("curl_global_init failed");
+
+       curl = curl_easy_init();
+
+       if (!curl)
+               die("curl_easy_init failed");
+
+       curl_easy_setopt(curl, CURLOPT_USERNAME, server.user);
+       curl_easy_setopt(curl, CURLOPT_PASSWORD, server.pass);
+
+       strbuf_addstr(&path, server.host);
+       if (!path.len || path.buf[path.len - 1] != '/')
+               strbuf_addch(&path, '/');
+       strbuf_addstr(&path, server.folder);
+
+       curl_easy_setopt(curl, CURLOPT_URL, path.buf);
+       strbuf_release(&path);
+       curl_easy_setopt(curl, CURLOPT_PORT, server.port);
+
+       if (server.auth_method) {
+               struct strbuf auth = STRBUF_INIT;
+               strbuf_addstr(&auth, "AUTH=");
+               strbuf_addstr(&auth, server.auth_method);
+               curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, auth.buf);
+               strbuf_release(&auth);
+       }
+
+       if (server.use_ssl)
+               curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
+
+       curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, server.ssl_verify);
+       curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, server.ssl_verify);
+
+       curl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer);
+
+       curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
+
+       if (0 < verbosity)
+               curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+
+       return curl;
+}
+
+static int curl_append_msgs_to_imap(struct imap_server_conf *server,
+                                   struct strbuf* all_msgs, int total) {
+       int ofs = 0;
+       int n = 0;
+       struct buffer msgbuf = { STRBUF_INIT, 0 };
+       CURL *curl;
+       CURLcode res = CURLE_OK;
+
+       curl = setup_curl(server);
+       curl_easy_setopt(curl, CURLOPT_READDATA, &msgbuf);
+
+       fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
+       while (1) {
+               unsigned percent = n * 100 / total;
+               int prev_len;
+
+               fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total);
+
+               prev_len = msgbuf.buf.len;
+               if (!split_msg(all_msgs, &msgbuf.buf, &ofs))
+                       break;
+               if (server->use_html)
+                       wrap_in_html(&msgbuf.buf);
+               lf_to_crlf(&msgbuf.buf);
+
+               curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,
+                                (curl_off_t)(msgbuf.buf.len-prev_len));
+
+               res = curl_easy_perform(curl);
+
+               if(res != CURLE_OK) {
+                       fprintf(stderr, "curl_easy_perform() failed: %s\n",
+                                       curl_easy_strerror(res));
+                       break;
+               }
+
+               n++;
+       }
+       fprintf(stderr, "\n");
+
+       curl_easy_cleanup(curl);
+       curl_global_cleanup();
+
+       return 0;
+}
+#endif
+
+int main(int argc, char **argv)
+{
+       struct strbuf all_msgs = STRBUF_INIT;
+       int total;
        int nongit_ok;
 
        git_extract_argv0_path(argv[0]);
 
        git_setup_gettext();
 
-       if (argc != 1)
-               usage(imap_send_usage);
-
        setup_git_directory_gently(&nongit_ok);
        git_imap_config();
 
+       argc = parse_options(argc, (const char **)argv, "", imap_send_options, imap_send_usage, 0);
+
+       if (argc)
+               usage_with_options(imap_send_usage, imap_send_options);
+
+#ifndef USE_CURL_FOR_IMAP_SEND
+       if (use_curl) {
+               warning("--use-curl not supported in this build");
+               use_curl = 0;
+       }
+#endif
+
        if (!server.port)
                server.port = server.use_ssl ? 993 : 143;
 
@@ -1391,29 +1542,14 @@ int main(int argc, char **argv)
        }
 
        /* write it to the imap server */
-       ctx = imap_open_store(&server, server.folder);
-       if (!ctx) {
-               fprintf(stderr, "failed to open store\n");
-               return 1;
-       }
-
-       fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
-       while (1) {
-               unsigned percent = n * 100 / total;
 
-               fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total);
-               if (!split_msg(&all_msgs, &msg, &ofs))
-                       break;
-               if (server.use_html)
-                       wrap_in_html(&msg);
-               r = imap_store_msg(ctx, &msg);
-               if (r != DRV_OK)
-                       break;
-               n++;
-       }
-       fprintf(stderr, "\n");
+       if (server.tunnel)
+               return append_msgs_to_imap(&server, &all_msgs, total);
 
-       imap_close_store(ctx);
+#ifdef USE_CURL_FOR_IMAP_SEND
+       if (use_curl)
+               return curl_append_msgs_to_imap(&server, &all_msgs, total);
+#endif
 
-       return 0;
+       return append_msgs_to_imap(&server, &all_msgs, total);
 }
index 4f16ee78ce3dbc263a762a8800dfe9ddfcfaecd5..988927775169487df7677a17465b512a567488dd 100644 (file)
@@ -128,9 +128,17 @@ static int lock_file(struct lock_file *lk, const char *path, int flags)
                    path);
        }
 
-       strbuf_add(&lk->filename, path, pathlen);
-       if (!(flags & LOCK_NO_DEREF))
-               resolve_symlink(&lk->filename);
+       if (flags & LOCK_NO_DEREF) {
+               strbuf_add_absolute_path(&lk->filename, path);
+       } else {
+               struct strbuf resolved_path = STRBUF_INIT;
+
+               strbuf_add(&resolved_path, path, pathlen);
+               resolve_symlink(&resolved_path);
+               strbuf_add_absolute_path(&lk->filename, resolved_path.buf);
+               strbuf_release(&resolved_path);
+       }
+
        strbuf_addstr(&lk->filename, LOCK_SUFFIX);
        lk->fd = open(lk->filename.buf, O_RDWR | O_CREAT | O_EXCL, 0666);
        if (lk->fd < 0) {
index 81890a6680029ec1d369a7eef11a4ec112847fb7..9e9589730fa44c94d122dfdb50172baf95e2578d 100644 (file)
--- a/mailmap.c
+++ b/mailmap.c
@@ -71,22 +71,17 @@ static void add_mapping(struct string_list *map,
                        char *old_name, char *old_email)
 {
        struct mailmap_entry *me;
-       int index;
+       struct string_list_item *item;
 
        if (old_email == NULL) {
                old_email = new_email;
                new_email = NULL;
        }
 
-       if ((index = string_list_find_insert_index(map, old_email, 1)) < 0) {
-               /* mailmap entry exists, invert index value */
-               index = -1 - index;
-               me = (struct mailmap_entry *)map->items[index].util;
+       item = string_list_insert(map, old_email);
+       if (item->util) {
+               me = (struct mailmap_entry *)item->util;
        } else {
-               /* create mailmap entry */
-               struct string_list_item *item;
-
-               item = string_list_insert_at_index(map, index, old_email);
                me = xcalloc(1, sizeof(struct mailmap_entry));
                me->namemap.strdup_strings = 1;
                me->namemap.cmp = namemap_cmp;
@@ -94,8 +89,8 @@ static void add_mapping(struct string_list *map,
        }
 
        if (old_name == NULL) {
-               debug_mm("mailmap: adding (simple) entry for %s at index %d\n",
-                        old_email, index);
+               debug_mm("mailmap: adding (simple) entry for '%s'\n", old_email);
+
                /* Replace current name and new email for simple entry */
                if (new_name) {
                        free(me->name);
@@ -107,8 +102,7 @@ static void add_mapping(struct string_list *map,
                }
        } else {
                struct mailmap_info *mi = xcalloc(1, sizeof(struct mailmap_info));
-               debug_mm("mailmap: adding (complex) entry for %s at index %d\n",
-                        old_email, index);
+               debug_mm("mailmap: adding (complex) entry for '%s'\n", old_email);
                if (new_name)
                        mi->name = xstrdup(new_name);
                if (new_email)
index fdb7d0f10ba471bcdff26dc87851d7df34fdc971..771f5e21b09aac6976297b8a6e9028f90787a764 100644 (file)
@@ -275,23 +275,20 @@ struct tree *write_tree_from_memory(struct merge_options *o)
 }
 
 static int save_files_dirs(const unsigned char *sha1,
-               const char *base, int baselen, const char *path,
+               struct strbuf *base, const char *path,
                unsigned int mode, int stage, void *context)
 {
-       int len = strlen(path);
-       char *newpath = xmalloc(baselen + len + 1);
+       int baselen = base->len;
        struct merge_options *o = context;
 
-       memcpy(newpath, base, baselen);
-       memcpy(newpath + baselen, path, len);
-       newpath[baselen + len] = '\0';
+       strbuf_addstr(base, path);
 
        if (S_ISDIR(mode))
-               string_list_insert(&o->current_directory_set, newpath);
+               string_list_insert(&o->current_directory_set, base->buf);
        else
-               string_list_insert(&o->current_file_set, newpath);
-       free(newpath);
+               string_list_insert(&o->current_file_set, base->buf);
 
+       strbuf_setlen(base, baselen);
        return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
 }
 
@@ -1904,7 +1901,7 @@ int merge_recursive(struct merge_options *o,
        }
 
        if (!ca) {
-               ca = get_merge_bases(h1, h2, 1);
+               ca = get_merge_bases(h1, h2);
                ca = reverse_commit_list(ca);
        }
 
index 85ac7201571ed34c35a3613b97bd1b82982e0d61..f138cb4e731018b40426337eb8062f40512df088 100644 (file)
@@ -11,5 +11,4 @@ merge_cmd () {
                "$merge_tool_path" --merge \
                        --result="$MERGED" "$LOCAL" "$REMOTE"
        fi
-       status=$?
 }
index f96d9e550a138d395ccb23c9496111630d2de594..7b895fdb1f9955eb470a2614e0634bfcd26d90c9 100644 (file)
@@ -15,7 +15,6 @@ merge_cmd () {
                        "$LOCAL" "$REMOTE" \
                        "$(basename "$MERGED")"
        fi
-       status=$?
 }
 
 translate_merge_tool_path() {
index a30034f116fda6f90448aeb4ddd42063ea60aad1..793d1293b16c9b28a9ec5c70ec7fa0875ab0da54 100644 (file)
@@ -20,5 +20,4 @@ merge_cmd () {
                        -o "$MERGED" "$LOCAL" "$REMOTE" \
                >/dev/null 2>&1
        fi
-       status=$?
 }
index 7eb9d7a0103ad8447e4fde50976a5669a75d8cdd..109ff4ef410b77a814cca282f728f1b88948e4ec 100644 (file)
@@ -594,7 +594,7 @@ int notes_merge(struct notes_merge_options *o,
        assert(local && remote);
 
        /* Find merge bases */
-       bases = get_merge_bases(local, remote, 1);
+       bases = get_merge_bases(local, remote);
        if (!bases) {
                base_sha1 = null_sha1;
                base_tree_sha1 = EMPTY_TREE_SHA1_BIN;
index b64dc1b0219928ac149894c99a63dcc9fd419668..ccbf0737a34e466d39b2084c8a6d258b8235d8f6 100644 (file)
@@ -44,8 +44,7 @@ void commit_notes(struct notes_tree *t, const char *msg)
 
        /* Prepare commit message and reflog message */
        strbuf_addstr(&buf, msg);
-       if (buf.buf[buf.len - 1] != '\n')
-               strbuf_addch(&buf, '\n'); /* Make sure msg ends with newline */
+       strbuf_complete_line(&buf);
 
        create_notes_commit(t, NULL, buf.buf, buf.len, commit_sha1);
        strbuf_insert(&buf, 0, "notes: ", 7); /* commit message starts at index 7 */
diff --git a/notes.c b/notes.c
index 5fe691dbcdfb9e3f9fa3c768f243234d5bb2e816..c763a21eef5b64c984c22d18cd5f21c1bd32e5a3 100644 (file)
--- a/notes.c
+++ b/notes.c
@@ -902,7 +902,7 @@ int combine_notes_cat_sort_uniq(unsigned char *cur_sha1,
        if (string_list_add_note_lines(&sort_uniq_list, new_sha1))
                goto out;
        string_list_remove_empty_items(&sort_uniq_list, 0);
-       sort_string_list(&sort_uniq_list);
+       string_list_sort(&sort_uniq_list);
        string_list_remove_duplicates(&sort_uniq_list, 0);
 
        /* create a new blob object from sort_uniq_list */
@@ -1218,8 +1218,7 @@ static void format_note(struct notes_tree *t, const unsigned char *object_sha1,
        if (!sha1)
                return;
 
-       if (!(msg = read_sha1_file(sha1, &type, &msglen)) || !msglen ||
-                       type != OBJ_BLOB) {
+       if (!(msg = read_sha1_file(sha1, &type, &msglen)) || type != OBJ_BLOB) {
                free(msg);
                return;
        }
index 8029ae35619fbff7e9e595b20ea25c379c698016..c05d1386af7210e75a1012f3772745315ecc3592 100644 (file)
@@ -472,7 +472,6 @@ static void write_selected_commits_v1(struct sha1file *f,
 
        for (i = 0; i < writer.selected_nr; ++i) {
                struct bitmapped_commit *stored = &writer.selected[i];
-               struct bitmap_disk_entry on_disk;
 
                int commit_pos =
                        sha1_pos(stored->commit->object.sha1, index, index_nr, sha1_access);
@@ -480,11 +479,10 @@ static void write_selected_commits_v1(struct sha1file *f,
                if (commit_pos < 0)
                        die("BUG: trying to write commit not in index");
 
-               on_disk.object_pos = htonl(commit_pos);
-               on_disk.xor_offset = stored->xor_offset;
-               on_disk.flags = stored->flags;
+               sha1write_be32(f, commit_pos);
+               sha1write_u8(f, stored->xor_offset);
+               sha1write_u8(f, stored->flags);
 
-               sha1write(f, &on_disk, sizeof(on_disk));
                dump_bitmap(f, stored->write_as);
        }
 }
index a1f3c0d34f8958c08310aa9fc77e764885b76008..6a818419ca46f8d66adbeb0027da49e6bab1bfa3 100644 (file)
@@ -197,13 +197,24 @@ static struct stored_bitmap *store_bitmap(struct bitmap_index *index,
        return stored;
 }
 
+static inline uint32_t read_be32(const unsigned char *buffer, size_t *pos)
+{
+       uint32_t result = get_be32(buffer + *pos);
+       (*pos) += sizeof(result);
+       return result;
+}
+
+static inline uint8_t read_u8(const unsigned char *buffer, size_t *pos)
+{
+       return buffer[(*pos)++];
+}
+
 static int load_bitmap_entries_v1(struct bitmap_index *index)
 {
        static const size_t MAX_XOR_OFFSET = 160;
 
        uint32_t i;
        struct stored_bitmap **recent_bitmaps;
-       struct bitmap_disk_entry *entry;
 
        recent_bitmaps = xcalloc(MAX_XOR_OFFSET, sizeof(struct stored_bitmap));
 
@@ -214,15 +225,12 @@ static int load_bitmap_entries_v1(struct bitmap_index *index)
                uint32_t commit_idx_pos;
                const unsigned char *sha1;
 
-               entry = (struct bitmap_disk_entry *)(index->map + index->map_pos);
-               index->map_pos += sizeof(struct bitmap_disk_entry);
+               commit_idx_pos = read_be32(index->map, &index->map_pos);
+               xor_offset = read_u8(index->map, &index->map_pos);
+               flags = read_u8(index->map, &index->map_pos);
 
-               commit_idx_pos = ntohl(entry->object_pos);
                sha1 = nth_packed_object_sha1(index->pack, commit_idx_pos);
 
-               xor_offset = (int)entry->xor_offset;
-               flags = (int)entry->flags;
-
                bitmap = read_bitmap_1(index);
                if (!bitmap)
                        return -1;
index 8b7f4e9f0df2d50ffab1c0535d678c69fd7d6e94..487600b18c79be22c4c611fc4c3d29d817f1f304 100644 (file)
@@ -5,12 +5,6 @@
 #include "khash.h"
 #include "pack-objects.h"
 
-struct bitmap_disk_entry {
-       uint32_t object_pos;
-       uint8_t xor_offset;
-       uint8_t flags;
-} __attribute__((packed));
-
 struct bitmap_disk_header {
        char magic[4];
        uint16_t version;
index 34e8af966c4a97bd3fafd5d9cfecbfb982f78897..4088f13e723a51a6e1cee0c616a7c279a780461d 100644 (file)
@@ -288,6 +288,40 @@ sub apply_autoprops {
        }
 }
 
+sub check_attr {
+       my ($attr,$path) = @_;
+       my $val = command_oneline("check-attr", $attr, "--", $path);
+       if ($val) { $val =~ s/^[^:]*:\s*[^:]*:\s*(.*)\s*$/$1/; }
+       return $val;
+}
+
+sub apply_manualprops {
+       my ($self, $file, $fbat) = @_;
+       my $pending_properties = check_attr( "svn-properties", $file );
+       if ($pending_properties eq "") { return; }
+       # Parse the list of properties to set.
+       my @props = split(/;/, $pending_properties);
+       # TODO: get existing properties to compare to
+       # - this fails for add so currently not done
+       # my $existing_props = ::get_svnprops($file);
+       my $existing_props = {};
+       # TODO: caching svn properties or storing them in .gitattributes
+       # would make that faster
+       foreach my $prop (@props) {
+               # Parse 'name=value' syntax and set the property.
+               if ($prop =~ /([^=]+)=(.*)/) {
+                       my ($n,$v) = ($1,$2);
+                       for ($n, $v) {
+                               s/^\s+//; s/\s+$//;
+                       }
+                       my $existing = $existing_props->{$n};
+                       if (!defined($existing) || $existing ne $v) {
+                           $self->change_file_prop($fbat, $n, $v);
+                       }
+               }
+       }
+}
+
 sub A {
        my ($self, $m, $deletions) = @_;
        my ($dir, $file) = split_path($m->{file_b});
@@ -296,6 +330,7 @@ sub A {
                                        undef, -1);
        print "\tA\t$m->{file_b}\n" unless $::_q;
        $self->apply_autoprops($file, $fbat);
+       $self->apply_manualprops($m->{file_b}, $fbat);
        $self->chg_file($fbat, $m);
        $self->close_file($fbat,undef,$self->{pool});
 }
@@ -311,6 +346,7 @@ sub C {
        my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat,
                                $upa, $self->{r});
        print "\tC\t$m->{file_a} => $m->{file_b}\n" unless $::_q;
+       $self->apply_manualprops($m->{file_b}, $fbat);
        $self->chg_file($fbat, $m);
        $self->close_file($fbat,undef,$self->{pool});
 }
@@ -333,6 +369,7 @@ sub R {
                                $upa, $self->{r});
        print "\tR\t$m->{file_a} => $m->{file_b}\n" unless $::_q;
        $self->apply_autoprops($file, $fbat);
+       $self->apply_manualprops($m->{file_b}, $fbat);
        $self->chg_file($fbat, $m);
        $self->close_file($fbat,undef,$self->{pool});
 
@@ -348,6 +385,7 @@ sub M {
        my $fbat = $self->open_file($self->repo_path($m->{file_b}),
                                $pbat,$self->{r},$self->{pool});
        print "\t$m->{chg}\t$m->{file_b}\n" unless $::_q;
+       $self->apply_manualprops($m->{file_b}, $fbat);
        $self->chg_file($fbat, $m);
        $self->close_file($fbat,undef,$self->{pool});
 }
index 8bc89b1e0c0206647a8f5ee8da7727f304d14b2f..187a2293e7d9a36ba294fe775efcf2b87f4e9233 100644 (file)
@@ -64,44 +64,45 @@ void packet_buf_flush(struct strbuf *buf)
 }
 
 #define hex(a) (hexchar[(a) & 15])
-static char buffer[1000];
-static unsigned format_packet(const char *fmt, va_list args)
+static void format_packet(struct strbuf *out, const char *fmt, va_list args)
 {
        static char hexchar[] = "0123456789abcdef";
-       unsigned n;
+       size_t orig_len, n;
 
-       n = vsnprintf(buffer + 4, sizeof(buffer) - 4, fmt, args);
-       if (n >= sizeof(buffer)-4)
+       orig_len = out->len;
+       strbuf_addstr(out, "0000");
+       strbuf_vaddf(out, fmt, args);
+       n = out->len - orig_len;
+
+       if (n > LARGE_PACKET_MAX)
                die("protocol error: impossibly long line");
-       n += 4;
-       buffer[0] = hex(n >> 12);
-       buffer[1] = hex(n >> 8);
-       buffer[2] = hex(n >> 4);
-       buffer[3] = hex(n);
-       packet_trace(buffer+4, n-4, 1);
-       return n;
+
+       out->buf[orig_len + 0] = hex(n >> 12);
+       out->buf[orig_len + 1] = hex(n >> 8);
+       out->buf[orig_len + 2] = hex(n >> 4);
+       out->buf[orig_len + 3] = hex(n);
+       packet_trace(out->buf + orig_len + 4, n - 4, 1);
 }
 
 void packet_write(int fd, const char *fmt, ...)
 {
+       static struct strbuf buf = STRBUF_INIT;
        va_list args;
-       unsigned n;
 
+       strbuf_reset(&buf);
        va_start(args, fmt);
-       n = format_packet(fmt, args);
+       format_packet(&buf, fmt, args);
        va_end(args);
-       write_or_die(fd, buffer, n);
+       write_or_die(fd, buf.buf, buf.len);
 }
 
 void packet_buf_write(struct strbuf *buf, const char *fmt, ...)
 {
        va_list args;
-       unsigned n;
 
        va_start(args, fmt);
-       n = format_packet(fmt, args);
+       format_packet(buf, fmt, args);
        va_end(args);
-       strbuf_add(buf, buffer, n);
 }
 
 static int get_packet_data(int fd, char **src_buf, size_t *src_size,
index e5b4938efcf329eb4f25b6f90231c35abeacbbd3..8181eebbfcd0080540bc580416336436ced98297 100644 (file)
--- a/prompt.c
+++ b/prompt.c
@@ -57,11 +57,19 @@ char *git_prompt(const char *prompt, int flags)
                        r = do_askpass(askpass, prompt);
        }
 
-       if (!r)
-               r = git_terminal_prompt(prompt, flags & PROMPT_ECHO);
        if (!r) {
-               /* prompts already contain ": " at the end */
-               die("could not read %s%s", prompt, strerror(errno));
+               const char *err;
+
+               if (git_env_bool("GIT_TERMINAL_PROMPT", 1)) {
+                       r = git_terminal_prompt(prompt, flags & PROMPT_ECHO);
+                       err = strerror(errno);
+               } else {
+                       err = "terminal prompts disabled";
+               }
+               if (!r) {
+                       /* prompts already contain ": " at the end */
+                       die("could not read %s%s", prompt, err);
+               }
        }
        return r;
 }
diff --git a/quote.c b/quote.c
index 45e3db12d514dd7393539ca0aff09f5aa8467b8d..7920e18e44834f1f86c218c172ae10227858ed66 100644 (file)
--- a/quote.c
+++ b/quote.c
@@ -274,27 +274,6 @@ void write_name_quoted(const char *name, FILE *fp, int terminator)
        fputc(terminator, fp);
 }
 
-void write_name_quotedpfx(const char *pfx, size_t pfxlen,
-                         const char *name, FILE *fp, int terminator)
-{
-       int needquote = 0;
-
-       if (terminator) {
-               needquote = next_quote_pos(pfx, pfxlen) < pfxlen
-                       || name[next_quote_pos(name, -1)];
-       }
-       if (needquote) {
-               fputc('"', fp);
-               quote_c_style_counted(pfx, pfxlen, NULL, fp, 1);
-               quote_c_style(name, NULL, fp, 1);
-               fputc('"', fp);
-       } else {
-               fwrite(pfx, pfxlen, 1, fp);
-               fputs(name, fp);
-       }
-       fputc(terminator, fp);
-}
-
 void write_name_quoted_relative(const char *name, const char *prefix,
                                FILE *fp, int terminator)
 {
diff --git a/quote.h b/quote.h
index 71dcc3aa0279af6611f7471d1a4c9949b1dc49fb..99e04d34bf223a0147e65623322ef2c2fb01e01d 100644 (file)
--- a/quote.h
+++ b/quote.h
@@ -56,8 +56,6 @@ extern size_t quote_c_style(const char *name, struct strbuf *, FILE *, int no_dq
 extern void quote_two_c_style(struct strbuf *, const char *, const char *, int);
 
 extern void write_name_quoted(const char *name, FILE *, int terminator);
-extern void write_name_quotedpfx(const char *pfx, size_t pfxlen,
-                                 const char *name, FILE *, int terminator);
 extern void write_name_quoted_relative(const char *name, const char *prefix,
                FILE *fp, int terminator);
 
diff --git a/refs.c b/refs.c
index 5ff457ebfce7aba9cd470f3e2e1f3f5dbe9d9741..5fcacc6c41e6c7033367cc9c4cf7c18b33eea286 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1068,8 +1068,10 @@ static const char PACKED_REFS_HEADER[] =
  * Return a pointer to the refname within the line (null-terminated),
  * or NULL if there was a problem.
  */
-static const char *parse_ref_line(char *line, unsigned char *sha1)
+static const char *parse_ref_line(struct strbuf *line, unsigned char *sha1)
 {
+       const char *ref;
+
        /*
         * 42: the answer to everything.
         *
@@ -1078,22 +1080,23 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
         *  +1 (space in between hex and name)
         *  +1 (newline at the end of the line)
         */
-       int len = strlen(line) - 42;
-
-       if (len <= 0)
+       if (line->len <= 42)
                return NULL;
-       if (get_sha1_hex(line, sha1) < 0)
+
+       if (get_sha1_hex(line->buf, sha1) < 0)
                return NULL;
-       if (!isspace(line[40]))
+       if (!isspace(line->buf[40]))
                return NULL;
-       line += 41;
-       if (isspace(*line))
+
+       ref = line->buf + 41;
+       if (isspace(*ref))
                return NULL;
-       if (line[len] != '\n')
+
+       if (line->buf[line->len - 1] != '\n')
                return NULL;
-       line[len] = 0;
+       line->buf[--line->len] = 0;
 
-       return line;
+       return ref;
 }
 
 /*
@@ -1126,16 +1129,15 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
 static void read_packed_refs(FILE *f, struct ref_dir *dir)
 {
        struct ref_entry *last = NULL;
-       char refline[PATH_MAX];
+       struct strbuf line = STRBUF_INIT;
        enum { PEELED_NONE, PEELED_TAGS, PEELED_FULLY } peeled = PEELED_NONE;
 
-       while (fgets(refline, sizeof(refline), f)) {
+       while (strbuf_getwholeline(&line, f, '\n') != EOF) {
                unsigned char sha1[20];
                const char *refname;
-               static const char header[] = "# pack-refs with:";
+               const char *traits;
 
-               if (!strncmp(refline, header, sizeof(header)-1)) {
-                       const char *traits = refline + sizeof(header) - 1;
+               if (skip_prefix(line.buf, "# pack-refs with:", &traits)) {
                        if (strstr(traits, " fully-peeled "))
                                peeled = PEELED_FULLY;
                        else if (strstr(traits, " peeled "))
@@ -1144,7 +1146,7 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir)
                        continue;
                }
 
-               refname = parse_ref_line(refline, sha1);
+               refname = parse_ref_line(&line, sha1);
                if (refname) {
                        int flag = REF_ISPACKED;
 
@@ -1160,10 +1162,10 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir)
                        continue;
                }
                if (last &&
-                   refline[0] == '^' &&
-                   strlen(refline) == PEELED_LINE_LENGTH &&
-                   refline[PEELED_LINE_LENGTH - 1] == '\n' &&
-                   !get_sha1_hex(refline + 1, sha1)) {
+                   line.buf[0] == '^' &&
+                   line.len == PEELED_LINE_LENGTH &&
+                   line.buf[PEELED_LINE_LENGTH - 1] == '\n' &&
+                   !get_sha1_hex(line.buf + 1, sha1)) {
                        hashcpy(last->u.value.peeled, sha1);
                        /*
                         * Regardless of what the file header said,
@@ -1173,6 +1175,8 @@ static void read_packed_refs(FILE *f, struct ref_dir *dir)
                        last->flag |= REF_KNOWS_PEELED;
                }
        }
+
+       strbuf_release(&line);
 }
 
 /*
@@ -2318,6 +2322,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
 
        lock->lock_fd = hold_lock_file_for_update(lock->lk, ref_file, lflags);
        if (lock->lock_fd < 0) {
+               last_errno = errno;
                if (errno == ENOENT && --attempts_remaining > 0)
                        /*
                         * Maybe somebody just deleted one of the
@@ -2325,8 +2330,13 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
                         * again:
                         */
                        goto retry;
-               else
-                       unable_to_lock_die(ref_file, errno);
+               else {
+                       struct strbuf err = STRBUF_INIT;
+                       unable_to_lock_message(ref_file, errno, &err);
+                       error("%s", err.buf);
+                       strbuf_reset(&err);
+                       goto error_return;
+               }
        }
        return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock;
 
@@ -2639,22 +2649,25 @@ static int curate_packed_ref_fn(struct ref_entry *entry, void *cb_data)
        return 0;
 }
 
-int repack_without_refs(const char **refnames, int n, struct strbuf *err)
+int repack_without_refs(struct string_list *refnames, struct strbuf *err)
 {
        struct ref_dir *packed;
        struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
-       struct string_list_item *ref_to_delete;
-       int i, ret, removed = 0;
+       struct string_list_item *refname, *ref_to_delete;
+       int ret, needs_repacking = 0, removed = 0;
 
        assert(err);
 
        /* Look for a packed ref */
-       for (i = 0; i < n; i++)
-               if (get_packed_ref(refnames[i]))
+       for_each_string_list_item(refname, refnames) {
+               if (get_packed_ref(refname->string)) {
+                       needs_repacking = 1;
                        break;
+               }
+       }
 
        /* Avoid locking if we have nothing to do */
-       if (i == n)
+       if (!needs_repacking)
                return 0; /* no refname exists in packed refs */
 
        if (lock_packed_refs(0)) {
@@ -2664,8 +2677,8 @@ int repack_without_refs(const char **refnames, int n, struct strbuf *err)
        packed = get_packed_refs(&ref_cache);
 
        /* Remove refnames from the cache */
-       for (i = 0; i < n; i++)
-               if (remove_entry(packed, refnames[i]) != -1)
+       for_each_string_list_item(refname, refnames)
+               if (remove_entry(packed, refname->string) != -1)
                        removed = 1;
        if (!removed) {
                /*
@@ -3404,29 +3417,54 @@ int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, void
 
                        bp = find_beginning_of_line(buf, scanp);
 
-                       if (*bp != '\n') {
-                               strbuf_splice(&sb, 0, 0, buf, endp - buf);
-                               if (pos)
-                                       break; /* need to fill another block */
-                               scanp = buf - 1; /* leave loop */
-                       } else {
+                       if (*bp == '\n') {
                                /*
-                                * (bp + 1) thru endp is the beginning of the
-                                * current line we have in sb
+                                * The newline is the end of the previous line,
+                                * so we know we have complete line starting
+                                * at (bp + 1). Prefix it onto any prior data
+                                * we collected for the line and process it.
                                 */
                                strbuf_splice(&sb, 0, 0, bp + 1, endp - (bp + 1));
                                scanp = bp;
                                endp = bp + 1;
+                               ret = show_one_reflog_ent(&sb, fn, cb_data);
+                               strbuf_reset(&sb);
+                               if (ret)
+                                       break;
+                       } else if (!pos) {
+                               /*
+                                * We are at the start of the buffer, and the
+                                * start of the file; there is no previous
+                                * line, and we have everything for this one.
+                                * Process it, and we can end the loop.
+                                */
+                               strbuf_splice(&sb, 0, 0, buf, endp - buf);
+                               ret = show_one_reflog_ent(&sb, fn, cb_data);
+                               strbuf_reset(&sb);
+                               break;
                        }
-                       ret = show_one_reflog_ent(&sb, fn, cb_data);
-                       strbuf_reset(&sb);
-                       if (ret)
+
+                       if (bp == buf) {
+                               /*
+                                * We are at the start of the buffer, and there
+                                * is more file to read backwards. Which means
+                                * we are in the middle of a line. Note that we
+                                * may get here even if *bp was a newline; that
+                                * just means we are at the exact end of the
+                                * previous line, rather than some spot in the
+                                * middle.
+                                *
+                                * Save away what we have to be combined with
+                                * the data from the next read.
+                                */
+                               strbuf_splice(&sb, 0, 0, buf, endp - buf);
                                break;
+                       }
                }
 
        }
        if (!ret && sb.len)
-               ret = show_one_reflog_ent(&sb, fn, cb_data);
+               die("BUG: reverse reflog parser had leftover data");
 
        fclose(logfp);
        strbuf_release(&sb);
@@ -3738,10 +3776,11 @@ static int ref_update_reject_duplicates(struct ref_update **updates, int n,
 int ref_transaction_commit(struct ref_transaction *transaction,
                           struct strbuf *err)
 {
-       int ret = 0, delnum = 0, i;
-       const char **delnames;
+       int ret = 0, i;
        int n = transaction->nr;
        struct ref_update **updates = transaction->updates;
+       struct string_list refs_to_delete = STRING_LIST_INIT_NODUP;
+       struct string_list_item *ref_to_delete;
 
        assert(err);
 
@@ -3753,9 +3792,6 @@ int ref_transaction_commit(struct ref_transaction *transaction,
                return 0;
        }
 
-       /* Allocate work space */
-       delnames = xmalloc(sizeof(*delnames) * n);
-
        /* Copy, sort, and reject duplicate refs */
        qsort(updates, n, sizeof(*updates), ref_update_compare);
        if (ref_update_reject_duplicates(updates, n, err)) {
@@ -3815,16 +3851,17 @@ int ref_transaction_commit(struct ref_transaction *transaction,
                        }
 
                        if (!(update->flags & REF_ISPRUNING))
-                               delnames[delnum++] = update->lock->ref_name;
+                               string_list_append(&refs_to_delete,
+                                                  update->lock->ref_name);
                }
        }
 
-       if (repack_without_refs(delnames, delnum, err)) {
+       if (repack_without_refs(&refs_to_delete, err)) {
                ret = TRANSACTION_GENERIC_ERROR;
                goto cleanup;
        }
-       for (i = 0; i < delnum; i++)
-               unlink_or_warn(git_path("logs/%s", delnames[i]));
+       for_each_string_list_item(ref_to_delete, &refs_to_delete)
+               unlink_or_warn(git_path("logs/%s", ref_to_delete->string));
        clear_loose_ref_cache(&ref_cache);
 
 cleanup:
@@ -3833,7 +3870,7 @@ int ref_transaction_commit(struct ref_transaction *transaction,
        for (i = 0; i < n; i++)
                if (updates[i]->lock)
                        unlock_ref(updates[i]->lock);
-       free(delnames);
+       string_list_clear(&refs_to_delete, 0);
        return ret;
 }
 
diff --git a/refs.h b/refs.h
index 2bc3556874a7b1cbccb4cebf4e3dc2fa13cc780f..405c6572f1135d06b68b6f60543e67343b117227 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -163,7 +163,15 @@ extern void rollback_packed_refs(void);
  */
 int pack_refs(unsigned int flags);
 
-extern int repack_without_refs(const char **refnames, int n,
+/*
+ * Rewrite the packed-refs file, omitting any refs listed in
+ * 'refnames'. On error, packed-refs will be unchanged, the return
+ * value is nonzero, and a message about the error is written to the
+ * 'err' strbuf.
+ *
+ * The refs in 'refnames' needn't be sorted. `err` must not be NULL.
+ */
+extern int repack_without_refs(struct string_list *refnames,
                               struct strbuf *err);
 
 extern int ref_exists(const char *);
index f62421702f66bb9b8f64247dd339d01f2fbfb4c1..5b9c6931c1e66adb03f5d505aa8dd57169452eae 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -1356,7 +1356,7 @@ static void add_missing_tags(struct ref *src, struct ref **dst, struct ref ***ds
        }
        clear_commit_marks_many(sent_tips.nr, sent_tips.tip, TMP_MARK);
 
-       sort_string_list(&dst_tag);
+       string_list_sort(&dst_tag);
 
        /* Collect tags they do not have. */
        for (ref = src; ref; ref = ref->next) {
@@ -1421,7 +1421,7 @@ static void prepare_ref_index(struct string_list *ref_index, struct ref *ref)
        for ( ; ref; ref = ref->next)
                string_list_append_nodup(ref_index, ref->name)->util = ref;
 
-       sort_string_list(ref_index);
+       string_list_sort(ref_index);
 }
 
 /*
@@ -1631,6 +1631,27 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
        }
 }
 
+static void set_merge(struct branch *ret)
+{
+       char *ref;
+       unsigned char sha1[20];
+       int i;
+
+       ret->merge = xcalloc(ret->merge_nr, sizeof(*ret->merge));
+       for (i = 0; i < ret->merge_nr; i++) {
+               ret->merge[i] = xcalloc(1, sizeof(**ret->merge));
+               ret->merge[i]->src = xstrdup(ret->merge_name[i]);
+               if (!remote_find_tracking(ret->remote, ret->merge[i]) ||
+                   strcmp(ret->remote_name, "."))
+                       continue;
+               if (dwim_ref(ret->merge_name[i], strlen(ret->merge_name[i]),
+                            sha1, &ref) == 1)
+                       ret->merge[i]->dst = ref;
+               else
+                       ret->merge[i]->dst = xstrdup(ret->merge_name[i]);
+       }
+}
+
 struct branch *branch_get(const char *name)
 {
        struct branch *ret;
@@ -1642,17 +1663,8 @@ struct branch *branch_get(const char *name)
                ret = make_branch(name, 0);
        if (ret && ret->remote_name) {
                ret->remote = remote_get(ret->remote_name);
-               if (ret->merge_nr) {
-                       int i;
-                       ret->merge = xcalloc(ret->merge_nr, sizeof(*ret->merge));
-                       for (i = 0; i < ret->merge_nr; i++) {
-                               ret->merge[i] = xcalloc(1, sizeof(**ret->merge));
-                               ret->merge[i]->src = xstrdup(ret->merge_name[i]);
-                               if (remote_find_tracking(ret->remote, ret->merge[i])
-                                   && !strcmp(ret->remote_name, "."))
-                                       ret->merge[i]->dst = xstrdup(ret->merge_name[i]);
-                       }
-               }
+               if (ret->merge_nr)
+                       set_merge(ret);
        }
        return ret;
 }
@@ -2135,7 +2147,7 @@ struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fet
        info.ref_count = ref_count;
        for (ref = fetch_map; ref; ref = ref->next)
                string_list_append(&ref_names, ref->name);
-       sort_string_list(&ref_names);
+       string_list_sort(&ref_names);
        for_each_ref(get_stale_heads_cb, &info);
        string_list_clear(&ref_names, 0);
        return stale_refs;
index 75dda928ea6be1dacd2fbeba5c0ce207ea46dd25..14e0e0358cf19dc95a5509ec441335a70a277503 100644 (file)
@@ -1441,7 +1441,7 @@ static void prepare_show_merge(struct rev_info *revs)
        other = lookup_commit_or_die(sha1, "MERGE_HEAD");
        add_pending_object(revs, &head->object, "HEAD");
        add_pending_object(revs, &other->object, "MERGE_HEAD");
-       bases = get_merge_bases(head, other, 1);
+       bases = get_merge_bases(head, other);
        add_rev_cmdline_list(revs, bases, REV_CMD_MERGE_BASE, UNINTERESTING | BOTTOM);
        add_pending_commit_list(revs, bases, UNINTERESTING | BOTTOM);
        free_commit_list(bases);
@@ -1546,7 +1546,7 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi
                                     : lookup_commit_reference(b_obj->sha1));
                                if (!a || !b)
                                        goto missing;
-                               exclude = get_merge_bases(a, b, 1);
+                               exclude = get_merge_bases(a, b);
                                add_rev_cmdline_list(revs, exclude,
                                                     REV_CMD_MERGE_BASE,
                                                     flags_exclude);
index a47699966c59f708683e439bcd3296d5fce8acf5..0b432cc9713251b4d116bedf52ae1f51bd9d80cf 100644 (file)
@@ -833,20 +833,3 @@ int run_hook_le(const char *const *env, const char *name, ...)
 
        return ret;
 }
-
-int run_hook_with_custom_index(const char *index_file, const char *name, ...)
-{
-       const char *hook_env[3] =  { NULL };
-       char index[PATH_MAX];
-       va_list args;
-       int ret;
-
-       snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
-       hook_env[0] = index;
-
-       va_start(args, name);
-       ret = run_hook_ve(hook_env, name, args);
-       va_end(args);
-
-       return ret;
-}
index 2137315ee46f672d945e0d3e011a8cbfbd5582a7..d6868dc8c868a61fb1ccc6230f43048dd9838a24 100644 (file)
@@ -57,10 +57,6 @@ LAST_ARG_MUST_BE_NULL
 extern int run_hook_le(const char *const *env, const char *name, ...);
 extern int run_hook_ve(const char *const *env, const char *name, va_list args);
 
-LAST_ARG_MUST_BE_NULL
-__attribute__((deprecated))
-extern int run_hook_with_custom_index(const char *index_file, const char *name, ...);
-
 #define RUN_COMMAND_NO_STDIN 1
 #define RUN_GIT_CMD         2  /*If this is to be git sub-command */
 #define RUN_COMMAND_STDOUT_TO_STDERR 4
index a03d4fa2521fbc119a8d6b471b9e3c1046610b84..77a1266760718b8e5b029636409634e241981888 100644 (file)
@@ -267,6 +267,23 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from,
        return 0;
 }
 
+void append_conflicts_hint(struct strbuf *msgbuf)
+{
+       int i;
+
+       strbuf_addch(msgbuf, '\n');
+       strbuf_commented_addf(msgbuf, "Conflicts:\n");
+       for (i = 0; i < active_nr;) {
+               const struct cache_entry *ce = active_cache[i++];
+               if (ce_stage(ce)) {
+                       strbuf_commented_addf(msgbuf, "\t%s\n", ce->name);
+                       while (i < active_nr && !strcmp(ce->name,
+                                                       active_cache[i]->name))
+                               i++;
+               }
+       }
+}
+
 static int do_recursive_merge(struct commit *base, struct commit *next,
                              const char *base_label, const char *next_label,
                              unsigned char *head, struct strbuf *msgbuf,
@@ -307,21 +324,8 @@ static int do_recursive_merge(struct commit *base, struct commit *next,
        if (opts->signoff)
                append_signoff(msgbuf, 0, 0);
 
-       if (!clean) {
-               int i;
-               strbuf_addstr(msgbuf, "\nConflicts:\n");
-               for (i = 0; i < active_nr;) {
-                       const struct cache_entry *ce = active_cache[i++];
-                       if (ce_stage(ce)) {
-                               strbuf_addch(msgbuf, '\t');
-                               strbuf_addstr(msgbuf, ce->name);
-                               strbuf_addch(msgbuf, '\n');
-                               while (i < active_nr && !strcmp(ce->name,
-                                               active_cache[i]->name))
-                                       i++;
-                       }
-               }
-       }
+       if (!clean)
+               append_conflicts_hint(msgbuf);
 
        return !clean;
 }
index db43e9cf86dcc0914a674adca63303c44e2ccc24..5ed5cb1d97ced70a9ebffd1dad524a12e7f7810a 100644 (file)
@@ -53,5 +53,6 @@ int sequencer_pick_revisions(struct replay_opts *opts);
 extern const char sign_off_header[];
 
 void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag);
+void append_conflicts_hint(struct strbuf *msgbuf);
 
 #endif
index d7f1838c13f5a88448d0f2034347bfb6482b3edf..30995e61b38fbfd1733acc5c3c5866b61d9f09e1 100644 (file)
@@ -1198,7 +1198,7 @@ static void report_pack_garbage(struct string_list *list)
        if (!report_garbage)
                return;
 
-       sort_string_list(list);
+       string_list_sort(list);
 
        for (i = 0; i < list->nr; i++) {
                const char *path = list->items[i].string;
index 5b004f513b999b31b7968b22dde955c859704853..cf2a83b14381ae02e737e6135561aab401f1f7e8 100644 (file)
@@ -372,10 +372,10 @@ const char *find_unique_abbrev(const unsigned char *sha1, int len)
        int status, exists;
        static char hex[41];
 
-       exists = has_sha1_file(sha1);
        memcpy(hex, sha1_to_hex(sha1), 40);
        if (len == 40 || !len)
                return hex;
+       exists = has_sha1_file(sha1);
        while (len < 40) {
                unsigned char sha1_ret[20];
                status = get_short_sha1(hex, len, sha1_ret, GET_SHA1_QUIETLY);
@@ -993,7 +993,7 @@ int get_sha1_mb(const char *name, unsigned char *sha1)
        two = lookup_commit_reference_gently(sha1_tmp, 0);
        if (!two)
                return -1;
-       mbs = get_merge_bases(one, two, 1);
+       mbs = get_merge_bases(one, two);
        if (!mbs || mbs->next)
                st = -1;
        else {
index 0346e74a47d14ef13757cadfe2a0de778b5c4cc4..88cafd4a70b8179a4e911c18704fb4ab0f2a21f5 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -229,7 +229,8 @@ static void add_lines(struct strbuf *out,
                const char *next = memchr(buf, '\n', size);
                next = next ? (next + 1) : (buf + size);
 
-               prefix = (prefix2 && buf[0] == '\n') ? prefix2 : prefix1;
+               prefix = ((prefix2 && (buf[0] == '\n' || buf[0] == '\t'))
+                         ? prefix2 : prefix1);
                strbuf_addstr(out, prefix);
                strbuf_add(out, buf, next - buf);
                size -= next - buf;
index c5aa0765e8e0a044e9e84e43280d5964f232ef63..2a32a3f1f5d250d7ea2a1b4a65998eeddb44962e 100644 (file)
@@ -59,13 +59,7 @@ static int add_entry(int insert_at, struct string_list *list, const char *string
 
 struct string_list_item *string_list_insert(struct string_list *list, const char *string)
 {
-       return string_list_insert_at_index(list, -1, string);
-}
-
-struct string_list_item *string_list_insert_at_index(struct string_list *list,
-                                                    int insert_at, const char *string)
-{
-       int index = add_entry(insert_at, list, string);
+       int index = add_entry(-1, list, string);
 
        if (index < 0)
                index = -1 - index;
@@ -220,7 +214,7 @@ struct string_list_item *string_list_append(struct string_list *list,
 /* Yuck */
 static compare_strings_fn compare_for_qsort;
 
-/* Only call this from inside sort_string_list! */
+/* Only call this from inside string_list_sort! */
 static int cmp_items(const void *a, const void *b)
 {
        const struct string_list_item *one = a;
@@ -228,7 +222,7 @@ static int cmp_items(const void *a, const void *b)
        return compare_for_qsort(one->string, two->string);
 }
 
-void sort_string_list(struct string_list *list)
+void string_list_sort(struct string_list *list)
 {
        compare_for_qsort = list->cmp ? list->cmp : strcmp;
        qsort(list->items, list->nr, sizeof(*list->items), cmp_items);
index 494eb5d95de0e5e8d69705f7a6f4fe2efcb232ad..d3809a14172da5b1512b08fa411136821465659e 100644 (file)
@@ -55,9 +55,17 @@ void string_list_remove_empty_items(struct string_list *list, int free_util);
 int string_list_has_string(const struct string_list *list, const char *string);
 int string_list_find_insert_index(const struct string_list *list, const char *string,
                                  int negative_existing_index);
+/*
+ * Inserts the given string into the sorted list.
+ * If the string already exists, the list is not altered.
+ * Returns the string_list_item, the string is part of.
+ */
 struct string_list_item *string_list_insert(struct string_list *list, const char *string);
-struct string_list_item *string_list_insert_at_index(struct string_list *list,
-                                                    int insert_at, const char *string);
+
+/*
+ * Checks if the given string is part of a sorted list. If it is part of the list,
+ * return the coresponding string_list_item, NULL otherwise.
+ */
 struct string_list_item *string_list_lookup(struct string_list *list, const char *string);
 
 /*
@@ -85,7 +93,7 @@ struct string_list_item *string_list_append(struct string_list *list, const char
  */
 struct string_list_item *string_list_append_nodup(struct string_list *list, char *string);
 
-void sort_string_list(struct string_list *list);
+void string_list_sort(struct string_list *list);
 int unsorted_string_list_has_string(struct string_list *list, const char *string);
 struct string_list_item *unsorted_string_list_lookup(struct string_list *list,
                                                     const char *string);
index 0690dc50d07e9fd30242e41afe149476a34fc105..d37d400b2227c58f352795b9f6ede20a9cd54631 100644 (file)
@@ -301,7 +301,7 @@ static int prepare_submodule_summary(struct rev_info *rev, const char *path,
        left->object.flags |= SYMMETRIC_LEFT;
        add_pending_object(rev, &left->object, path);
        add_pending_object(rev, &right->object, path);
-       merge_bases = get_merge_bases(left, right, 1);
+       merge_bases = get_merge_bases(left, right);
        if (merge_bases) {
                if (merge_bases->item == left)
                        *fast_forward = 1;
index 9952261299e62c88d04954a2a8e738cd6a2adb30..d5bb0c9aa197661bf154d78858a79e60fa50fbaa 100644 (file)
--- a/t/README
+++ b/t/README
@@ -418,7 +418,8 @@ Don't:
    dies in an unexpected way (e.g. segfault).
 
    On the other hand, don't use test_must_fail for running regular
-   platform commands; just use '! cmd'.
+   platform commands; just use '! cmd'.  We are not in the business
+   of verifying that the world given to us sanely works.
 
  - use perl without spelling it as "$PERL_PATH". This is to help our
    friends on Windows where the platform Perl often adds CR before
index cd2baef383df7dbea5b1544a162f99573476520e..d88da29f77d23fe2f3efc86a15daf198dddbeb69 100755 (executable)
@@ -12,20 +12,39 @@ else
                say "Your version of gpg (1.0.6) is too buggy for testing"
                ;;
        *)
-               # key generation info: gpg --homedir t/lib-gpg --gen-key
-               # Type DSA and Elgamal, size 2048 bits, no expiration date.
-               # Name and email: C O Mitter <committer@example.com>
+               # Available key info:
+               # * Type DSA and Elgamal, size 2048 bits, no expiration date,
+               #   name and email: C O Mitter <committer@example.com>
+               # * Type RSA, size 2048 bits, no expiration date,
+               #   name and email: Eris Discordia <discord@example.net>
                # No password given, to enable non-interactive operation.
-               cp -R "$TEST_DIRECTORY"/lib-gpg ./gpghome
-               chmod 0700 gpghome
-               chmod 0600 gpghome/*
-               GNUPGHOME="$(pwd)/gpghome"
-               export GNUPGHOME
+               # To generate new key:
+               #       gpg --homedir /tmp/gpghome --gen-key
+               # To write armored exported key to keyring:
+               #       gpg --homedir /tmp/gpghome --export-secret-keys \
+               #               --armor 0xDEADBEEF >> lib-gpg/keyring.gpg
+               # To export ownertrust:
+               #       gpg --homedir /tmp/gpghome --export-ownertrust \
+               #               > lib-gpg/ownertrust
+               mkdir ./gpghome &&
+               chmod 0700 ./gpghome &&
+               GNUPGHOME="$(pwd)/gpghome" &&
+               export GNUPGHOME &&
+               gpg --homedir "${GNUPGHOME}" 2>/dev/null --import \
+                       "$TEST_DIRECTORY"/lib-gpg/keyring.gpg &&
+               gpg --homedir "${GNUPGHOME}" 2>/dev/null --import-ownertrust \
+                       "$TEST_DIRECTORY"/lib-gpg/ownertrust &&
                test_set_prereq GPG
                ;;
        esac
 fi
 
+if test_have_prereq GPG &&
+    echo | gpg --homedir "${GNUPGHOME}" -b --rfc1991 >/dev/null 2>&1
+then
+       test_set_prereq RFC1991
+fi
+
 sanitize_pgp() {
        perl -ne '
                /^-----END PGP/ and $in_pgp = 0;
diff --git a/t/lib-gpg/keyring.gpg b/t/lib-gpg/keyring.gpg
new file mode 100644 (file)
index 0000000..fb1f048
--- /dev/null
@@ -0,0 +1,88 @@
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1
+
+lQG7BEZnyykRBACzCPjIpTYNL7Y2tQqlEGTTDlvZcWNLjF5f7ZzuyOqNOidLUgFD
+36qch1LZLSZkShdR3Gae+bsolyjxrlFuFP0eXRPMtqK20aLw7WZvPFpEV1ThMne+
+PRJjYrvghWw3L0VVIAIZ8GXwrVBuU99uEjHEI0ojYloOvFc2jVPgSaoBvwCg48Tj
+fol2foSoJa7XUu9yAL8szg8D/RUsTzNF+I9hSRHl7MYKFMYoKEY9BDgrgAujp7YY
+8qdGsiUb0Ggyzp2kRjZFt4lpcvKhGfHn5GEjmtk+fRbD5qPfMqKFW+T0NPfYlYmL
+JJ4fs4qZ8Lx7x6iG6X51u+YNwsQuIGjMCC3CeNi3F7or651kkNYASbaQ1NROkCIN
+NudyA/0aasvoZUoNJAc2cP5Ifs6WhXMWLfMR2p2XbfKwKNYneec60usnSComcKqh
+sJVk0Gytvr3FOYVhRkXnKAbx+0W2urFP8OFVBTEKO6Ts2VygWGgneQYoHnqzwlUE
+yjOjlr+lyf7u2s/KAxpKA6jnttEdRZAmzWkhuox1wwAUkr27/QAAn3TEzKR1pxxR
++R3dHuFpnnfatMIDC5O0IkMgTyBNaXR0ZXIgPGNvbW1pdHRlckBleGFtcGxlLmNv
+bT6IXgQTEQIAHgUCRmfLKQIbAwYLCQgHAwIDFQIDAxYCAQIeAQIXgAAKCRATtvUe
+zd5DDXQdAKC92f+wOrTkbmPEf+u+qA/Gv6BxQwCfQ128JXCi3MpMB8tI2Kmo15tY
+gnmdAj0ERmfLThAIAM65eT9T6+gg0fJn+Qxhs3FFDPjxK6AOBS3SieWWmXO6stZZ
+plvb7r2+sXYp8HMHntnOX3TRPolIx1dsdkv3W3w8yUzf9Lmo2XMPsZ3/isWdEbOI
+A0rO3B1xwbQO7vEoWHeB7uyYIF6YsIH0pMqxkImciwB1tnJPB9OxqPHlD/HyyHr2
+voj6nmEGaPQWj8/dkfyenXm6XmNZUZL/slk6tRhNwv4cW3QQLh39nbiz9rqvZMKF
+XX8wkY4FdQkJjCGwqzG+7yJcyHvem29/iq//jRLZgdiN8BwV3MCTJyDp8/Wb/d9y
+jZcUm1RdtwRiwfhfQ+zmpyspm7OxINfH65rf7f8ABA0IALRiMRs/eOD59jrYXmPS
+ZQUbiALlbJJtuP2c9N3WZ5OgrhDiAW+SDIN+hgDynJ9b7C2dE3xNaud4zaXAAF44
+J4J0bAo2ZtZoJajw+GXwaZfh4Z7nPNHwEcbFD4/uXPCj9jPkcLOJqGmUY1aXdygo
+t3Hn5U/zo8JxPQ83YbJQhkzAOZ/HGowLNqKgGkLLHn1X9qay0CxlfTQeEN5RZyl3
+b4qRzGgGALFvoheyZIUw1TbjRpbn3kqlJooEQY02VwXFXfLI/LwzglilH6sSckvs
+0WHKLZ+0L6b3CgJHN2RsZ7QxwCBi1aemsvr65FeEXp/AYxaG5duUbsugG8PgoJ06
+bsEAAVQNQO3cXWpuiJ/nNLLnWuPunBKJUlurkBdf2GD+m+muF0VpwDchhqqbTO4e
+FqOISQQYEQIACQUCRmfLTgIbDAAKCRATtvUezd5DDcHsAKDQcoAtDWJFupVRqleB
+Cezx4Q2khACcCs+/LtE8Lb9hC+2cvr3uH5p82AI=
+=aEiU
+-----END PGP PRIVATE KEY BLOCK-----
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1
+
+lQOYBFFMlkcBCADJi/xnAF8yI34PHilSCbM7VtOFO17oFMkpu4cgN2QpPuM5MVjy
+cvrzKSguZFvPCDLzeAFJW1uPxL4SHaHSkisCrFhijH7OJWcOPNPSFCwu+inAoAsv
+Hm4ns6pfDZyRjVTHSY4rdMISqKFRozaXu8vHeBRzIhFnubBCepKZW07oKPnrnELV
+TVUSUVI+6el8JFmJIWxxLNLhfRRSPF0v4MDXPF//iCWiZDI+J1pLvQ5V/f7YtfsD
+GV0oPY66J72BFJG555eKBttnNY901LmI3ocn5P5iVnXDaqMElw7FKpnANXucgY3H
+4kLyNkI3s3J0CGbXI7b3MBWtjctuhWv1q2G5ABEBAAEAB/wLiuza/qEfv1Cfj7FQ
+ytAXpz1YoAcrcM/53TeRQhrbvIee5ZNGhLdCkyot81QeuJrSaXO0E9CxRynrjQQ7
+ibYqN7Hy0uu1kAbQQJjmVdQXTKnKJ7Wm7oM4hYhNsVCKNXc+1+5AfDYGg4nZob36
+qqgHtc+Ardl5VfUg7uF+eZrnSMynjZANgikKbPtE09DKVtVOtUE4xTD9ijkpgn65
+glsZDqb7J4QVgTeEiCDKJsQvin3SwrPBqBxBRULF2TIaMbOwe6dHiiaI85rsvAWS
+VGzonUB3IU1470P2SDIVczbXYUK/nDSGx6ZZ0wLu9ZcCyUPvxVEykuh2P4UWHla+
+nHLRBADMLavcfjsCI5CRUsdurYpgE8Y3bEbcDpvzAu5jT5D25p3YPDODOXD3AKTt
+PzVMARVtv8twkbgAyWaoDevJz8OtmoSwsWjdFo4YvsYw9jV7Yf3GwzD3Ya1ZnW32
+JWQr6cX8qcK0AukAD7UZkVyhU2KBvB02t8lKHLbScHXTYVqrywQA/LNUXwmHji+6
+osnSQAC8X9ggMOEs9dGo7Qlk4JgfGAH17CFI3S3ubsaVEdxz3YwzOkD8SNmEbLyW
+a7CZ/RnpdAZU0nB7kSfbfZl7ajhPbgKBMsaV2yvaDdJeor4m5eKdXffRk0SksxjL
+Z/4P1tTIuL8WzetGB/aDcWDFgseSAAsEALzmf579ptlSmDyGRAKQqub+mj4V3EUZ
+1GVGcfBY86w3BZVDsaRiCtcNjk/lcP4AZ1Vbb42RM6jk8nLsENRc7rf2xa7ZPf0T
+6n5F6W+vk7EG76RoFhKVtGZngGKiDGVavxk3FT/yf8lKrT3wYiT03SZDuZ0pWvku
+FiJGEyesAC8WRz60JEVyaXMgRGlzY29yZGlhIDxkaXNjb3JkQGV4YW1wbGUubmV0
+PokBOAQTAQIAIgUCUUyWRwIbAwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQ
+YQkuhbcicYlYowf7B+f+FDcLVfw8XzGlKku1F6PI1yGCt7AMO2/JkmO4LlgHuIgF
+pqe5b/XjKl0IsRcbVLitqiIokc8u+7H8yYU67DDliq7t1gqBy+qThSHcgn6WMKTa
+qCqOE2jzHyqulIAzQsJQ+c5SRofEZAKT4Qa2Dy+nsqWDpIE78aJd0Vnkk9U6H2Vu
+ABvUeN/IMgvxPr525o+rBD7LU4J3CtOzfV+sO6+33da+Bm9UhkR4tC4H/n1dDN1J
+YuxBQbgxTq/h8mKe4/7/Yvy+5WsYd96ZRLE2ZFWeWXtKkwmYbQ42G3SZUXaZ8R8O
+tbTyUrjbFKipO4wvXwhyju1l9cxAsrca6xbSCJ0DmARRTJZHAQgAqTtPFcTXqM+U
+o7bOoo+dcHi8XDf/8XSEmZfMKc/U5pSTBk7h1gSKuGzjF2n3wQm6A8+101vTLaQ6
+PoFDFW8uQB00mjymGrRDYFgz8bjhnaekZnA4XThr1ROjffgMhs3uTpCebdV+lL8K
+0oJTHc39TPLTg23DFcRSDN+3ARJJS7+CRBIbt9L5gObpgA4HUap/o6N7O04rQOPU
+83MAqnwo2JTO/Ded0zoad0Vo31Nmk4F+KvEE52ftGHbd7yqIUGKBt2SeTAh850ac
+LeNZP+V1Y7atBCr7/zm+JpHWq9OH7/NomlEIkxL8WDt8GfAKoqZgqefL+ACEnLbA
+t1du3f0FswARAQABAAf8DclaIQDfPM5kYo3y+YVPoykC11RskmQWpVibdlCLHJm/
+/ISSm1fVYT7lpTOpzl0XfVX/jw9s/cviPtNS/r0G/Iwki+gi9Av5bTDiUm/oWWqd
+1waPYPDGwB4QdKOviY/fOSFI9tOsszt5Czs4wDXWy90AZDWd7fkHYisbgofV1sjK
+Q8bYQPabcepcZ2JyET+EpZBEmUHHqQ76bTiqjN+Vz6k1OFlsEBzGkE+WIakAhkQ2
+57oUrRgFe+h6Ch7meB/v6vVfIRSsLpZe183uc4SigqtfsgjbG9PqOcAJOqovDncB
+Scg3qvpWFOAkTA3Re+yBPUd2HHl9WF/TPa2kBDCT2QQAxcJZeUCuUgDgCizqEgfs
+Kzm6dy4G/OJdW0q9m9psHqD1XWLd7ZLE4+eTS1cxktJiGcGNdGoZD0EtgxkV09uM
+12QYCOBErFJzv4/4oledHeEhTaRR/mFFGRp+kWTz2Ai/zNqUd3D++DYUe8g4mVQJ
+6JP014XhvoRnaCfT8cH9Zd0EANsSL70WGdifcVoWKA9jFJhahc0sSG6IZvMOc7bs
+cSbhBqLEnheObkarBP+A+zgllqIf+sbCassMXjcV52mnl9th3J5RWr7scrQLJ9ZX
+Ivz3uoP85vwlUI98dI9roYK0OpKmG4hNFppAcgiCVNVjnQlhuQ/HoexRHxRmnmcb
+38jPA/sEHPCFbLCGOSB+HQNKx/5Wf6VpFX/4oBNbIUiYoxcRl0jpYT7Lc0zbc8So
+HthjPfWhXhKzYvEDC5YgASEy1cNbGMUJcGyuAInwIQjq44FSwRMkI3ISSHnbv1iH
+0wBVJUzpluMebEAesdZUz1DcZWVf6eVJD0dhZxD6DoG7Xj1m9ThUiQEfBBgBAgAJ
+BQJRTJZHAhsMAAoJEGEJLoW3InGJ7HEIAMXkMf4cOWmnAuvvcSm3KpLghuWik9dy
+fn1sY/IG5atoKK+ypmV/TlBlMZqFQzuPIJQT8VLbmxtLlDhJG04LbI6c8axIZxOO
+ZKLy5nTTSy16ztqEeS7eifHLPZg1UFFyEEIQ1XW0CNDAeuWKh90ERjyl4Cg7PnWS
+Z9Ei+zj6JD5Pcdi3BJhQo9WOLOVEJ0NHmewTYqk9QVXH/0v1Hdl4LMJtgcbdbDWk
+4UTkXbg9pn3umCgkNJ3Vs8fWnIWO9Izdr2/wrFY2JvUT7Yvl+wsNIWatvOEzGy7n
+BOW78WUxzhu0YJTLKy+iKCjg5HS5dx6OC+e4aEEgfhNPCMkbvDsJjtQ=
+=hieJ
+-----END PGP PRIVATE KEY BLOCK-----
diff --git a/t/lib-gpg/ownertrust b/t/lib-gpg/ownertrust
new file mode 100644 (file)
index 0000000..b3e3c4f
--- /dev/null
@@ -0,0 +1,4 @@
+# List of assigned trustvalues, created Thu 11 Dec 2014 01:26:28 PM CET
+# (Use "gpg --import-ownertrust" to restore them)
+73D758744BE721698EC54E8713B6F51ECDDE430D:6:
+D4BE22311AD3131E5EDA29A461092E85B7227189:3:
diff --git a/t/lib-gpg/pubring.gpg b/t/lib-gpg/pubring.gpg
deleted file mode 100644 (file)
index 1a3c2d4..0000000
Binary files a/t/lib-gpg/pubring.gpg and /dev/null differ
diff --git a/t/lib-gpg/random_seed b/t/lib-gpg/random_seed
deleted file mode 100644 (file)
index 95d249f..0000000
Binary files a/t/lib-gpg/random_seed and /dev/null differ
diff --git a/t/lib-gpg/secring.gpg b/t/lib-gpg/secring.gpg
deleted file mode 100644 (file)
index 82dca8f..0000000
Binary files a/t/lib-gpg/secring.gpg and /dev/null differ
diff --git a/t/lib-gpg/trustdb.gpg b/t/lib-gpg/trustdb.gpg
deleted file mode 100644 (file)
index 4879ae9..0000000
Binary files a/t/lib-gpg/trustdb.gpg and /dev/null differ
index 7713dd260948c0fca0c0633b6c2cc152f7bc1361..03a4c2ee842e51e13b14774f1f86a4e7b22ae10c 100644 (file)
@@ -69,6 +69,7 @@ LockFile accept.lock
 PassEnv GIT_VALGRIND
 PassEnv GIT_VALGRIND_OPTIONS
 PassEnv GNUPGHOME
+PassEnv ASAN_OPTIONS
 
 Alias /dumb/ www/
 Alias /auth/dumb/ www/auth/dumb/
index e53cf6d36d573c3d758f0005c95aa4a364df82b1..fac0986134fefa5c61763f4c56873da8ba28072a 100755 (executable)
@@ -82,4 +82,7 @@ check_approxidate 'Jun 6, 5AM' '2009-06-06 05:00:00'
 check_approxidate '5AM Jun 6' '2009-06-06 05:00:00'
 check_approxidate '6AM, June 7, 2009' '2009-06-07 06:00:00'
 
+check_approxidate '2008-12-01' '2008-12-01 19:20:00'
+check_approxidate '2009-12-01' '2009-12-01 19:20:00'
+
 test_done
index 2a4a6c1226f7cf315510f8bd84b5d6fb8045ee5d..452320df8391580fbc1d7112c45e1758691a0c16 100755 (executable)
@@ -55,16 +55,41 @@ create_gitattributes () {
        esac
 }
 
+check_warning () {
+       case "$1" in
+       LF_CRLF) grep "LF will be replaced by CRLF" $2;;
+       CRLF_LF) grep "CRLF will be replaced by LF" $2;;
+       '')
+               >expect
+               grep "will be replaced by" $2 >actual
+               test_cmp expect actual
+               ;;
+       *) false ;;
+       esac
+}
+
 create_file_in_repo () {
        crlf=$1
        attr=$2
+       lfname=$3
+       crlfname=$4
+       lfmixcrlf=$5
+       lfmixcr=$6
+       crlfnul=$7
        create_gitattributes "$attr" &&
+       pfx=crlf_${crlf}_attr_${attr}
        for f in LF CRLF LF_mix_CR CRLF_mix_LF CRLF_nul
        do
-               pfx=crlf_${crlf}_attr_${attr}_$f.txt &&
-               cp $f $pfx && git -c core.autocrlf=$crlf add $pfx
+               fname=${pfx}_$f.txt &&
+               cp $f $fname &&
+               git -c core.autocrlf=$crlf add $fname 2>"${pfx}_$f.err"
        done &&
-       git commit -m "core.autocrlf $crlf"
+       git commit -m "core.autocrlf $crlf" &&
+       check_warning "$lfname" ${pfx}_LF.err &&
+       check_warning "$crlfname" ${pfx}_CRLF.err &&
+       check_warning "$lfmixcrlf" ${pfx}_CRLF_mix_LF.err &&
+       check_warning "$lfmixcr" ${pfx}_LF_mix_CR.err &&
+       check_warning "$crlfnul" ${pfx}_CRLF_nul.err
 }
 
 check_files_in_repo () {
@@ -140,22 +165,47 @@ test_expect_success 'setup master' '
 '
 
 
-test_expect_success 'create files' '
-       create_file_in_repo false "" &&
-       create_file_in_repo true  "" &&
-       create_file_in_repo input "" &&
 
-       create_file_in_repo false "auto" &&
-       create_file_in_repo true  "auto" &&
-       create_file_in_repo input "auto" &&
+warn_LF_CRLF="LF will be replaced by CRLF"
+warn_CRLF_LF="CRLF will be replaced by LF"
+
+test_expect_success 'add files empty attr' '
+       create_file_in_repo false ""     ""        ""        ""        ""        "" &&
+       create_file_in_repo true  ""     "LF_CRLF" ""        "LF_CRLF" ""        "" &&
+       create_file_in_repo input ""     ""        "CRLF_LF" "CRLF_LF" ""        ""
+'
+
+test_expect_success 'add files attr=auto' '
+       create_file_in_repo false "auto" ""        "CRLF_LF" "CRLF_LF" ""        "" &&
+       create_file_in_repo true  "auto" "LF_CRLF" ""        "LF_CRLF" ""        "" &&
+       create_file_in_repo input "auto" ""        "CRLF_LF" "CRLF_LF" ""        ""
+'
+
+test_expect_success 'add files attr=text' '
+       create_file_in_repo false "text" ""        "CRLF_LF" "CRLF_LF" ""        "CRLF_LF" &&
+       create_file_in_repo true  "text" "LF_CRLF" ""        "LF_CRLF" "LF_CRLF" ""        &&
+       create_file_in_repo input "text" ""        "CRLF_LF" "CRLF_LF" ""        "CRLF_LF"
+'
+
+test_expect_success 'add files attr=-text' '
+       create_file_in_repo false "-text" ""       ""        ""        ""        "" &&
+       create_file_in_repo true  "-text" ""       ""        ""        ""        "" &&
+       create_file_in_repo input "-text" ""       ""        ""        ""        ""
+'
+
+test_expect_success 'add files attr=lf' '
+       create_file_in_repo false "lf"    ""       "CRLF_LF" "CRLF_LF"  ""       "CRLF_LF" &&
+       create_file_in_repo true  "lf"    ""       "CRLF_LF" "CRLF_LF"  ""       "CRLF_LF" &&
+       create_file_in_repo input "lf"    ""       "CRLF_LF" "CRLF_LF"  ""       "CRLF_LF"
+'
 
-       create_file_in_repo false "text" &&
-       create_file_in_repo true  "text" &&
-       create_file_in_repo input "text" &&
+test_expect_success 'add files attr=crlf' '
+       create_file_in_repo false "crlf" "LF_CRLF" ""        "LF_CRLF" "LF_CRLF" "" &&
+       create_file_in_repo true  "crlf" "LF_CRLF" ""        "LF_CRLF" "LF_CRLF" "" &&
+       create_file_in_repo input "crlf" "LF_CRLF" ""        "LF_CRLF" "LF_CRLF" ""
+'
 
-       create_file_in_repo false "-text" &&
-       create_file_in_repo true  "-text" &&
-       create_file_in_repo input "-text" &&
+test_expect_success 'create files cleanup' '
        rm -f *.txt &&
        git reset --hard
 '
index 0333dd9875af9fbbad04cf05eb9f0e9fe37ae182..29e91d861cbd6473d80c7343a0e292b010d83173 100755 (executable)
@@ -432,4 +432,10 @@ test_expect_success '-c with changed comment char' '
        test_cmp expect actual
 '
 
+test_expect_success 'avoid SP-HT sequence in commented line' '
+       printf "#\tone\n#\n# two\n" >expect &&
+       printf "\tone\n\ntwo\n" | git stripspace -c >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 6b3cedcf24613b9c72c67b02c0b731db67055a26..988c3925d5e68be461b252675413671617e88809 100755 (executable)
@@ -64,7 +64,7 @@ test_expect_success "setup case tests" '
        git checkout -f master
 '
 
-$test_case 'rename (case change)' '
+test_expect_success 'rename (case change)' '
        git mv camelcase CamelCase &&
        git commit -m "rename"
 '
index 067f4c6e52abe86e952367d8cf576a80aa5139bd..601d02d71f735b4247528cc45b0ea055299ee7a0 100755 (executable)
@@ -22,7 +22,7 @@ generate_expected_cache_tree_rec () {
        # ls-files might have foo/bar, foo/bar/baz, and foo/bar/quux
        # We want to count only foo because it's the only direct child
        subtrees=$(git ls-files|grep /|cut -d / -f 1|uniq) &&
-       subtree_count=$(echo "$subtrees"|awk -v c=0 '$1 {++c} END {print c}') &&
+       subtree_count=$(echo "$subtrees"|awk -v c=0 '$1 != "" {++c} END {print c}') &&
        entries=$(git ls-files|wc -l) &&
        printf "SHA $dir (%d entries, %d subtrees)\n" "$entries" "$subtree_count" &&
        for subtree in $subtrees
index 57ea5a10c5c716f52a8c8c7335ac7f68fe9dd92d..d7ef44b4a261a588874df3b8359d809655286a43 100755 (executable)
@@ -289,4 +289,13 @@ test_expect_success 'http paths can be part of context' '
        EOF
 '
 
+test_expect_success 'helpers can abort the process' '
+       test_must_fail git \
+               -c credential.helper="!f() { echo quit=1; }; f" \
+               -c credential.helper="verbatim foo bar" \
+               credential fill >stdout &&
+       >expect &&
+       test_cmp expect stdout
+'
+
 test_done
index 7b4707b776f493ad4b2df9877926dd420e94ca81..6805b9e6bb5b7e6a6b6b9546e96023ebeb557bd0 100755 (executable)
@@ -619,6 +619,52 @@ test_expect_success 'stdin update/create/verify combination works' '
        test_must_fail git rev-parse --verify -q $c
 '
 
+test_expect_success 'stdin verify succeeds for correct value' '
+       git rev-parse $m >expect &&
+       echo "verify $m $m" >stdin &&
+       git update-ref --stdin <stdin &&
+       git rev-parse $m >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin verify succeeds for missing reference' '
+       echo "verify refs/heads/missing $Z" >stdin &&
+       git update-ref --stdin <stdin &&
+       test_must_fail git rev-parse --verify -q refs/heads/missing
+'
+
+test_expect_success 'stdin verify treats no value as missing' '
+       echo "verify refs/heads/missing" >stdin &&
+       git update-ref --stdin <stdin &&
+       test_must_fail git rev-parse --verify -q refs/heads/missing
+'
+
+test_expect_success 'stdin verify fails for wrong value' '
+       git rev-parse $m >expect &&
+       echo "verify $m $m~1" >stdin &&
+       test_must_fail git update-ref --stdin <stdin &&
+       git rev-parse $m >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin verify fails for mistaken null value' '
+       git rev-parse $m >expect &&
+       echo "verify $m $Z" >stdin &&
+       test_must_fail git update-ref --stdin <stdin &&
+       git rev-parse $m >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin verify fails for mistaken empty value' '
+       M=$(git rev-parse $m) &&
+       test_when_finished "git update-ref $m $M" &&
+       git rev-parse $m >expect &&
+       echo "verify $m" >stdin &&
+       test_must_fail git update-ref --stdin <stdin &&
+       git rev-parse $m >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'stdin update refs works with identity updates' '
        cat >stdin <<-EOF &&
        update $a $m $m
@@ -938,6 +984,52 @@ test_expect_success 'stdin -z update/create/verify combination works' '
        test_must_fail git rev-parse --verify -q $c
 '
 
+test_expect_success 'stdin -z verify succeeds for correct value' '
+       git rev-parse $m >expect &&
+       printf $F "verify $m" "$m" >stdin &&
+       git update-ref -z --stdin <stdin &&
+       git rev-parse $m >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin -z verify succeeds for missing reference' '
+       printf $F "verify refs/heads/missing" "$Z" >stdin &&
+       git update-ref -z --stdin <stdin &&
+       test_must_fail git rev-parse --verify -q refs/heads/missing
+'
+
+test_expect_success 'stdin -z verify treats no value as missing' '
+       printf $F "verify refs/heads/missing" "" >stdin &&
+       git update-ref -z --stdin <stdin &&
+       test_must_fail git rev-parse --verify -q refs/heads/missing
+'
+
+test_expect_success 'stdin -z verify fails for wrong value' '
+       git rev-parse $m >expect &&
+       printf $F "verify $m" "$m~1" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin &&
+       git rev-parse $m >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin -z verify fails for mistaken null value' '
+       git rev-parse $m >expect &&
+       printf $F "verify $m" "$Z" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin &&
+       git rev-parse $m >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'stdin -z verify fails for mistaken empty value' '
+       M=$(git rev-parse $m) &&
+       test_when_finished "git update-ref $m $M" &&
+       git rev-parse $m >expect &&
+       printf $F "verify $m" "" >stdin &&
+       test_must_fail git update-ref -z --stdin <stdin &&
+       git rev-parse $m >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'stdin -z update refs works with identity updates' '
        printf $F "update $a" "$m" "$m" "update $b" "$m" "$m" "update $c" "$Z" "" >stdin &&
        git update-ref -z --stdin <stdin &&
index 8cf446165eff431106dd86d01754633fbd3ce246..779d4e3829b29d7092d54f6e342f923f0d239b96 100755 (executable)
@@ -287,4 +287,34 @@ test_expect_success 'stale dirs do not cause d/f conflicts (reflogs off)' '
        test_cmp expect actual
 '
 
+# Triggering the bug detected by this test requires a newline to fall
+# exactly BUFSIZ-1 bytes from the end of the file. We don't know
+# what that value is, since it's platform dependent. However, if
+# we choose some value N, we also catch any D which divides N evenly
+# (since we will read backwards in chunks of D). So we choose 8K,
+# which catches glibc (with an 8K BUFSIZ) and *BSD (1K).
+#
+# Each line is 114 characters, so we need 75 to still have a few before the
+# last 8K. The 89-character padding on the final entry lines up our
+# newline exactly.
+test_expect_success 'parsing reverse reflogs at BUFSIZ boundaries' '
+       git checkout -b reflogskip &&
+       z38=00000000000000000000000000000000000000 &&
+       ident="abc <xyz> 0000000001 +0000" &&
+       for i in $(test_seq 1 75); do
+               printf "$z38%02d $z38%02d %s\t" $i $(($i+1)) "$ident" &&
+               if test $i = 75; then
+                       for j in $(test_seq 1 89); do
+                               printf X
+                       done
+               else
+                       printf X
+               fi &&
+               printf "\n"
+       done >.git/logs/refs/heads/reflogskip &&
+       git rev-parse reflogskip@{73} >actual &&
+       echo ${z38}03 >expect &&
+       test_cmp expect actual
+'
+
 test_done
index 793aee9f0bbd535ddef38249a088d102b15b6479..cfb32b62420dc162e79aaea29a36f7d78f3353f5 100755 (executable)
@@ -229,8 +229,12 @@ test_expect_success 'tag with incorrect tag name & missing tagger' '
        echo $tag >.git/refs/tags/wrong &&
        test_when_finished "git update-ref -d refs/tags/wrong" &&
        git fsck --tags 2>out &&
-       grep "invalid .tag. name" out &&
-       grep "expected .tagger. line" out
+
+       cat >expect <<-EOF &&
+       warning in tag $tag: invalid '\''tag'\'' name: wrong name format
+       warning in tag $tag: invalid format - expected '\''tagger'\'' line
+       EOF
+       test_cmp expect out
 '
 
 test_expect_success 'tag with bad tagger' '
index 6ecb559465b43e528a5cb1511b758cc48d940e92..468a000e4bbb113d004ee8df8ef0db9b8260fdb5 100755 (executable)
@@ -185,4 +185,22 @@ test_expect_success 'checkout <branch> -- succeeds, even if a file with the same
        test_branch_upstream spam repo_c spam
 '
 
+test_expect_success 'loosely defined local base branch is reported correctly' '
+
+       git checkout master &&
+       git branch strict &&
+       git branch loose &&
+       git commit --allow-empty -m "a bit more" &&
+
+       test_config branch.strict.remote . &&
+       test_config branch.loose.remote . &&
+       test_config branch.strict.merge refs/heads/master &&
+       test_config branch.loose.merge master &&
+
+       git checkout strict | sed -e "s/strict/BRANCHNAME/g" >expect &&
+       git checkout loose | sed -e "s/loose/BRANCHNAME/g" >actual &&
+
+       test_cmp expect actual
+'
+
 test_done
index 1bafb9098c7fae33969e9231fbdee1c0370830a1..dfe02f48183ad77a93d72c0f5e952380b63a9229 100755 (executable)
@@ -65,4 +65,19 @@ test_expect_success '--cacheinfo mode,sha1,path (new syntax)' '
        test_cmp expect actual
 '
 
+test_expect_success '.lock files cleaned up' '
+       mkdir cleanup &&
+       (
+       cd cleanup &&
+       mkdir worktree &&
+       git init repo &&
+       cd repo &&
+       git config core.worktree ../../worktree &&
+       # --refresh triggers late setup_work_tree,
+       # active_cache_changed is zero, rollback_lock_file fails
+       git update-index --refresh &&
+       ! test -f .git/index.lock
+       )
+'
+
 test_done
index c286854485d065816ff2c9fdd225c54734d48b60..4d4b02e760d322586eb496d72d0fd6c6b6946a02 100755 (executable)
@@ -12,11 +12,25 @@ test_expect_success 'setup' '
 '
 
 test_expect_success 'ls-tree a[a] matches literally' '
-       cat >expected <<EOF &&
-100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391   a[a]/three
-EOF
+       cat >expect <<-\EOF &&
+       100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391    a[a]/three
+       EOF
        git ls-tree -r HEAD "a[a]" >actual &&
-       test_cmp expected actual
+       test_cmp expect actual
+'
+
+test_expect_success 'ls-tree outside prefix' '
+       cat >expect <<-\EOF &&
+       100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391    ../a[a]/three
+       EOF
+       ( cd aa && git ls-tree -r HEAD "../a[a]"; ) >actual &&
+       test_cmp expect actual
+'
+
+test_expect_failure 'ls-tree does not yet support negated pathspec' '
+       git ls-files ":(exclude)a" "a*" >expect &&
+       git ls-tree --name-only -r HEAD ":(exclude)a" "a*" >actual &&
+       test_cmp expect actual
 '
 
 test_done
index 432921b6b81684313c6b0041a288749c30fdee8e..ddea49808d063f6c169cf8078f5698e34c2ba803 100755 (executable)
@@ -97,6 +97,20 @@ test_expect_success 'git branch -m o/o o should fail when o/p exists' '
        test_must_fail git branch -m o/o o
 '
 
+test_expect_success 'git branch -m o/q o/p should fail when o/p exists' '
+       git branch o/q &&
+       test_must_fail git branch -m o/q o/p
+'
+
+test_expect_success 'git branch -M o/q o/p should work when o/p exists' '
+       git branch -M o/q o/p
+'
+
+test_expect_success 'git branch -m -f o/q o/p should work when o/p exists' '
+       git branch o/q &&
+       git branch -m -f o/q o/p
+'
+
 test_expect_success 'git branch -m q r/q should fail when r exists' '
        git branch q &&
        git branch r &&
index cfd67ff3dfc64b160bbc53318df3eb661970f2e1..245406ab979d63d3588c4e2000b02cc5f24e493b 100755 (executable)
@@ -7,28 +7,22 @@ test_description='Test commit notes'
 
 . ./test-lib.sh
 
-cat > fake_editor.sh << \EOF
-#!/bin/sh
-echo "$MSG" > "$1"
-echo "$MSG" >& 2
+write_script fake_editor <<\EOF
+echo "$MSG" >"$1"
+echo "$MSG" >&2
 EOF
-chmod a+x fake_editor.sh
-GIT_EDITOR=./fake_editor.sh
+GIT_EDITOR=./fake_editor
 export GIT_EDITOR
 
+indent="    "
+
 test_expect_success 'cannot annotate non-existing HEAD' '
        test_must_fail env MSG=3 git notes add
 '
 
-test_expect_success setup '
-       : > a1 &&
-       git add a1 &&
-       test_tick &&
-       git commit -m 1st &&
-       : > a2 &&
-       git add a2 &&
-       test_tick &&
-       git commit -m 2nd
+test_expect_success 'setup' '
+       test_commit 1st &&
+       test_commit 2nd
 '
 
 test_expect_success 'need valid notes ref' '
@@ -50,206 +44,186 @@ test_expect_success 'handle empty notes gracefully' '
 '
 
 test_expect_success 'show non-existent notes entry with %N' '
-       for l in A B
-       do
-               echo "$l"
-       done >expect &&
-       git show -s --format='A%n%NB' >output &&
-       test_cmp expect output
+       test_write_lines A B >expect &&
+       git show -s --format="A%n%NB" >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'create notes' '
-       git config core.notesRef refs/notes/commits &&
        MSG=b4 git notes add &&
-       test ! -f .git/NOTES_EDITMSG &&
-       test 1 = $(git ls-tree refs/notes/commits | wc -l) &&
-       test b4 = $(git notes show) &&
+       test_path_is_missing .git/NOTES_EDITMSG &&
+       git ls-tree -r refs/notes/commits >actual &&
+       test_line_count = 1 actual &&
+       test "b4" = "$(git notes show)" &&
        git show HEAD^ &&
        test_must_fail git notes show HEAD^
 '
 
 test_expect_success 'show notes entry with %N' '
-       for l in A b4 B
-       do
-               echo "$l"
-       done >expect &&
-       git show -s --format='A%n%NB' >output &&
-       test_cmp expect output
+       test_write_lines A b4 B >expect &&
+       git show -s --format="A%n%NB" >actual &&
+       test_cmp expect actual
 '
 
-cat >expect <<EOF
-d423f8c refs/notes/commits@{0}: notes: Notes added by 'git notes add'
-EOF
-
 test_expect_success 'create reflog entry' '
-       git reflog show refs/notes/commits >output &&
-       test_cmp expect output
+       cat <<-EOF >expect &&
+               a1d8fa6 refs/notes/commits@{0}: notes: Notes added by '\''git notes add'\''
+       EOF
+       git reflog show refs/notes/commits >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'edit existing notes' '
        MSG=b3 git notes edit &&
-       test ! -f .git/NOTES_EDITMSG &&
-       test 1 = $(git ls-tree refs/notes/commits | wc -l) &&
-       test b3 = $(git notes show) &&
+       test_path_is_missing .git/NOTES_EDITMSG &&
+       git ls-tree -r refs/notes/commits >actual &&
+       test_line_count = 1 actual &&
+       test "b3" = "$(git notes show)" &&
        git show HEAD^ &&
        test_must_fail git notes show HEAD^
 '
 
 test_expect_success 'cannot "git notes add -m" where notes already exists' '
        test_must_fail git notes add -m "b2" &&
-       test ! -f .git/NOTES_EDITMSG &&
-       test 1 = $(git ls-tree refs/notes/commits | wc -l) &&
-       test b3 = $(git notes show) &&
+       test_path_is_missing .git/NOTES_EDITMSG &&
+       git ls-tree -r refs/notes/commits >actual &&
+       test_line_count = 1 actual &&
+       test "b3" = "$(git notes show)" &&
        git show HEAD^ &&
        test_must_fail git notes show HEAD^
 '
 
 test_expect_success 'can overwrite existing note with "git notes add -f -m"' '
        git notes add -f -m "b1" &&
-       test ! -f .git/NOTES_EDITMSG &&
-       test 1 = $(git ls-tree refs/notes/commits | wc -l) &&
-       test b1 = $(git notes show) &&
+       test_path_is_missing .git/NOTES_EDITMSG &&
+       git ls-tree -r refs/notes/commits >actual &&
+       test_line_count = 1 actual &&
+       test "b1" = "$(git notes show)" &&
        git show HEAD^ &&
        test_must_fail git notes show HEAD^
 '
 
 test_expect_success 'add w/no options on existing note morphs into edit' '
        MSG=b2 git notes add &&
-       test ! -f .git/NOTES_EDITMSG &&
-       test 1 = $(git ls-tree refs/notes/commits | wc -l) &&
-       test b2 = $(git notes show) &&
+       test_path_is_missing .git/NOTES_EDITMSG &&
+       git ls-tree -r refs/notes/commits >actual &&
+       test_line_count = 1 actual &&
+       test "b2" = "$(git notes show)" &&
        git show HEAD^ &&
        test_must_fail git notes show HEAD^
 '
 
 test_expect_success 'can overwrite existing note with "git notes add -f"' '
        MSG=b1 git notes add -f &&
-       test ! -f .git/NOTES_EDITMSG &&
-       test 1 = $(git ls-tree refs/notes/commits | wc -l) &&
-       test b1 = $(git notes show) &&
+       test_path_is_missing .git/NOTES_EDITMSG &&
+       git ls-tree -r refs/notes/commits >actual &&
+       test_line_count = 1 actual &&
+       test "b1" = "$(git notes show)" &&
        git show HEAD^ &&
        test_must_fail git notes show HEAD^
 '
 
-cat > expect << EOF
-commit 268048bfb8a1fb38e703baceb8ab235421bf80c5
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:14:13 2005 -0700
-
-    2nd
+test_expect_success 'show notes' '
+       cat >expect <<-EOF &&
+               commit 7a4ca6ee52a974a66cbaa78e33214535dff1d691
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:14:13 2005 -0700
 
-Notes:
-    b1
-EOF
+               ${indent}2nd
 
-test_expect_success 'show notes' '
+               Notes:
+               ${indent}b1
+       EOF
        ! (git cat-file commit HEAD | grep b1) &&
-       git log -1 > output &&
-       test_cmp expect output
-'
-
-test_expect_success 'create multi-line notes (setup)' '
-       : > a3 &&
-       git add a3 &&
-       test_tick &&
-       git commit -m 3rd &&
-       MSG="b3
-c3c3c3c3
-d3d3d3" git notes add
+       git log -1 >actual &&
+       test_cmp expect actual
 '
 
-cat > expect-multiline << EOF
-commit 1584215f1d29c65e99c6c6848626553fdd07fd75
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:15:13 2005 -0700
-
-    3rd
+test_expect_success 'show multi-line notes' '
+       test_commit 3rd &&
+       MSG="b3${LF}c3c3c3c3${LF}d3d3d3" git notes add &&
+       cat >expect-multiline <<-EOF &&
+               commit d07d62e5208f22eb5695e7eb47667dc8b9860290
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:15:13 2005 -0700
 
-Notes:
-    b3
-    c3c3c3c3
-    d3d3d3
-EOF
+               ${indent}3rd
 
-printf "\n" >> expect-multiline
-cat expect >> expect-multiline
+               Notes:
+               ${indent}b3
+               ${indent}c3c3c3c3
+               ${indent}d3d3d3
 
-test_expect_success 'show multi-line notes' '
-       git log -2 > output &&
-       test_cmp expect-multiline output
-'
-test_expect_success 'create -F notes (setup)' '
-       : > a4 &&
-       git add a4 &&
-       test_tick &&
-       git commit -m 4th &&
-       echo "xyzzy" > note5 &&
-       git notes add -F note5
+       EOF
+       cat expect >>expect-multiline &&
+       git log -2 >actual &&
+       test_cmp expect-multiline actual
 '
 
-cat > expect-F << EOF
-commit 15023535574ded8b1a89052b32673f84cf9582b8
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:16:13 2005 -0700
+test_expect_success 'show -F notes' '
+       test_commit 4th &&
+       echo "xyzzy" >note5 &&
+       git notes add -F note5 &&
+       cat >expect-F <<-EOF &&
+               commit 0f7aa3ec6325aeb88b910453bb3eb37c49d75c11
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:16:13 2005 -0700
 
-    4th
+               ${indent}4th
 
-Notes:
-    xyzzy
-EOF
+               Notes:
+               ${indent}xyzzy
 
-printf "\n" >> expect-F
-cat expect-multiline >> expect-F
-
-test_expect_success 'show -F notes' '
-       git log -3 > output &&
-       test_cmp expect-F output
+       EOF
+       cat expect-multiline >>expect-F &&
+       git log -3 >actual &&
+       test_cmp expect-F actual
 '
 
 test_expect_success 'Re-adding -F notes without -f fails' '
-       echo "zyxxy" > note5 &&
+       echo "zyxxy" >note5 &&
        test_must_fail git notes add -F note5 &&
-       git log -3 > output &&
-       test_cmp expect-F output
+       git log -3 >actual &&
+       test_cmp expect-F actual
 '
 
-cat >expect << EOF
-commit 15023535574ded8b1a89052b32673f84cf9582b8
-tree e070e3af51011e47b183c33adf9736736a525709
-parent 1584215f1d29c65e99c6c6848626553fdd07fd75
-author A U Thor <author@example.com> 1112912173 -0700
-committer C O Mitter <committer@example.com> 1112912173 -0700
-
-    4th
-EOF
 test_expect_success 'git log --pretty=raw does not show notes' '
-       git log -1 --pretty=raw >output &&
-       test_cmp expect output
+       cat >expect <<-EOF &&
+               commit 0f7aa3ec6325aeb88b910453bb3eb37c49d75c11
+               tree 05ac65288c4c4b3b709a020ae94b2ece2f2201ae
+               parent d07d62e5208f22eb5695e7eb47667dc8b9860290
+               author A U Thor <author@example.com> 1112912173 -0700
+               committer C O Mitter <committer@example.com> 1112912173 -0700
+
+               ${indent}4th
+       EOF
+       git log -1 --pretty=raw >actual &&
+       test_cmp expect actual
 '
 
-cat >>expect <<EOF
-
-Notes:
-    xyzzy
-EOF
 test_expect_success 'git log --show-notes' '
-       git log -1 --pretty=raw --show-notes >output &&
-       test_cmp expect output
+       cat >>expect <<-EOF &&
+
+       Notes:
+       ${indent}xyzzy
+       EOF
+       git log -1 --pretty=raw --show-notes >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'git log --no-notes' '
-       git log -1 --no-notes >output &&
-       ! grep xyzzy output
+       git log -1 --no-notes >actual &&
+       ! grep xyzzy actual
 '
 
 test_expect_success 'git format-patch does not show notes' '
-       git format-patch -1 --stdout >output &&
-       ! grep xyzzy output
+       git format-patch -1 --stdout >actual &&
+       ! grep xyzzy actual
 '
 
 test_expect_success 'git format-patch --show-notes does show notes' '
-       git format-patch --show-notes -1 --stdout >output &&
-       grep xyzzy output
+       git format-patch --show-notes -1 --stdout >actual &&
+       grep xyzzy actual
 '
 
 for pretty in \
@@ -261,8 +235,8 @@ do
        ?*) p="$pretty" not=" not" negate="!" ;;
        esac
        test_expect_success "git show $pretty does$not show notes" '
-               git show $p >output &&
-               eval "$negate grep xyzzy output"
+               git show $p >actual &&
+               eval "$negate grep xyzzy actual"
        '
 done
 
@@ -271,161 +245,131 @@ test_expect_success 'setup alternate notes ref' '
 '
 
 test_expect_success 'git log --notes shows default notes' '
-       git log -1 --notes >output &&
-       grep xyzzy output &&
-       ! grep alternate output
+       git log -1 --notes >actual &&
+       grep xyzzy actual &&
+       ! grep alternate actual
 '
 
 test_expect_success 'git log --notes=X shows only X' '
-       git log -1 --notes=alternate >output &&
-       ! grep xyzzy output &&
-       grep alternate output
+       git log -1 --notes=alternate >actual &&
+       ! grep xyzzy actual &&
+       grep alternate actual
 '
 
 test_expect_success 'git log --notes --notes=X shows both' '
-       git log -1 --notes --notes=alternate >output &&
-       grep xyzzy output &&
-       grep alternate output
+       git log -1 --notes --notes=alternate >actual &&
+       grep xyzzy actual &&
+       grep alternate actual
 '
 
 test_expect_success 'git log --no-notes resets default state' '
        git log -1 --notes --notes=alternate \
                --no-notes --notes=alternate \
-               >output &&
-       ! grep xyzzy output &&
-       grep alternate output
+               >actual &&
+       ! grep xyzzy actual &&
+       grep alternate actual
 '
 
 test_expect_success 'git log --no-notes resets ref list' '
        git log -1 --notes --notes=alternate \
                --no-notes --notes \
-               >output &&
-       grep xyzzy output &&
-       ! grep alternate output
-'
-
-test_expect_success 'create -m notes (setup)' '
-       : > a5 &&
-       git add a5 &&
-       test_tick &&
-       git commit -m 5th &&
-       git notes add -m spam -m "foo
-bar
-baz"
-'
-
-whitespace="    "
-cat > expect-m << EOF
-commit bd1753200303d0a0344be813e504253b3d98e74d
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:17:13 2005 -0700
-
-    5th
-
-Notes:
-    spam
-$whitespace
-    foo
-    bar
-    baz
-EOF
-
-printf "\n" >> expect-m
-cat expect-F >> expect-m
-
-test_expect_success 'show -m notes' '
-       git log -4 > output &&
-       test_cmp expect-m output
+               >actual &&
+       grep xyzzy actual &&
+       ! grep alternate actual
 '
 
-test_expect_success 'remove note with add -f -F /dev/null (setup)' '
-       git notes add -f -F /dev/null
-'
-
-cat > expect-rm-F << EOF
-commit bd1753200303d0a0344be813e504253b3d98e74d
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:17:13 2005 -0700
-
-    5th
-EOF
-
-printf "\n" >> expect-rm-F
-cat expect-F >> expect-rm-F
-
-test_expect_success 'verify note removal with -F /dev/null' '
-       git log -4 > output &&
-       test_cmp expect-rm-F output &&
+test_expect_success 'show -m notes' '
+       test_commit 5th &&
+       git notes add -m spam -m "foo${LF}bar${LF}baz" &&
+       cat >expect-m <<-EOF &&
+               commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:17:13 2005 -0700
+
+               ${indent}5th
+
+               Notes:
+               ${indent}spam
+               ${indent}
+               ${indent}foo
+               ${indent}bar
+               ${indent}baz
+
+       EOF
+       cat expect-F >>expect-m &&
+       git log -4 >actual &&
+       test_cmp expect-m actual
+'
+
+test_expect_success 'remove note with add -f -F /dev/null' '
+       git notes add -f -F /dev/null &&
+       cat >expect-rm-F <<-EOF &&
+               commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:17:13 2005 -0700
+
+               ${indent}5th
+
+       EOF
+       cat expect-F >>expect-rm-F &&
+       git log -4 >actual &&
+       test_cmp expect-rm-F actual &&
        test_must_fail git notes show
 '
 
-test_expect_success 'do not create empty note with -m "" (setup)' '
-       git notes add -m ""
-'
-
-test_expect_success 'verify non-creation of note with -m ""' '
-       git log -4 > output &&
-       test_cmp expect-rm-F output &&
+test_expect_success 'do not create empty note with -m ""' '
+       git notes add -m "" &&
+       git log -4 >actual &&
+       test_cmp expect-rm-F actual &&
        test_must_fail git notes show
 '
 
-cat > expect-combine_m_and_F << EOF
-foo
-
-xyzzy
+test_expect_success 'create note with combination of -m and -F' '
+       cat >expect-combine_m_and_F <<-EOF &&
+               foo
 
-bar
+               xyzzy
 
-zyxxy
+               bar
 
-baz
-EOF
+               zyxxy
 
-test_expect_success 'create note with combination of -m and -F' '
-       echo "xyzzy" > note_a &&
-       echo "zyxxy" > note_b &&
+               baz
+       EOF
+       echo "xyzzy" >note_a &&
+       echo "zyxxy" >note_b &&
        git notes add -m "foo" -F note_a -m "bar" -F note_b -m "baz" &&
-       git notes show > output &&
-       test_cmp expect-combine_m_and_F output
+       git notes show >actual &&
+       test_cmp expect-combine_m_and_F actual
 '
 
-test_expect_success 'remove note with "git notes remove" (setup)' '
+test_expect_success 'remove note with "git notes remove"' '
        git notes remove HEAD^ &&
-       git notes remove
-'
-
-cat > expect-rm-remove << EOF
-commit bd1753200303d0a0344be813e504253b3d98e74d
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:17:13 2005 -0700
+       git notes remove &&
+       cat >expect-rm-remove <<-EOF &&
+               commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:17:13 2005 -0700
 
-    5th
+               ${indent}5th
 
-commit 15023535574ded8b1a89052b32673f84cf9582b8
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:16:13 2005 -0700
+               commit 0f7aa3ec6325aeb88b910453bb3eb37c49d75c11
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:16:13 2005 -0700
 
-    4th
-EOF
-
-printf "\n" >> expect-rm-remove
-cat expect-multiline >> expect-rm-remove
+               ${indent}4th
 
-test_expect_success 'verify note removal with "git notes remove"' '
-       git log -4 > output &&
-       test_cmp expect-rm-remove output &&
+       EOF
+       cat expect-multiline >>expect-rm-remove &&
+       git log -4 >actual &&
+       test_cmp expect-rm-remove actual &&
        test_must_fail git notes show HEAD^
 '
 
-cat > expect << EOF
-c18dc024e14f08d18d14eea0d747ff692d66d6a3 1584215f1d29c65e99c6c6848626553fdd07fd75
-c9c6af7f78bc47490dbf3e822cf2f3c24d4b9061 268048bfb8a1fb38e703baceb8ab235421bf80c5
-EOF
-
 test_expect_success 'removing non-existing note should not create new commit' '
-       git rev-parse --verify refs/notes/commits > before_commit &&
+       git rev-parse --verify refs/notes/commits >before_commit &&
        test_must_fail git notes remove HEAD^ &&
-       git rev-parse --verify refs/notes/commits > after_commit &&
+       git rev-parse --verify refs/notes/commits >after_commit &&
        test_cmp before_commit after_commit
 '
 
@@ -505,70 +449,68 @@ test_expect_success 'removing with --stdin --ignore-missing' '
 '
 
 test_expect_success 'list notes with "git notes list"' '
-       git notes list > output &&
-       test_cmp expect output
+       cat >expect <<-EOF &&
+               c9c6af7f78bc47490dbf3e822cf2f3c24d4b9061 7a4ca6ee52a974a66cbaa78e33214535dff1d691
+               c18dc024e14f08d18d14eea0d747ff692d66d6a3 d07d62e5208f22eb5695e7eb47667dc8b9860290
+       EOF
+       git notes list >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'list notes with "git notes"' '
-       git notes > output &&
-       test_cmp expect output
+       git notes >actual &&
+       test_cmp expect actual
 '
 
-cat > expect << EOF
-c18dc024e14f08d18d14eea0d747ff692d66d6a3
-EOF
-
 test_expect_success 'list specific note with "git notes list <object>"' '
-       git notes list HEAD^^ > output &&
-       test_cmp expect output
+       cat >expect <<-EOF &&
+               c18dc024e14f08d18d14eea0d747ff692d66d6a3
+       EOF
+       git notes list HEAD^^ >actual &&
+       test_cmp expect actual
 '
 
-cat > expect << EOF
-EOF
-
 test_expect_success 'listing non-existing notes fails' '
-       test_must_fail git notes list HEAD > output &&
-       test_cmp expect output
+       cat >expect <<-EOF &&
+       EOF
+       test_must_fail git notes list HEAD >actual &&
+       test_cmp expect actual
 '
 
-cat > expect << EOF
-Initial set of notes
-
-More notes appended with git notes append
-EOF
-
 test_expect_success 'append to existing note with "git notes append"' '
+       cat >expect <<-EOF &&
+               Initial set of notes
+
+               More notes appended with git notes append
+       EOF
        git notes add -m "Initial set of notes" &&
        git notes append -m "More notes appended with git notes append" &&
-       git notes show > output &&
-       test_cmp expect output
+       git notes show >actual &&
+       test_cmp expect actual
 '
 
-cat > expect_list << EOF
-c18dc024e14f08d18d14eea0d747ff692d66d6a3 1584215f1d29c65e99c6c6848626553fdd07fd75
-c9c6af7f78bc47490dbf3e822cf2f3c24d4b9061 268048bfb8a1fb38e703baceb8ab235421bf80c5
-4b6ad22357cc8a1296720574b8d2fbc22fab0671 bd1753200303d0a0344be813e504253b3d98e74d
-EOF
-
 test_expect_success '"git notes list" does not expand to "git notes list HEAD"' '
-       git notes list > output &&
-       test_cmp expect_list output
+       cat >expect_list <<-EOF &&
+               c9c6af7f78bc47490dbf3e822cf2f3c24d4b9061 7a4ca6ee52a974a66cbaa78e33214535dff1d691
+               4b6ad22357cc8a1296720574b8d2fbc22fab0671 7f9ad8836c775acb134c0a055fc55fb4cd1ba361
+               c18dc024e14f08d18d14eea0d747ff692d66d6a3 d07d62e5208f22eb5695e7eb47667dc8b9860290
+       EOF
+       git notes list >actual &&
+       test_cmp expect_list actual
 '
 
 test_expect_success 'appending empty string does not change existing note' '
        git notes append -m "" &&
-       git notes show > output &&
-       test_cmp expect output
+       git notes show >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'git notes append == add when there is no existing note' '
        git notes remove HEAD &&
        test_must_fail git notes list HEAD &&
-       git notes append -m "Initial set of notes
-
-More notes appended with git notes append" &&
-       git notes show > output &&
-       test_cmp expect output
+       git notes append -m "Initial set of notes${LF}${LF}More notes appended with git notes append" &&
+       git notes show >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'appending empty string to non-existing note does not create note' '
@@ -579,229 +521,208 @@ test_expect_success 'appending empty string to non-existing note does not create
 '
 
 test_expect_success 'create other note on a different notes ref (setup)' '
-       : > a6 &&
-       git add a6 &&
-       test_tick &&
-       git commit -m 6th &&
-       GIT_NOTES_REF="refs/notes/other" git notes add -m "other note"
-'
+       test_commit 6th &&
+       GIT_NOTES_REF="refs/notes/other" git notes add -m "other note" &&
+       cat >expect-not-other <<-EOF &&
+               commit 2c125331118caba0ff8238b7f4958ac6e93fe39c
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:18:13 2005 -0700
 
-cat > expect-other << EOF
-commit 387a89921c73d7ed72cd94d179c1c7048ca47756
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:18:13 2005 -0700
-
-    6th
-
-Notes (other):
-    other note
-EOF
+               ${indent}6th
+       EOF
+       cp expect-not-other expect-other &&
+       cat >>expect-other <<-EOF
 
-cat > expect-not-other << EOF
-commit 387a89921c73d7ed72cd94d179c1c7048ca47756
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:18:13 2005 -0700
-
-    6th
-EOF
+               Notes (other):
+               ${indent}other note
+       EOF
+'
 
 test_expect_success 'Do not show note on other ref by default' '
-       git log -1 > output &&
-       test_cmp expect-not-other output
+       git log -1 >actual &&
+       test_cmp expect-not-other actual
 '
 
 test_expect_success 'Do show note when ref is given in GIT_NOTES_REF' '
-       GIT_NOTES_REF="refs/notes/other" git log -1 > output &&
-       test_cmp expect-other output
+       GIT_NOTES_REF="refs/notes/other" git log -1 >actual &&
+       test_cmp expect-other actual
 '
 
 test_expect_success 'Do show note when ref is given in core.notesRef config' '
-       git config core.notesRef "refs/notes/other" &&
-       git log -1 > output &&
-       test_cmp expect-other output
+       test_config core.notesRef "refs/notes/other" &&
+       git log -1 >actual &&
+       test_cmp expect-other actual
 '
 
 test_expect_success 'Do not show note when core.notesRef is overridden' '
-       GIT_NOTES_REF="refs/notes/wrong" git log -1 > output &&
-       test_cmp expect-not-other output
+       test_config core.notesRef "refs/notes/other" &&
+       GIT_NOTES_REF="refs/notes/wrong" git log -1 >actual &&
+       test_cmp expect-not-other actual
 '
 
-cat > expect-both << EOF
-commit 387a89921c73d7ed72cd94d179c1c7048ca47756
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:18:13 2005 -0700
-
-    6th
+test_expect_success 'Show all notes when notes.displayRef=refs/notes/*' '
+       cat >expect-both <<-EOF &&
+               commit 2c125331118caba0ff8238b7f4958ac6e93fe39c
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:18:13 2005 -0700
 
-Notes:
-    order test
+               ${indent}6th
 
-Notes (other):
-    other note
+               Notes:
+               ${indent}order test
 
-commit bd1753200303d0a0344be813e504253b3d98e74d
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:17:13 2005 -0700
+               Notes (other):
+               ${indent}other note
 
-    5th
+               commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:17:13 2005 -0700
 
-Notes:
-    replacement for deleted note
-EOF
+               ${indent}5th
 
-test_expect_success 'Show all notes when notes.displayRef=refs/notes/*' '
+               Notes:
+               ${indent}replacement for deleted note
+       EOF
        GIT_NOTES_REF=refs/notes/commits git notes add \
                -m"replacement for deleted note" HEAD^ &&
        GIT_NOTES_REF=refs/notes/commits git notes add -m"order test" &&
-       git config --unset core.notesRef &&
-       git config notes.displayRef "refs/notes/*" &&
-       git log -2 > output &&
-       test_cmp expect-both output
+       test_unconfig core.notesRef &&
+       test_config notes.displayRef "refs/notes/*" &&
+       git log -2 >actual &&
+       test_cmp expect-both actual
 '
 
 test_expect_success 'core.notesRef is implicitly in notes.displayRef' '
-       git config core.notesRef refs/notes/commits &&
-       git config notes.displayRef refs/notes/other &&
-       git log -2 > output &&
-       test_cmp expect-both output
+       test_config core.notesRef refs/notes/commits &&
+       test_config notes.displayRef refs/notes/other &&
+       git log -2 >actual &&
+       test_cmp expect-both actual
 '
 
 test_expect_success 'notes.displayRef can be given more than once' '
-       git config --unset core.notesRef &&
-       git config notes.displayRef refs/notes/commits &&
+       test_unconfig core.notesRef &&
+       test_config notes.displayRef refs/notes/commits &&
        git config --add notes.displayRef refs/notes/other &&
-       git log -2 > output &&
-       test_cmp expect-both output
+       git log -2 >actual &&
+       test_cmp expect-both actual
 '
 
-cat > expect-both-reversed << EOF
-commit 387a89921c73d7ed72cd94d179c1c7048ca47756
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:18:13 2005 -0700
-
-    6th
+test_expect_success 'notes.displayRef respects order' '
+       cat >expect-both-reversed <<-EOF &&
+               commit 2c125331118caba0ff8238b7f4958ac6e93fe39c
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:18:13 2005 -0700
 
-Notes (other):
-    other note
+               ${indent}6th
 
-Notes:
-    order test
-EOF
+               Notes (other):
+               ${indent}other note
 
-test_expect_success 'notes.displayRef respects order' '
-       git config core.notesRef refs/notes/other &&
-       git config --unset-all notes.displayRef &&
-       git config notes.displayRef refs/notes/commits &&
-       git log -1 > output &&
-       test_cmp expect-both-reversed output
+               Notes:
+               ${indent}order test
+       EOF
+       test_config core.notesRef refs/notes/other &&
+       test_config notes.displayRef refs/notes/commits &&
+       git log -1 >actual &&
+       test_cmp expect-both-reversed actual
 '
 
 test_expect_success 'GIT_NOTES_DISPLAY_REF works' '
-       git config --unset-all core.notesRef &&
-       git config --unset-all notes.displayRef &&
        GIT_NOTES_DISPLAY_REF=refs/notes/commits:refs/notes/other \
-               git log -2 > output &&
-       test_cmp expect-both output
+               git log -2 >actual &&
+       test_cmp expect-both actual
 '
 
-cat > expect-none << EOF
-commit 387a89921c73d7ed72cd94d179c1c7048ca47756
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:18:13 2005 -0700
-
-    6th
+test_expect_success 'GIT_NOTES_DISPLAY_REF overrides config' '
+       cat >expect-none <<-EOF &&
+               commit 2c125331118caba0ff8238b7f4958ac6e93fe39c
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:18:13 2005 -0700
 
-commit bd1753200303d0a0344be813e504253b3d98e74d
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:17:13 2005 -0700
+               ${indent}6th
 
-    5th
-EOF
+               commit 7f9ad8836c775acb134c0a055fc55fb4cd1ba361
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:17:13 2005 -0700
 
-test_expect_success 'GIT_NOTES_DISPLAY_REF overrides config' '
-       git config notes.displayRef "refs/notes/*" &&
-       GIT_NOTES_REF= GIT_NOTES_DISPLAY_REF= git log -2 > output &&
-       test_cmp expect-none output
+               ${indent}5th
+       EOF
+       test_config notes.displayRef "refs/notes/*" &&
+       GIT_NOTES_REF= GIT_NOTES_DISPLAY_REF= git log -2 >actual &&
+       test_cmp expect-none actual
 '
 
 test_expect_success '--show-notes=* adds to GIT_NOTES_DISPLAY_REF' '
-       GIT_NOTES_REF= GIT_NOTES_DISPLAY_REF= git log --show-notes=* -2 > output &&
-       test_cmp expect-both output
+       GIT_NOTES_REF= GIT_NOTES_DISPLAY_REF= git log --show-notes=* -2 >actual &&
+       test_cmp expect-both actual
 '
 
-cat > expect-commits << EOF
-commit 387a89921c73d7ed72cd94d179c1c7048ca47756
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:18:13 2005 -0700
-
-    6th
+test_expect_success '--no-standard-notes' '
+       cat >expect-commits <<EOF
+               commit 2c125331118caba0ff8238b7f4958ac6e93fe39c
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:18:13 2005 -0700
 
-Notes:
-    order test
-EOF
+               ${indent}6th
 
-test_expect_success '--no-standard-notes' '
-       git log --no-standard-notes --show-notes=commits -1 > output &&
-       test_cmp expect-commits output
+               Notes:
+               ${indent}order test
+       EOF
+       git log --no-standard-notes --show-notes=commits -1 >actual &&
+       test_cmp expect-commits actual
 '
 
 test_expect_success '--standard-notes' '
+       test_config notes.displayRef "refs/notes/*" &&
        git log --no-standard-notes --show-notes=commits \
-               --standard-notes -2 > output &&
-       test_cmp expect-both output
+               --standard-notes -2 >actual &&
+       test_cmp expect-both actual
 '
 
 test_expect_success '--show-notes=ref accumulates' '
        git log --show-notes=other --show-notes=commits \
-                --no-standard-notes -1 > output &&
-       test_cmp expect-both-reversed output
+                --no-standard-notes -1 >actual &&
+       test_cmp expect-both-reversed actual
 '
 
 test_expect_success 'Allow notes on non-commits (trees, blobs, tags)' '
-       git config core.notesRef refs/notes/other &&
-       echo "Note on a tree" > expect &&
+       test_config core.notesRef refs/notes/other &&
+       echo "Note on a tree" >expect &&
        git notes add -m "Note on a tree" HEAD: &&
-       git notes show HEAD: > actual &&
+       git notes show HEAD: >actual &&
        test_cmp expect actual &&
-       echo "Note on a blob" > expect &&
+       echo "Note on a blob" >expect &&
        filename=$(git ls-tree --name-only HEAD | head -n1) &&
        git notes add -m "Note on a blob" HEAD:$filename &&
-       git notes show HEAD:$filename > actual &&
+       git notes show HEAD:$filename >actual &&
        test_cmp expect actual &&
-       echo "Note on a tag" > expect &&
+       echo "Note on a tag" >expect &&
        git tag -a -m "This is an annotated tag" foobar HEAD^ &&
        git notes add -m "Note on a tag" foobar &&
-       git notes show foobar > actual &&
+       git notes show foobar >actual &&
        test_cmp expect actual
 '
 
-cat > expect << EOF
-commit 2ede89468182a62d0bde2583c736089bcf7d7e92
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:19:13 2005 -0700
-
-    7th
+test_expect_success 'create note from other note with "git notes add -C"' '
+       cat >expect <<-EOF &&
+               commit fb01e0ca8c33b6cc0c6451dde747f97df567cb5c
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:19:13 2005 -0700
 
-Notes (other):
-    other note
-EOF
+               ${indent}7th
 
-test_expect_success 'create note from other note with "git notes add -C"' '
-       : > a7 &&
-       git add a7 &&
-       test_tick &&
-       git commit -m 7th &&
+               Notes:
+               ${indent}order test
+       EOF
+       test_commit 7th &&
        git notes add -C $(git notes list HEAD^) &&
-       git log -1 > actual &&
+       git log -1 >actual &&
        test_cmp expect actual &&
        test "$(git notes list HEAD)" = "$(git notes list HEAD^)"
 '
 
 test_expect_success 'create note from non-existing note with "git notes add -C" fails' '
-       : > a8 &&
-       git add a8 &&
-       test_tick &&
-       git commit -m 8th &&
+       test_commit 8th &&
        test_must_fail git notes add -C deadbeef &&
        test_must_fail git notes list HEAD
 '
@@ -814,405 +735,386 @@ test_expect_success 'create note from non-blob with "git notes add -C" fails' '
        test_must_fail git notes list HEAD
 '
 
-cat > expect << EOF
-commit 80d796defacd5db327b7a4e50099663902fbdc5c
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:20:13 2005 -0700
-
-    8th
+test_expect_success 'create note from blob with "git notes add -C" reuses blob id' '
+       cat >expect <<-EOF &&
+               commit 9a4c31c7f722b5d517e92c64e932dd751e1413bf
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:20:13 2005 -0700
 
-Notes (other):
-    This is a blob object
-EOF
+               ${indent}8th
 
-test_expect_success 'create note from blob with "git notes add -C" reuses blob id' '
+               Notes:
+               ${indent}This is a blob object
+       EOF
        blob=$(echo "This is a blob object" | git hash-object -w --stdin) &&
        git notes add -C $blob &&
-       git log -1 > actual &&
+       git log -1 >actual &&
        test_cmp expect actual &&
        test "$(git notes list HEAD)" = "$blob"
 '
 
-cat > expect << EOF
-commit 016e982bad97eacdbda0fcbd7ce5b0ba87c81f1b
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:21:13 2005 -0700
-
-    9th
+test_expect_success 'create note from other note with "git notes add -c"' '
+       cat >expect <<-EOF &&
+               commit 2e0db4bc649e174d667a1cde19e725cf897a5bd2
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:21:13 2005 -0700
 
-Notes (other):
-    yet another note
-EOF
+               ${indent}9th
 
-test_expect_success 'create note from other note with "git notes add -c"' '
-       : > a9 &&
-       git add a9 &&
-       test_tick &&
-       git commit -m 9th &&
+               Notes:
+               ${indent}yet another note
+       EOF
+       test_commit 9th &&
        MSG="yet another note" git notes add -c $(git notes list HEAD^^) &&
-       git log -1 > actual &&
+       git log -1 >actual &&
        test_cmp expect actual
 '
 
 test_expect_success 'create note from non-existing note with "git notes add -c" fails' '
-       : > a10 &&
-       git add a10 &&
-       test_tick &&
-       git commit -m 10th &&
+       test_commit 10th &&
        test_must_fail env MSG="yet another note" git notes add -c deadbeef &&
        test_must_fail git notes list HEAD
 '
 
-cat > expect << EOF
-commit 016e982bad97eacdbda0fcbd7ce5b0ba87c81f1b
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:21:13 2005 -0700
-
-    9th
-
-Notes (other):
-    yet another note
-$whitespace
-    yet another note
-EOF
-
 test_expect_success 'append to note from other note with "git notes append -C"' '
+       cat >expect <<-EOF &&
+               commit 2e0db4bc649e174d667a1cde19e725cf897a5bd2
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:21:13 2005 -0700
+
+               ${indent}9th
+
+               Notes:
+               ${indent}yet another note
+               ${indent}
+               ${indent}yet another note
+       EOF
        git notes append -C $(git notes list HEAD^) HEAD^ &&
-       git log -1 HEAD^ > actual &&
+       git log -1 HEAD^ >actual &&
        test_cmp expect actual
 '
 
-cat > expect << EOF
-commit ffed603236bfa3891c49644257a83598afe8ae5a
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:22:13 2005 -0700
+test_expect_success 'create note from other note with "git notes append -c"' '
+       cat >expect <<-EOF &&
+               commit 7c3b87ab368f81e11b1ea87b2ab99a71ccd25406
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:22:13 2005 -0700
 
-    10th
+               ${indent}10th
 
-Notes (other):
-    other note
-EOF
-
-test_expect_success 'create note from other note with "git notes append -c"' '
+               Notes:
+               ${indent}other note
+       EOF
        MSG="other note" git notes append -c $(git notes list HEAD^) &&
-       git log -1 > actual &&
+       git log -1 >actual &&
        test_cmp expect actual
 '
 
-cat > expect << EOF
-commit ffed603236bfa3891c49644257a83598afe8ae5a
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:22:13 2005 -0700
-
-    10th
-
-Notes (other):
-    other note
-$whitespace
-    yet another note
-EOF
-
 test_expect_success 'append to note from other note with "git notes append -c"' '
+       cat >expect <<-EOF &&
+               commit 7c3b87ab368f81e11b1ea87b2ab99a71ccd25406
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:22:13 2005 -0700
+
+               ${indent}10th
+
+               Notes:
+               ${indent}other note
+               ${indent}
+               ${indent}yet another note
+       EOF
        MSG="yet another note" git notes append -c $(git notes list HEAD) &&
-       git log -1 > actual &&
+       git log -1 >actual &&
        test_cmp expect actual
 '
 
-cat > expect << EOF
-commit 6352c5e33dbcab725fe0579be16aa2ba8eb369be
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:23:13 2005 -0700
-
-    11th
-
-Notes (other):
-    other note
-$whitespace
-    yet another note
-EOF
-
 test_expect_success 'copy note with "git notes copy"' '
-       : > a11 &&
-       git add a11 &&
-       test_tick &&
-       git commit -m 11th &&
+       cat >expect <<-EOF &&
+               commit a446fff8777efdc6eb8f4b7c8a5ff699484df0d5
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:23:13 2005 -0700
+
+               ${indent}11th
+
+               Notes:
+               ${indent}other note
+               ${indent}
+               ${indent}yet another note
+       EOF
+       test_commit 11th &&
        git notes copy HEAD^ HEAD &&
-       git log -1 > actual &&
+       git log -1 >actual &&
        test_cmp expect actual &&
        test "$(git notes list HEAD)" = "$(git notes list HEAD^)"
 '
 
 test_expect_success 'prevent overwrite with "git notes copy"' '
        test_must_fail git notes copy HEAD~2 HEAD &&
-       git log -1 > actual &&
+       git log -1 >actual &&
        test_cmp expect actual &&
        test "$(git notes list HEAD)" = "$(git notes list HEAD^)"
 '
 
-cat > expect << EOF
-commit 6352c5e33dbcab725fe0579be16aa2ba8eb369be
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:23:13 2005 -0700
-
-    11th
-
-Notes (other):
-    yet another note
-$whitespace
-    yet another note
-EOF
-
 test_expect_success 'allow overwrite with "git notes copy -f"' '
+       cat >expect <<-EOF &&
+               commit a446fff8777efdc6eb8f4b7c8a5ff699484df0d5
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:23:13 2005 -0700
+
+               ${indent}11th
+
+               Notes:
+               ${indent}yet another note
+               ${indent}
+               ${indent}yet another note
+       EOF
        git notes copy -f HEAD~2 HEAD &&
-       git log -1 > actual &&
+       git log -1 >actual &&
        test_cmp expect actual &&
        test "$(git notes list HEAD)" = "$(git notes list HEAD~2)"
 '
 
 test_expect_success 'cannot copy note from object without notes' '
-       : > a12 &&
-       git add a12 &&
-       test_tick &&
-       git commit -m 12th &&
-       : > a13 &&
-       git add a13 &&
-       test_tick &&
-       git commit -m 13th &&
+       test_commit 12th &&
+       test_commit 13th &&
        test_must_fail git notes copy HEAD^ HEAD
 '
 
-cat > expect << EOF
-commit e5d4fb5698d564ab8c73551538ecaf2b0c666185
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:25:13 2005 -0700
-
-    13th
+test_expect_success 'git notes copy --stdin' '
+       cat >expect <<-EOF &&
+               commit e871aa61182b1d95d0a6fb75445d891722863b6b
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:25:13 2005 -0700
 
-Notes (other):
-    yet another note
-$whitespace
-    yet another note
+               ${indent}13th
 
-commit 7038787dfe22a14c3867ce816dbba39845359719
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:24:13 2005 -0700
+               Notes:
+               ${indent}yet another note
+               ${indent}
+               ${indent}yet another note
 
-    12th
+               commit 65e263ded02ae4e8839bc151095113737579dc12
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:24:13 2005 -0700
 
-Notes (other):
-    other note
-$whitespace
-    yet another note
-EOF
+               ${indent}12th
 
-test_expect_success 'git notes copy --stdin' '
+               Notes:
+               ${indent}other note
+               ${indent}
+               ${indent}yet another note
+       EOF
        (echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^); \
        echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) |
        git notes copy --stdin &&
-       git log -2 > output &&
-       test_cmp expect output &&
+       git log -2 >actual &&
+       test_cmp expect actual &&
        test "$(git notes list HEAD)" = "$(git notes list HEAD~2)" &&
        test "$(git notes list HEAD^)" = "$(git notes list HEAD~3)"
 '
 
-cat > expect << EOF
-commit 37a0d4cba38afef96ba54a3ea567e6dac575700b
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:27:13 2005 -0700
-
-    15th
+test_expect_success 'git notes copy --for-rewrite (unconfigured)' '
+       cat >expect <<-EOF &&
+               commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:27:13 2005 -0700
 
-commit be28d8b4d9951ad940d229ee3b0b9ee3b1ec273d
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:26:13 2005 -0700
+               ${indent}15th
 
-    14th
-EOF
+               commit 07c85d77059393ed0154b8c96906547a59dfcddd
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:26:13 2005 -0700
 
-test_expect_success 'git notes copy --for-rewrite (unconfigured)' '
+               ${indent}14th
+       EOF
        test_commit 14th &&
        test_commit 15th &&
        (echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^); \
        echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) |
        git notes copy --for-rewrite=foo &&
-       git log -2 > output &&
-       test_cmp expect output
+       git log -2 >actual &&
+       test_cmp expect actual
 '
 
-cat > expect << EOF
-commit 37a0d4cba38afef96ba54a3ea567e6dac575700b
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:27:13 2005 -0700
-
-    15th
-
-Notes (other):
-    yet another note
-$whitespace
-    yet another note
-
-commit be28d8b4d9951ad940d229ee3b0b9ee3b1ec273d
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:26:13 2005 -0700
-
-    14th
-
-Notes (other):
-    other note
-$whitespace
-    yet another note
-EOF
-
 test_expect_success 'git notes copy --for-rewrite (enabled)' '
-       git config notes.rewriteMode overwrite &&
-       git config notes.rewriteRef "refs/notes/*" &&
+       cat >expect <<-EOF &&
+               commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:27:13 2005 -0700
+
+               ${indent}15th
+
+               Notes:
+               ${indent}yet another note
+               ${indent}
+               ${indent}yet another note
+
+               commit 07c85d77059393ed0154b8c96906547a59dfcddd
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:26:13 2005 -0700
+
+               ${indent}14th
+
+               Notes:
+               ${indent}other note
+               ${indent}
+               ${indent}yet another note
+       EOF
+       test_config notes.rewriteMode overwrite &&
+       test_config notes.rewriteRef "refs/notes/*" &&
        (echo $(git rev-parse HEAD~3) $(git rev-parse HEAD^); \
        echo $(git rev-parse HEAD~2) $(git rev-parse HEAD)) |
        git notes copy --for-rewrite=foo &&
-       git log -2 > output &&
-       test_cmp expect output
+       git log -2 >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'git notes copy --for-rewrite (disabled)' '
-       git config notes.rewrite.bar false &&
+       test_config notes.rewrite.bar false &&
        echo $(git rev-parse HEAD~3) $(git rev-parse HEAD) |
        git notes copy --for-rewrite=bar &&
-       git log -2 > output &&
-       test_cmp expect output
+       git log -2 >actual &&
+       test_cmp expect actual
 '
 
-cat > expect << EOF
-commit 37a0d4cba38afef96ba54a3ea567e6dac575700b
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:27:13 2005 -0700
-
-    15th
+test_expect_success 'git notes copy --for-rewrite (overwrite)' '
+       cat >expect <<-EOF &&
+               commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:27:13 2005 -0700
 
-Notes (other):
-    a fresh note
-EOF
+               ${indent}15th
 
-test_expect_success 'git notes copy --for-rewrite (overwrite)' '
+               Notes:
+               ${indent}a fresh note
+       EOF
        git notes add -f -m"a fresh note" HEAD^ &&
+       test_config notes.rewriteMode overwrite &&
+       test_config notes.rewriteRef "refs/notes/*" &&
        echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
        git notes copy --for-rewrite=foo &&
-       git log -1 > output &&
-       test_cmp expect output
+       git log -1 >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'git notes copy --for-rewrite (ignore)' '
-       git config notes.rewriteMode ignore &&
+       test_config notes.rewriteMode ignore &&
+       test_config notes.rewriteRef "refs/notes/*" &&
        echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
        git notes copy --for-rewrite=foo &&
-       git log -1 > output &&
-       test_cmp expect output
+       git log -1 >actual &&
+       test_cmp expect actual
 '
 
-cat > expect << EOF
-commit 37a0d4cba38afef96ba54a3ea567e6dac575700b
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:27:13 2005 -0700
-
-    15th
-
-Notes (other):
-    a fresh note
-$whitespace
-    another fresh note
-EOF
-
 test_expect_success 'git notes copy --for-rewrite (append)' '
+       cat >expect <<-EOF &&
+               commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:27:13 2005 -0700
+
+               ${indent}15th
+
+               Notes:
+               ${indent}a fresh note
+               ${indent}
+               ${indent}another fresh note
+       EOF
        git notes add -f -m"another fresh note" HEAD^ &&
-       git config notes.rewriteMode concatenate &&
+       test_config notes.rewriteMode concatenate &&
+       test_config notes.rewriteRef "refs/notes/*" &&
        echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
        git notes copy --for-rewrite=foo &&
-       git log -1 > output &&
-       test_cmp expect output
+       git log -1 >actual &&
+       test_cmp expect actual
 '
 
-cat > expect << EOF
-commit 37a0d4cba38afef96ba54a3ea567e6dac575700b
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:27:13 2005 -0700
-
-    15th
-
-Notes (other):
-    a fresh note
-$whitespace
-    another fresh note
-$whitespace
-    append 1
-$whitespace
-    append 2
-EOF
-
 test_expect_success 'git notes copy --for-rewrite (append two to one)' '
+       cat >expect <<-EOF &&
+               commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:27:13 2005 -0700
+
+               ${indent}15th
+
+               Notes:
+               ${indent}a fresh note
+               ${indent}
+               ${indent}another fresh note
+               ${indent}
+               ${indent}append 1
+               ${indent}
+               ${indent}append 2
+       EOF
        git notes add -f -m"append 1" HEAD^ &&
        git notes add -f -m"append 2" HEAD^^ &&
+       test_config notes.rewriteMode concatenate &&
+       test_config notes.rewriteRef "refs/notes/*" &&
        (echo $(git rev-parse HEAD^) $(git rev-parse HEAD);
        echo $(git rev-parse HEAD^^) $(git rev-parse HEAD)) |
        git notes copy --for-rewrite=foo &&
-       git log -1 > output &&
-       test_cmp expect output
+       git log -1 >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'git notes copy --for-rewrite (append empty)' '
        git notes remove HEAD^ &&
+       test_config notes.rewriteMode concatenate &&
+       test_config notes.rewriteRef "refs/notes/*" &&
        echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
        git notes copy --for-rewrite=foo &&
-       git log -1 > output &&
-       test_cmp expect output
+       git log -1 >actual &&
+       test_cmp expect actual
 '
 
-cat > expect << EOF
-commit 37a0d4cba38afef96ba54a3ea567e6dac575700b
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:27:13 2005 -0700
-
-    15th
-
-Notes (other):
-    replacement note 1
-EOF
-
 test_expect_success 'GIT_NOTES_REWRITE_MODE works' '
+       cat >expect <<-EOF &&
+               commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:27:13 2005 -0700
+
+               ${indent}15th
+
+               Notes:
+               ${indent}replacement note 1
+       EOF
+       test_config notes.rewriteMode concatenate &&
+       test_config notes.rewriteRef "refs/notes/*" &&
        git notes add -f -m"replacement note 1" HEAD^ &&
        echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
        GIT_NOTES_REWRITE_MODE=overwrite git notes copy --for-rewrite=foo &&
-       git log -1 > output &&
-       test_cmp expect output
+       git log -1 >actual &&
+       test_cmp expect actual
 '
 
-cat > expect << EOF
-commit 37a0d4cba38afef96ba54a3ea567e6dac575700b
-Author: A U Thor <author@example.com>
-Date:   Thu Apr 7 15:27:13 2005 -0700
+test_expect_success 'GIT_NOTES_REWRITE_REF works' '
+       cat >expect <<-EOF &&
+               commit 4acf42e847e7fffbbf89ee365c20ac7caf40de89
+               Author: A U Thor <author@example.com>
+               Date:   Thu Apr 7 15:27:13 2005 -0700
 
-    15th
+               ${indent}15th
 
-Notes (other):
-    replacement note 2
-EOF
-
-test_expect_success 'GIT_NOTES_REWRITE_REF works' '
-       git config notes.rewriteMode overwrite &&
+               Notes:
+               ${indent}replacement note 2
+       EOF
        git notes add -f -m"replacement note 2" HEAD^ &&
-       git config --unset-all notes.rewriteRef &&
+       test_config notes.rewriteMode overwrite &&
+       test_unconfig notes.rewriteRef &&
        echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
        GIT_NOTES_REWRITE_REF=refs/notes/commits:refs/notes/other \
                git notes copy --for-rewrite=foo &&
-       git log -1 > output &&
-       test_cmp expect output
+       git log -1 >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'GIT_NOTES_REWRITE_REF overrides config' '
-       git config notes.rewriteRef refs/notes/other &&
        git notes add -f -m"replacement note 3" HEAD^ &&
+       test_config notes.rewriteMode overwrite &&
+       test_config notes.rewriteRef refs/notes/other &&
        echo $(git rev-parse HEAD^) $(git rev-parse HEAD) |
        GIT_NOTES_REWRITE_REF= git notes copy --for-rewrite=foo &&
-       git log -1 > output &&
-       test_cmp expect output
+       git log -1 >actual &&
+       test_cmp expect actual
 '
 
 test_expect_success 'git notes copy diagnoses too many or too few parameters' '
@@ -1221,13 +1123,13 @@ test_expect_success 'git notes copy diagnoses too many or too few parameters' '
 '
 
 test_expect_success 'git notes get-ref (no overrides)' '
-       git config --unset core.notesRef &&
+       test_unconfig core.notesRef &&
        sane_unset GIT_NOTES_REF &&
        test "$(git notes get-ref)" = "refs/notes/commits"
 '
 
 test_expect_success 'git notes get-ref (core.notesRef)' '
-       git config core.notesRef refs/notes/foo &&
+       test_config core.notesRef refs/notes/foo &&
        test "$(git notes get-ref)" = "refs/notes/foo"
 '
 
@@ -1239,4 +1141,51 @@ test_expect_success 'git notes get-ref (--ref)' '
        test "$(GIT_NOTES_REF=refs/notes/bar git notes --ref=baz get-ref)" = "refs/notes/baz"
 '
 
+test_expect_success 'setup testing of empty notes' '
+       test_unconfig core.notesRef &&
+       test_commit 16th &&
+       empty_blob=$(git hash-object -w /dev/null) &&
+       echo "$empty_blob" >expect_empty
+'
+
+while read cmd
+do
+       test_expect_success "'git notes $cmd' removes empty note" "
+               test_might_fail git notes remove HEAD &&
+               MSG= git notes $cmd &&
+               test_must_fail git notes list HEAD
+       "
+
+       test_expect_success "'git notes $cmd --allow-empty' stores empty note" "
+               test_might_fail git notes remove HEAD &&
+               MSG= git notes $cmd --allow-empty &&
+               git notes list HEAD >actual &&
+               test_cmp expect_empty actual
+       "
+done <<\EOF
+add
+add -F /dev/null
+add -m ""
+add -c "$empty_blob"
+add -C "$empty_blob"
+append
+append -F /dev/null
+append -m ""
+append -c "$empty_blob"
+append -C "$empty_blob"
+edit
+EOF
+
+test_expect_success 'empty notes are displayed by git log' '
+       test_commit 17th &&
+       git log -1 >expect &&
+       cat >>expect <<-EOF &&
+
+               Notes:
+       EOF
+       git notes add -C "$empty_blob" --allow-empty &&
+       git log -1 >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 223b98433c502b03c4ba70550cb32d42a5f6295b..7c5ad086264e3d1c140da7fd996f27c1352a26a9 100755 (executable)
@@ -351,19 +351,45 @@ test_expect_success 'commit after failed cherry-pick does not add duplicated -s'
 test_expect_success 'commit after failed cherry-pick adds -s at the right place' '
        pristine_detach initial &&
        test_must_fail git cherry-pick picked &&
+
        git commit -a -s &&
-       pwd &&
-       cat <<EOF > expected &&
-picked
 
-Signed-off-by: C O Mitter <committer@example.com>
+       # Do S-o-b and Conflicts appear in the right order?
+       cat <<-\EOF >expect &&
+       Signed-off-by: C O Mitter <committer@example.com>
+       # Conflicts:
+       EOF
+       grep -e "^# Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual &&
+       test_cmp expect actual &&
+
+       cat <<-\EOF >expected &&
+       picked
 
-Conflicts:
-       foo
-EOF
+       Signed-off-by: C O Mitter <committer@example.com>
+       EOF
 
-       git show -s --pretty=format:%B > actual &&
+       git show -s --pretty=format:%B >actual &&
        test_cmp expected actual
 '
 
+test_expect_success 'commit --amend -s places the sign-off at the right place' '
+       pristine_detach initial &&
+       test_must_fail git cherry-pick picked &&
+
+       # emulate old-style conflicts block
+       mv .git/MERGE_MSG .git/MERGE_MSG+ &&
+       sed -e "/^# Conflicts:/,\$s/^# *//" <.git/MERGE_MSG+ >.git/MERGE_MSG &&
+
+       git commit -a &&
+       git commit --amend -s &&
+
+       # Do S-o-b and Conflicts appear in the right order?
+       cat <<-\EOF >expect &&
+       Signed-off-by: C O Mitter <committer@example.com>
+       Conflicts:
+       EOF
+       grep -e "^Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual &&
+       test_cmp expect actual
+'
+
 test_done
index fe274e2fb14869314dfb21d563fd2c3f367365c8..f7ff1f555d473ec1e7bd0f32d8d3c29426adc9f0 100755 (executable)
@@ -91,6 +91,13 @@ test_expect_success 'error out when attempting to add ignored ones without -f' '
        ! (git ls-files | grep "\\.ig")
 '
 
+test_expect_success 'error out when attempting to add ignored ones but add others' '
+       touch a.if &&
+       test_must_fail git add a.?? &&
+       ! (git ls-files | grep "\\.ig") &&
+       (git ls-files | grep a.if)
+'
+
 test_expect_success 'add ignored ones with -f' '
        git add -f a.?? &&
        git ls-files --error-unmatch a.ig
@@ -311,7 +318,6 @@ cat >expect.err <<\EOF
 The following paths are ignored by one of your .gitignore files:
 ignored-file
 Use -f if you really want to add them.
-fatal: no files added
 EOF
 cat >expect.out <<\EOF
 add 'track-this'
index 27e98a8f9d6c858468904542c500236b9e9f99c2..89204648965b2b6b7d7984e3398b3ef21a8d7c7e 100755 (executable)
@@ -123,10 +123,10 @@ test_expect_success \
     'git diff-index -B -M "$tree" >current'
 
 # file0 changed from regular to symlink.  file1 is very close to the preimage of file0.
-# because we break file0, file1 can become a rename of it.
+# the change does not make file0 disappear, so file1 is denoted as a copy of file0
 cat >expected <<\EOF
 :100644 120000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 67be421f88824578857624f7b3dc75e99a8a1481 T     file0
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 R     file0   file1
+:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 C     file0   file1
 EOF
 
 test_expect_success \
index 55d549fcf441be927bc43b2c41107a90aa614c2a..8c9823765e66aca886a1ec32a8ad523c1c28e1bc 100755 (executable)
@@ -76,7 +76,8 @@ test_expect_success 'moves and renames' '
 
        git diff-tree three four -r --name-status -B -M | sort >actual &&
        {
-               echo "R100      foo     bar"
+               # see -B -M (#6) in t4008
+               echo "C100      foo     bar"
                echo "T100      foo"
        } | sort >expect &&
        test_cmp expect actual
index 63e423838f1025d74b830bf84629427defdb756a..267c43bd95c9b7dbbc5991e7312deeb5527a175a 100755 (executable)
@@ -45,14 +45,29 @@ test_expect_success 'fg bg attr...' '
        color "blue bold dim ul blink reverse" "[1;2;4;5;7;34m"
 '
 
+# note that nobold and nodim are the same code (22)
+test_expect_success 'attr negation' '
+       color "nobold nodim noul noblink noreverse" "[22;24;25;27m"
+'
+
 test_expect_success 'long color specification' '
        color "254 255 bold dim ul blink reverse" "[1;2;4;5;7;38;5;254;48;5;255m"
 '
 
+test_expect_success 'absurdly long color specification' '
+       color \
+         "#ffffff #ffffff bold nobold dim nodim ul noul blink noblink reverse noreverse" \
+         "[1;2;4;5;7;22;24;25;27;38;2;255;255;255;48;2;255;255;255m"
+'
+
 test_expect_success '256 colors' '
        color "254 bold 255" "[1;38;5;254;48;5;255m"
 '
 
+test_expect_success '24-bit colors' '
+       color "#ff00ff black" "[38;2;255;0;255;40m"
+'
+
 test_expect_success '"normal" yields no color at all"' '
        color "normal black" "[40m"
 '
index 5edb79a058f407f47353041afb8e7851b066a517..306e6f39ac88e7ee4ee0fb16dee12cf999fbba1b 100755 (executable)
@@ -85,6 +85,7 @@ test_expect_success setup '
 
        git format-patch --stdout first >patch1 &&
        {
+               echo "Message-Id: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>" &&
                echo "X-Fake-Field: Line One" &&
                echo "X-Fake-Field: Line Two" &&
                echo "X-Fake-Field: Line Three" &&
@@ -536,4 +537,26 @@ test_expect_success 'am empty-file does not infloop' '
        test_i18ncmp expected actual
 '
 
+test_expect_success 'am --message-id really adds the message id' '
+       rm -fr .git/rebase-apply &&
+       git reset --hard &&
+       git checkout HEAD^ &&
+       git am --message-id patch1.eml &&
+       test_path_is_missing .git/rebase-apply &&
+       git cat-file commit HEAD | tail -n1 >actual &&
+       grep Message-Id patch1.eml >expected &&
+       test_cmp expected actual
+'
+
+test_expect_success 'am --message-id -s signs off after the message id' '
+       rm -fr .git/rebase-apply &&
+       git reset --hard &&
+       git checkout HEAD^ &&
+       git am -s --message-id patch1.eml &&
+       test_path_is_missing .git/rebase-apply &&
+       git cat-file commit HEAD | tail -n2 | head -n1 >actual &&
+       grep Message-Id patch1.eml >expected &&
+       test_cmp expected actual
+'
+
 test_done
index d01bbdc968a0fcde9eb5410793f8a22108ee6c2d..4b68bbafbe9016d66ce4f96f2058ac67640ed147 100755 (executable)
@@ -101,7 +101,7 @@ test_expect_success \
      ten=0123456789 && hundred=$ten$ten$ten$ten$ten$ten$ten$ten$ten$ten &&
      echo long filename >a/four$hundred &&
      mkdir a/bin &&
-     cp /bin/sh a/bin &&
+     test-genrandom "frotz" 500000 >a/bin/sh &&
      printf "A\$Format:%s\$O" "$SUBSTFORMAT" >a/substfile1 &&
      printf "A not substituted O" >a/substfile2 &&
      if test_have_prereq SYMLINKS; then
index 9e1ad1ca21341d449fa3ab1b896a899e51272127..60df10f46a52ea4ea33eded268beddc13fec29ea 100755 (executable)
@@ -35,6 +35,10 @@ do
                then
                        check_mailinfo $mail --no-inbody-headers
                fi
+               if test -f "$TEST_DIRECTORY"/t5100/msg$mail--message-id
+               then
+                       check_mailinfo $mail --message-id
+               fi
        '
 done
 
diff --git a/t/t5100/info0012--message-id b/t/t5100/info0012--message-id
new file mode 100644 (file)
index 0000000..ac1216f
--- /dev/null
@@ -0,0 +1,5 @@
+Author: Dmitriy Blinov
+Email: bda@mnsspb.ru
+Subject: Изменён список пакетов необходимых для сборки
+Date: Wed, 12 Nov 2008 17:54:41 +0300
+
diff --git a/t/t5100/msg0012--message-id b/t/t5100/msg0012--message-id
new file mode 100644 (file)
index 0000000..376e26e
--- /dev/null
@@ -0,0 +1,8 @@
+textlive-* исправлены на texlive-*
+docutils заменён на python-docutils
+
+Действительно, оказалось, что rest2web вытягивает за собой
+python-docutils. В то время как сам rest2web не нужен.
+
+Signed-off-by: Dmitriy Blinov <bda@mnsspb.ru>
+Message-Id: <1226501681-24923-1-git-send-email-bda@mnsspb.ru>
diff --git a/t/t5100/patch0012--message-id b/t/t5100/patch0012--message-id
new file mode 100644 (file)
index 0000000..36a0b68
--- /dev/null
@@ -0,0 +1,30 @@
+---
+ howto/build_navy.txt |    6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/howto/build_navy.txt b/howto/build_navy.txt
+index 3fd3afb..0ee807e 100644
+--- a/howto/build_navy.txt
++++ b/howto/build_navy.txt
+@@ -119,8 +119,8 @@
+    - libxv-dev
+    - libusplash-dev
+    - latex-make
+-   - textlive-lang-cyrillic
+-   - textlive-latex-extra
++   - texlive-lang-cyrillic
++   - texlive-latex-extra
+    - dia
+    - python-pyrex
+    - libtool
+@@ -128,7 +128,7 @@
+    - sox
+    - cython
+    - imagemagick
+-   - docutils
++   - python-docutils
+ #. на машине dinar: добавить свой открытый ssh-ключ в authorized_keys2 пользователя ddev
+ #. на своей машине: отредактировать /etc/sudoers (команда ``visudo``) примерно следующим образом::
+-- 
+1.5.6.5
index 0736bcbcd52a76ef3400c046e7d3558dd1a866c7..04cea97f87784bfb9a9a04fdb7341478e64fd5b6 100755 (executable)
@@ -76,8 +76,7 @@ test_expect_success 'refuse pushing rewound head without --force' '
        test "$victim_head" = "$pushed_head"
 '
 
-test_expect_success \
-        'push can be used to delete a ref' '
+test_expect_success 'push can be used to delete a ref' '
        ( cd victim && git branch extra master ) &&
        git send-pack ./victim :extra master &&
        ( cd victim &&
@@ -196,19 +195,6 @@ rewound_push_setup() {
        )
 }
 
-rewound_push_succeeded() {
-       cmp ../parent/.git/refs/heads/master .git/refs/heads/master
-}
-
-rewound_push_failed() {
-       if rewound_push_succeeded
-       then
-               false
-       else
-               true
-       fi
-}
-
 test_expect_success 'pushing explicit refspecs respects forcing' '
        rewound_push_setup &&
        parent_orig=$(cd parent && git rev-parse --verify master) &&
index f4da20aa9bf7df1b2ab1fda207b70e1913277603..85c7fecd22a37d06001398883954180a2b1a9868 100755 (executable)
@@ -1330,4 +1330,108 @@ test_expect_success 'fetch into bare respects core.logallrefupdates' '
        )
 '
 
+test_expect_success 'receive.denyCurrentBranch = updateInstead' '
+       git push testrepo master &&
+       (
+               cd testrepo &&
+               git reset --hard &&
+               git config receive.denyCurrentBranch updateInstead
+       ) &&
+       test_commit third path2 &&
+
+       # Try pushing into a repository with pristine working tree
+       git push testrepo master &&
+       (
+               cd testrepo &&
+               git update-index -q --refresh &&
+               git diff-files --quiet -- &&
+               git diff-index --quiet --cached HEAD -- &&
+               test third = "$(cat path2)" &&
+               test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
+       ) &&
+
+       # Try pushing into a repository with working tree needing a refresh
+       (
+               cd testrepo &&
+               git reset --hard HEAD^ &&
+               test $(git -C .. rev-parse HEAD^) = $(git rev-parse HEAD) &&
+               test-chmtime +100 path1
+       ) &&
+       git push testrepo master &&
+       (
+               cd testrepo &&
+               git update-index -q --refresh &&
+               git diff-files --quiet -- &&
+               git diff-index --quiet --cached HEAD -- &&
+               test_cmp ../path1 path1 &&
+               test third = "$(cat path2)" &&
+               test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
+       ) &&
+
+       # Update what is to be pushed
+       test_commit fourth path2 &&
+
+       # Try pushing into a repository with a dirty working tree
+       # (1) the working tree updated
+       (
+               cd testrepo &&
+               echo changed >path1
+       ) &&
+       test_must_fail git push testrepo master &&
+       (
+               cd testrepo &&
+               test $(git -C .. rev-parse HEAD^) = $(git rev-parse HEAD) &&
+               git diff --quiet --cached &&
+               test changed = "$(cat path1)"
+       ) &&
+
+       # (2) the index updated
+       (
+               cd testrepo &&
+               echo changed >path1 &&
+               git add path1
+       ) &&
+       test_must_fail git push testrepo master &&
+       (
+               cd testrepo &&
+               test $(git -C .. rev-parse HEAD^) = $(git rev-parse HEAD) &&
+               git diff --quiet &&
+               test changed = "$(cat path1)"
+       ) &&
+
+       # Introduce a new file in the update
+       test_commit fifth path3 &&
+
+       # (3) the working tree has an untracked file that would interfere
+       (
+               cd testrepo &&
+               git reset --hard &&
+               echo changed >path3
+       ) &&
+       test_must_fail git push testrepo master &&
+       (
+               cd testrepo &&
+               test $(git -C .. rev-parse HEAD^^) = $(git rev-parse HEAD) &&
+               git diff --quiet &&
+               git diff --quiet --cached &&
+               test changed = "$(cat path3)"
+       ) &&
+
+       # (4) the target changes to what gets pushed but it still is a change
+       (
+               cd testrepo &&
+               git reset --hard &&
+               echo fifth >path3 &&
+               git add path3
+       ) &&
+       test_must_fail git push testrepo master &&
+       (
+               cd testrepo &&
+               test $(git -C .. rev-parse HEAD^^) = $(git rev-parse HEAD) &&
+               git diff --quiet &&
+               test fifth = "$(cat path3)"
+       )
+
+'
+
 test_done
index edea9f957e4034098faeb51dec59e9661af8e29e..207899a99faa4ff8fb4d7226e930ba1e9803dc74 100755 (executable)
@@ -26,4 +26,37 @@ test_expect_success 'suffix ref is ignored during fetch' '
        test_cmp expect actual
 '
 
+test_expect_success 'try to create repo with absurdly long refname' '
+       ref240=$_z40/$_z40/$_z40/$_z40/$_z40/$_z40 &&
+       ref1440=$ref240/$ref240/$ref240/$ref240/$ref240/$ref240 &&
+       git init long &&
+       (
+               cd long &&
+               test_commit long &&
+               test_commit master
+       ) &&
+       if git -C long update-ref refs/heads/$ref1440 long; then
+               test_set_prereq LONG_REF
+       else
+               echo >&2 "long refs not supported"
+       fi
+'
+
+test_expect_success LONG_REF 'fetch handles extremely long refname' '
+       git fetch long refs/heads/*:refs/remotes/long/* &&
+       cat >expect <<-\EOF &&
+       long
+       master
+       EOF
+       git for-each-ref --format="%(subject)" refs/remotes/long >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success LONG_REF 'push handles extremely long refname' '
+       git push long :refs/heads/$ref1440 &&
+       git -C long for-each-ref --format="%(subject)" refs/heads >actual &&
+       echo master >expect &&
+       test_cmp expect actual
+'
+
 test_done
index 6537911a4300656706c995226b2f0444a760bae0..3e783fc450d21c8de6fae2cb3677e9eaebacf927 100755 (executable)
@@ -198,4 +198,21 @@ test_expect_success 'clone using repo pointed at by gitfile as reference' '
        test_cmp expected "$base_dir/O/.git/objects/info/alternates"
 '
 
+test_expect_success 'clone and dissociate from reference' '
+       git init P &&
+       (
+               cd P && test_commit one
+       ) &&
+       git clone P Q &&
+       (
+               cd Q && test_commit two
+       ) &&
+       git clone --no-local --reference=P Q R &&
+       git clone --no-local --reference=P --dissociate Q S &&
+       # removing the reference P would corrupt R but not S
+       rm -fr P &&
+       test_must_fail git -C R fsck &&
+       git -C S fsck
+'
+
 test_done
index 796e9f79eadfdf5b641d429e2083dd7d0c27332c..35c805a44e817c637c667b1d1d14d97b4ee46803 100755 (executable)
@@ -1081,7 +1081,7 @@ test_expect_success GPG \
 get_tag_header rfc1991-signed-tag $commit commit $time >expect
 echo "RFC1991 signed tag" >>expect
 echo '-----BEGIN PGP MESSAGE-----' >>expect
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
        'creating a signed tag with rfc1991' '
        echo "rfc1991" >gpghome/gpg.conf &&
        git tag -s -m "RFC1991 signed tag" rfc1991-signed-tag $commit &&
@@ -1095,7 +1095,7 @@ cp "$1" actual
 EOF
 chmod +x fakeeditor
 
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
        'reediting a signed tag body omits signature' '
        echo "rfc1991" >gpghome/gpg.conf &&
        echo "RFC1991 signed tag" >expect &&
@@ -1103,13 +1103,13 @@ test_expect_success GPG \
        test_cmp expect actual
 '
 
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
        'verifying rfc1991 signature' '
        echo "rfc1991" >gpghome/gpg.conf &&
        git tag -v rfc1991-signed-tag
 '
 
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
        'list tag with rfc1991 signature' '
        echo "rfc1991" >gpghome/gpg.conf &&
        echo "rfc1991-signed-tag RFC1991 signed tag" >expect &&
@@ -1123,12 +1123,12 @@ test_expect_success GPG \
 
 rm -f gpghome/gpg.conf
 
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
        'verifying rfc1991 signature without --rfc1991' '
        git tag -v rfc1991-signed-tag
 '
 
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
        'list tag with rfc1991 signature without --rfc1991' '
        echo "rfc1991-signed-tag RFC1991 signed tag" >expect &&
        git tag -l -n1 rfc1991-signed-tag >actual &&
@@ -1139,7 +1139,7 @@ test_expect_success GPG \
        test_cmp expect actual
 '
 
-test_expect_success GPG \
+test_expect_success GPG,RFC1991 \
        'reediting a signed tag body omits signature' '
        echo "RFC1991 signed tag" >expect &&
        GIT_EDITOR=./fakeeditor git tag -f -s rfc1991-signed-tag $commit &&
index 1efb88051af0d783dff554337d565547f946d06e..bd0ab4675089b54c336ccc9590c4b65bbd37138d 100755 (executable)
@@ -213,7 +213,7 @@ test_expect_success 'with 2 files arguments' '
 '
 
 test_expect_success 'with message that has comments' '
-       cat basic_message >>message_with_comments &&
+       cat basic_message >message_with_comments &&
        sed -e "s/ Z\$/ /" >>message_with_comments <<-\EOF &&
                # comment
 
@@ -232,12 +232,44 @@ test_expect_success 'with message that has comments' '
 
                Reviewed-by: Johan
                Cc: Peff
+               # last comment
+
        EOF
        cat basic_patch >>expected &&
        git interpret-trailers --trim-empty --trailer "Cc: Peff" message_with_comments >actual &&
        test_cmp expected actual
 '
 
+test_expect_success 'with message that has an old style conflict block' '
+       cat basic_message >message_with_comments &&
+       sed -e "s/ Z\$/ /" >>message_with_comments <<-\EOF &&
+               # comment
+
+               # other comment
+               Cc: Z
+               # yet another comment
+               Reviewed-by: Johan
+               Reviewed-by: Z
+               # last comment
+
+               Conflicts:
+
+       EOF
+       cat basic_message >expected &&
+       cat >>expected <<-\EOF &&
+               # comment
+
+               Reviewed-by: Johan
+               Cc: Peff
+               # last comment
+
+               Conflicts:
+
+       EOF
+       git interpret-trailers --trim-empty --trailer "Cc: Peff" message_with_comments >actual &&
+       test_cmp expected actual
+'
+
 test_expect_success 'with commit complex message and trailer args' '
        cat complex_message_body >expected &&
        sed -e "s/ Z\$/ /" >>expected <<-\EOF &&
index 19a3ced600a20d805d430533b275a8fa4269b835..af6a3e8904ab1d953b359707de1e0c9a09b3ce1f 100755 (executable)
@@ -6,35 +6,37 @@ test_description='git send-email'
 # May be altered later in the test
 PREREQ="PERL"
 
-test_expect_success $PREREQ \
-    'prepare reference tree' \
-    'echo "1A quick brown fox jumps over the" >file &&
-     echo "lazy dog" >>file &&
-     git add file &&
-     GIT_AUTHOR_NAME="A" git commit -a -m "Initial."'
-
-test_expect_success $PREREQ \
-    'Setup helper tool' \
-    '(echo "#!$SHELL_PATH"
-      echo shift
-      echo output=1
-      echo "while test -f commandline\$output; do output=\$((\$output+1)); done"
-      echo for a
-      echo do
-      echo "  echo \"!\$a!\""
-      echo "done >commandline\$output"
-      echo "cat > msgtxt\$output"
-      ) >fake.sendmail &&
-     chmod +x ./fake.sendmail &&
-     git add fake.sendmail &&
-     GIT_AUTHOR_NAME="A" git commit -a -m "Second."'
-
-clean_fake_sendmail() {
+test_expect_success $PREREQ 'prepare reference tree' '
+       echo "1A quick brown fox jumps over the" >file &&
+       echo "lazy dog" >>file &&
+       git add file &&
+       GIT_AUTHOR_NAME="A" git commit -a -m "Initial."
+'
+
+test_expect_success $PREREQ 'Setup helper tool' '
+       write_script fake.sendmail <<-\EOF &&
+       shift
+       output=1
+       while test -f commandline$output
+       do
+               output=$(($output+1))
+       done
+       for a
+       do
+               echo "!$a!"
+       done >commandline$output
+       cat >"msgtxt$output"
+       EOF
+       git add fake.sendmail &&
+       GIT_AUTHOR_NAME="A" git commit -a -m "Second."
+'
+
+clean_fake_sendmail () {
        rm -f commandline* msgtxt*
 }
 
 test_expect_success $PREREQ 'Extract patches' '
-    patches=`git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1`
+       patches=`git format-patch -s --cc="One <one@example.com>" --cc=two@example.com -n HEAD^1`
 '
 
 # Test no confirm early to ensure remaining tests will not hang
@@ -47,9 +49,9 @@ test_no_confirm () {
                --to=nobody@example.com \
                --smtp-server="$(pwd)/fake.sendmail" \
                $@ \
-               $patches > stdout &&
+               $patches >stdout &&
                test_must_fail grep "Send this email" stdout &&
-               > no_confirm_okay
+               >no_confirm_okay
 }
 
 # Exit immediately to prevent hang if a no-confirm test fails
@@ -82,61 +84,61 @@ test_expect_success $PREREQ 'No confirm with sendemail.confirm=never' '
 '
 
 test_expect_success $PREREQ 'Send patches' '
-     git send-email --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
+       git send-email --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
 '
 
 test_expect_success $PREREQ 'setup expect' '
-cat >expected <<\EOF
-!nobody@example.com!
-!author@example.com!
-!one@example.com!
-!two@example.com!
-EOF
+       cat >expected <<-\EOF
+       !nobody@example.com!
+       !author@example.com!
+       !one@example.com!
+       !two@example.com!
+       EOF
 '
 
-test_expect_success $PREREQ \
-    'Verify commandline' \
-    'test_cmp expected commandline1'
+test_expect_success $PREREQ 'Verify commandline' '
+       test_cmp expected commandline1
+'
 
 test_expect_success $PREREQ 'Send patches with --envelope-sender' '
-    clean_fake_sendmail &&
-     git send-email --envelope-sender="Patch Contributor <patch@example.com>" --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
+       clean_fake_sendmail &&
+       git send-email --envelope-sender="Patch Contributor <patch@example.com>" --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
 '
 
 test_expect_success $PREREQ 'setup expect' '
-cat >expected <<\EOF
-!patch@example.com!
-!-i!
-!nobody@example.com!
-!author@example.com!
-!one@example.com!
-!two@example.com!
-EOF
+       cat >expected <<-\EOF
+       !patch@example.com!
+       !-i!
+       !nobody@example.com!
+       !author@example.com!
+       !one@example.com!
+       !two@example.com!
+       EOF
 '
 
-test_expect_success $PREREQ \
-    'Verify commandline' \
-    'test_cmp expected commandline1'
+test_expect_success $PREREQ 'Verify commandline' '
+       test_cmp expected commandline1
+'
 
 test_expect_success $PREREQ 'Send patches with --envelope-sender=auto' '
-    clean_fake_sendmail &&
-     git send-email --envelope-sender=auto --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
+       clean_fake_sendmail &&
+       git send-email --envelope-sender=auto --suppress-cc=sob --from="Example <nobody@example.com>" --to=nobody@example.com --smtp-server="$(pwd)/fake.sendmail" $patches 2>errors
 '
 
 test_expect_success $PREREQ 'setup expect' '
-cat >expected <<\EOF
-!nobody@example.com!
-!-i!
-!nobody@example.com!
-!author@example.com!
-!one@example.com!
-!two@example.com!
-EOF
+       cat >expected <<-\EOF
+       !nobody@example.com!
+       !-i!
+       !nobody@example.com!
+       !author@example.com!
+       !one@example.com!
+       !two@example.com!
+       EOF
 '
 
-test_expect_success $PREREQ \
-    'Verify commandline' \
-    'test_cmp expected commandline1'
+test_expect_success $PREREQ 'Verify commandline' '
+       test_cmp expected commandline1
+'
 
 test_expect_success $PREREQ 'setup expect' "
 cat >expected-show-all-headers <<\EOF
@@ -240,6 +242,13 @@ test_expect_success $PREREQ 'non-ascii self name is suppressed' "
                'non_ascii_self_suppressed'
 "
 
+# This name is long enough to force format-patch to split it into multiple
+# encoded-words, assuming it uses UTF-8 with the "Q" encoding.
+test_expect_success $PREREQ 'long non-ascii self name is suppressed' "
+       test_suppress_self_quoted 'Ƒüñníęř €. Nâṁé' 'odd_?=mail@example.com' \
+               'long_non_ascii_self_suppressed'
+"
+
 test_expect_success $PREREQ 'sanitized self name is suppressed' "
        test_suppress_self_unquoted '\"A U. Thor\"' 'author@example.com' \
                'self_name_sanitized_suppressed'
@@ -307,11 +316,9 @@ test_expect_success $PREREQ 'tocmd works' '
        clean_fake_sendmail &&
        cp $patches tocmd.patch &&
        echo tocmd--tocmd@example.com >>tocmd.patch &&
-       {
-         echo "#!$SHELL_PATH"
-         echo sed -n -e s/^tocmd--//p \"\$1\"
-       } > tocmd-sed &&
-       chmod +x tocmd-sed &&
+       write_script tocmd-sed <<-\EOF &&
+       sed -n -e "s/^tocmd--//p" "$1"
+       EOF
        git send-email \
                --from="Example <nobody@example.com>" \
                --to-cmd=./tocmd-sed \
@@ -325,11 +332,9 @@ test_expect_success $PREREQ 'cccmd works' '
        clean_fake_sendmail &&
        cp $patches cccmd.patch &&
        echo "cccmd--  cccmd@example.com" >>cccmd.patch &&
-       {
-         echo "#!$SHELL_PATH"
-         echo sed -n -e s/^cccmd--//p \"\$1\"
-       } > cccmd-sed &&
-       chmod +x cccmd-sed &&
+       write_script cccmd-sed <<-\EOF &&
+       sed -n -e "s/^cccmd--//p" "$1"
+       EOF
        git send-email \
                --from="Example <nobody@example.com>" \
                --to=nobody@example.com \
@@ -367,7 +372,7 @@ test_expect_success $PREREQ 'Author From: in message body' '
                --to=nobody@example.com \
                --smtp-server="$(pwd)/fake.sendmail" \
                $patches &&
-       sed "1,/^\$/d" < msgtxt1 > msgbody1 &&
+       sed "1,/^\$/d" <msgtxt1 >msgbody1 &&
        grep "From: A <author@example.com>" msgbody1
 '
 
@@ -378,7 +383,7 @@ test_expect_success $PREREQ 'Author From: not in message body' '
                --to=nobody@example.com \
                --smtp-server="$(pwd)/fake.sendmail" \
                $patches &&
-       sed "1,/^\$/d" < msgtxt1 > msgbody1 &&
+       sed "1,/^\$/d" <msgtxt1 >msgbody1 &&
        ! grep "From: A <author@example.com>" msgbody1
 '
 
@@ -459,10 +464,9 @@ test_expect_success $PREREQ 'In-Reply-To with --chain-reply-to' '
 '
 
 test_expect_success $PREREQ 'setup fake editor' '
-       (echo "#!$SHELL_PATH" &&
-        echo "echo fake edit >>\"\$1\""
-       ) >fake-editor &&
-       chmod +x fake-editor
+       write_script fake-editor <<-\EOF
+       echo fake edit >>"$1"
+       EOF
 '
 
 test_set_editor "$(pwd)/fake-editor"
@@ -598,8 +602,9 @@ EOF
 "
 
 test_expect_success $PREREQ 'sendemail.cccmd' '
-       echo echo cc-cmd@example.com > cccmd &&
-       chmod +x cccmd &&
+       write_script cccmd <<-\EOF &&
+       echo cc-cmd@example.com
+       EOF
        git config sendemail.cccmd ./cccmd &&
        test_suppression cccmd
 '
@@ -792,7 +797,7 @@ test_confirm () {
                --from="Example <nobody@example.com>" \
                --to=nobody@example.com \
                --smtp-server="$(pwd)/fake.sendmail" \
-               $@ $patches > stdout &&
+               $@ $patches >stdout &&
        grep "Send this email" stdout
 }
 
@@ -840,7 +845,7 @@ test_expect_success $PREREQ 'confirm detects EOF (inform assumes y)' '
                        --from="Example <nobody@example.com>" \
                        --to=nobody@example.com \
                        --smtp-server="$(pwd)/fake.sendmail" \
-                       outdir/*.patch < /dev/null
+                       outdir/*.patch </dev/null
        ret="$?"
        git config sendemail.confirm ${CONFIRM:-never}
        test $ret = "0"
@@ -855,7 +860,7 @@ test_expect_success $PREREQ 'confirm detects EOF (auto causes failure)' '
                        --from="Example <nobody@example.com>" \
                        --to=nobody@example.com \
                        --smtp-server="$(pwd)/fake.sendmail" \
-                       $patches < /dev/null
+                       $patches </dev/null
        ret="$?"
        git config sendemail.confirm ${CONFIRM:-never}
        test $ret = "0"
@@ -891,39 +896,39 @@ test_expect_success $PREREQ 'utf8 Cc is rfc2047 encoded' '
 
 test_expect_success $PREREQ '--compose adds MIME for utf8 body' '
        clean_fake_sendmail &&
-       (echo "#!$SHELL_PATH" &&
-        echo "echo utf8 body: àéìöú >>\"\$1\""
-       ) >fake-editor-utf8 &&
-       chmod +x fake-editor-utf8 &&
-         GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
-         git send-email \
-         --compose --subject foo \
-         --from="Example <nobody@example.com>" \
-         --to=nobody@example.com \
-         --smtp-server="$(pwd)/fake.sendmail" \
-         $patches &&
+       write_script fake-editor-utf8 <<-\EOF &&
+       echo "utf8 body: àéìöú" >>"$1"
+       EOF
+       GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
+       git send-email \
+               --compose --subject foo \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               $patches &&
        grep "^utf8 body" msgtxt1 &&
        grep "^Content-Type: text/plain; charset=UTF-8" msgtxt1
 '
 
 test_expect_success $PREREQ '--compose respects user mime type' '
        clean_fake_sendmail &&
-       (echo "#!$SHELL_PATH" &&
-        echo "(echo MIME-Version: 1.0"
-        echo " echo Content-Type: text/plain\\; charset=iso-8859-1"
-        echo " echo Content-Transfer-Encoding: 8bit"
-        echo " echo Subject: foo"
-        echo " echo "
-        echo " echo utf8 body: àéìöú) >\"\$1\""
-       ) >fake-editor-utf8-mime &&
-       chmod +x fake-editor-utf8-mime &&
-         GIT_EDITOR="\"$(pwd)/fake-editor-utf8-mime\"" \
-         git send-email \
-         --compose --subject foo \
-         --from="Example <nobody@example.com>" \
-         --to=nobody@example.com \
-         --smtp-server="$(pwd)/fake.sendmail" \
-         $patches &&
+       write_script fake-editor-utf8-mime <<-\EOF &&
+       cat >"$1" <<-\EOM
+       MIME-Version: 1.0
+       Content-Type: text/plain; charset=iso-8859-1
+       Content-Transfer-Encoding: 8bit
+       Subject: foo
+
+       utf8 body: àéìöú
+       EOM
+       EOF
+       GIT_EDITOR="\"$(pwd)/fake-editor-utf8-mime\"" \
+       git send-email \
+               --compose --subject foo \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               $patches &&
        grep "^utf8 body" msgtxt1 &&
        grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1 &&
        ! grep "^Content-Type: text/plain; charset=UTF-8" msgtxt1
@@ -931,13 +936,13 @@ test_expect_success $PREREQ '--compose respects user mime type' '
 
 test_expect_success $PREREQ '--compose adds MIME for utf8 subject' '
        clean_fake_sendmail &&
-         GIT_EDITOR="\"$(pwd)/fake-editor\"" \
-         git send-email \
-         --compose --subject utf8-sübjëct \
-         --from="Example <nobody@example.com>" \
-         --to=nobody@example.com \
-         --smtp-server="$(pwd)/fake.sendmail" \
-         $patches &&
+       GIT_EDITOR="\"$(pwd)/fake-editor\"" \
+       git send-email \
+               --compose --subject utf8-sübjëct \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               $patches &&
        grep "^fake edit" msgtxt1 &&
        grep "^Subject: =?UTF-8?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1
 '
@@ -949,9 +954,9 @@ test_expect_success $PREREQ 'utf8 author is correctly passed on' '
        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 &&
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               funny_name.patch &&
        grep "^From: Füñný Nâmé <odd_?=mail@example.com>" msgtxt1
 '
 
@@ -962,9 +967,9 @@ test_expect_success $PREREQ 'utf8 sender is not duplicated' '
        git commit --amend --author "Füñný Nâmé <odd_?=mail@example.com>" &&
        git format-patch --stdout -1 >funny_name.patch &&
        git send-email --from="Füñný Nâmé <odd_?=mail@example.com>" \
-         --to=nobody@example.com \
-         --smtp-server="$(pwd)/fake.sendmail" \
-         funny_name.patch &&
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               funny_name.patch &&
        grep "^From: " msgtxt1 >msgfrom &&
        test_line_count = 1 msgfrom
 '
@@ -972,35 +977,33 @@ test_expect_success $PREREQ 'utf8 sender is not duplicated' '
 test_expect_success $PREREQ 'sendemail.composeencoding works' '
        clean_fake_sendmail &&
        git config sendemail.composeencoding iso-8859-1 &&
-       (echo "#!$SHELL_PATH" &&
-        echo "echo utf8 body: àéìöú >>\"\$1\""
-       ) >fake-editor-utf8 &&
-       chmod +x fake-editor-utf8 &&
-         GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
-         git send-email \
-         --compose --subject foo \
-         --from="Example <nobody@example.com>" \
-         --to=nobody@example.com \
-         --smtp-server="$(pwd)/fake.sendmail" \
-         $patches &&
+       write_script fake-editor-utf8 <<-\EOF &&
+       echo "utf8 body: àéìöú" >>"$1"
+       EOF
+       GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
+       git send-email \
+               --compose --subject foo \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               $patches &&
        grep "^utf8 body" msgtxt1 &&
        grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1
 '
 
 test_expect_success $PREREQ '--compose-encoding works' '
        clean_fake_sendmail &&
-       (echo "#!$SHELL_PATH" &&
-        echo "echo utf8 body: àéìöú >>\"\$1\""
-       ) >fake-editor-utf8 &&
-       chmod +x fake-editor-utf8 &&
-         GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
-         git send-email \
-         --compose-encoding iso-8859-1 \
-         --compose --subject foo \
-         --from="Example <nobody@example.com>" \
-         --to=nobody@example.com \
-         --smtp-server="$(pwd)/fake.sendmail" \
-         $patches &&
+       write_script fake-editor-utf8 <<-\EOF &&
+       echo "utf8 body: àéìöú" >>"$1"
+       EOF
+       GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
+       git send-email \
+               --compose-encoding iso-8859-1 \
+               --compose --subject foo \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               $patches &&
        grep "^utf8 body" msgtxt1 &&
        grep "^Content-Type: text/plain; charset=iso-8859-1" msgtxt1
 '
@@ -1008,38 +1011,37 @@ test_expect_success $PREREQ '--compose-encoding works' '
 test_expect_success $PREREQ '--compose-encoding overrides sendemail.composeencoding' '
        clean_fake_sendmail &&
        git config sendemail.composeencoding iso-8859-1 &&
-       (echo "#!$SHELL_PATH" &&
-        echo "echo utf8 body: àéìöú >>\"\$1\""
-       ) >fake-editor-utf8 &&
-       chmod +x fake-editor-utf8 &&
-         GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
-         git send-email \
-         --compose-encoding iso-8859-2 \
-         --compose --subject foo \
-         --from="Example <nobody@example.com>" \
-         --to=nobody@example.com \
-         --smtp-server="$(pwd)/fake.sendmail" \
-         $patches &&
+       write_script fake-editor-utf8 <<-\EOF &&
+       echo "utf8 body: àéìöú" >>"$1"
+       EOF
+       GIT_EDITOR="\"$(pwd)/fake-editor-utf8\"" \
+       git send-email \
+               --compose-encoding iso-8859-2 \
+               --compose --subject foo \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               $patches &&
        grep "^utf8 body" msgtxt1 &&
        grep "^Content-Type: text/plain; charset=iso-8859-2" msgtxt1
 '
 
 test_expect_success $PREREQ '--compose-encoding adds correct MIME for subject' '
        clean_fake_sendmail &&
-         GIT_EDITOR="\"$(pwd)/fake-editor\"" \
-         git send-email \
-         --compose-encoding iso-8859-2 \
-         --compose --subject utf8-sübjëct \
-         --from="Example <nobody@example.com>" \
-         --to=nobody@example.com \
-         --smtp-server="$(pwd)/fake.sendmail" \
-         $patches &&
+       GIT_EDITOR="\"$(pwd)/fake-editor\"" \
+       git send-email \
+               --compose-encoding iso-8859-2 \
+               --compose --subject utf8-sübjëct \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               $patches &&
        grep "^fake edit" msgtxt1 &&
        grep "^Subject: =?iso-8859-2?q?utf8-s=C3=BCbj=C3=ABct?=" msgtxt1
 '
 
 test_expect_success $PREREQ 'detects ambiguous reference/file conflict' '
-       echo master > master &&
+       echo master >master &&
        git add master &&
        git commit -m"add master" &&
        test_must_fail git send-email --dry-run master 2>errors &&
@@ -1050,10 +1052,10 @@ test_expect_success $PREREQ 'feed two files' '
        rm -fr outdir &&
        git format-patch -2 -o outdir &&
        git send-email \
-       --dry-run \
-       --from="Example <nobody@example.com>" \
-       --to=nobody@example.com \
-       outdir/000?-*.patch 2>errors >out &&
+               --dry-run \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               outdir/000?-*.patch 2>errors >out &&
        grep "^Subject: " out >subjects &&
        test "z$(sed -n -e 1p subjects)" = "zSubject: [PATCH 1/2] Second." &&
        test "z$(sed -n -e 2p subjects)" = "zSubject: [PATCH 2/2] add master"
@@ -1197,7 +1199,7 @@ test_expect_success $PREREQ 'To headers from files reset each patch' '
 '
 
 test_expect_success $PREREQ 'setup expect' '
-cat >email-using-8bit <<EOF
+cat >email-using-8bit <<\EOF
 From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
 Message-Id: <bogus-message-id@example.com>
 From: author@example.com
@@ -1209,9 +1211,7 @@ EOF
 '
 
 test_expect_success $PREREQ 'setup expect' '
-cat >expected <<EOF
-Subject: subject goes here
-EOF
+       echo "Subject: subject goes here" >expected
 '
 
 test_expect_success $PREREQ 'ASCII subject is not RFC2047 quoted' '
@@ -1226,11 +1226,11 @@ test_expect_success $PREREQ 'ASCII subject is not RFC2047 quoted' '
 '
 
 test_expect_success $PREREQ 'setup expect' '
-cat >content-type-decl <<EOF
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-EOF
+       cat >content-type-decl <<-\EOF
+       MIME-Version: 1.0
+       Content-Type: text/plain; charset=UTF-8
+       Content-Transfer-Encoding: 8bit
+       EOF
 '
 
 test_expect_success $PREREQ 'asks about and fixes 8bit encodings' '
@@ -1270,21 +1270,21 @@ test_expect_success $PREREQ '--8bit-encoding overrides sendemail.8bitEncoding' '
 '
 
 test_expect_success $PREREQ 'setup expect' '
-cat >email-using-8bit <<EOF
-From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
-Message-Id: <bogus-message-id@example.com>
-From: author@example.com
-Date: Sat, 12 Jun 2010 15:53:58 +0200
-Subject: Dieser Betreff enthält auch einen Umlaut!
-
-Nothing to see here.
-EOF
+       cat >email-using-8bit <<-\EOF
+       From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
+       Message-Id: <bogus-message-id@example.com>
+       From: author@example.com
+       Date: Sat, 12 Jun 2010 15:53:58 +0200
+       Subject: Dieser Betreff enthält auch einen Umlaut!
+
+       Nothing to see here.
+       EOF
 '
 
 test_expect_success $PREREQ 'setup expect' '
-cat >expected <<EOF
-Subject: =?UTF-8?q?Dieser=20Betreff=20enth=C3=A4lt=20auch=20einen=20Umlaut!?=
-EOF
+       cat >expected <<-\EOF
+       Subject: =?UTF-8?q?Dieser=20Betreff=20enth=C3=A4lt=20auch=20einen=20Umlaut!?=
+       EOF
 '
 
 test_expect_success $PREREQ '--8bit-encoding also treats subject' '
@@ -1298,6 +1298,163 @@ test_expect_success $PREREQ '--8bit-encoding also treats subject' '
        test_cmp expected actual
 '
 
+test_expect_success $PREREQ 'setup expect' '
+       cat >email-using-8bit <<-\EOF
+       From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
+       Message-Id: <bogus-message-id@example.com>
+       From: A U Thor <author@example.com>
+       Date: Sat, 12 Jun 2010 15:53:58 +0200
+       Content-Type: text/plain; charset=UTF-8
+       Subject: Nothing to see here.
+
+       Dieser Betreff enthält auch einen Umlaut!
+       EOF
+'
+
+test_expect_success $PREREQ 'sendemail.transferencoding=7bit fails on 8bit data' '
+       clean_fake_sendmail &&
+       git config sendemail.transferEncoding 7bit &&
+       test_must_fail git send-email \
+               --transfer-encoding=7bit \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               email-using-8bit \
+               2>errors >out &&
+       grep "cannot send message as 7bit" errors &&
+       test -z "$(ls msgtxt*)"
+'
+
+test_expect_success $PREREQ '--transfer-encoding overrides sendemail.transferEncoding' '
+       clean_fake_sendmail &&
+       git config sendemail.transferEncoding 8bit
+       test_must_fail git send-email \
+               --transfer-encoding=7bit \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               email-using-8bit \
+               2>errors >out &&
+       grep "cannot send message as 7bit" errors &&
+       test -z "$(ls msgtxt*)"
+'
+
+test_expect_success $PREREQ 'sendemail.transferencoding=8bit' '
+       clean_fake_sendmail &&
+       git send-email \
+               --transfer-encoding=8bit \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               email-using-8bit \
+               2>errors >out &&
+       sed '1,/^$/d' msgtxt1 >actual &&
+       sed '1,/^$/d' email-using-8bit >expected &&
+       test_cmp expected actual
+'
+
+test_expect_success $PREREQ 'setup expect' '
+       cat >expected <<-\EOF
+       Dieser Betreff enth=C3=A4lt auch einen Umlaut!
+       EOF
+'
+
+test_expect_success $PREREQ '8-bit and sendemail.transferencoding=quoted-printable' '
+       clean_fake_sendmail &&
+       git send-email \
+               --transfer-encoding=quoted-printable \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               email-using-8bit \
+               2>errors >out &&
+       sed '1,/^$/d' msgtxt1 >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success $PREREQ 'setup expect' '
+       cat >expected <<-\EOF
+       RGllc2VyIEJldHJlZmYgZW50aMOkbHQgYXVjaCBlaW5lbiBVbWxhdXQhCg==
+       EOF
+'
+
+test_expect_success $PREREQ '8-bit and sendemail.transferencoding=base64' '
+       clean_fake_sendmail &&
+       git send-email \
+               --transfer-encoding=base64 \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               email-using-8bit \
+               2>errors >out &&
+       sed '1,/^$/d' msgtxt1 >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success $PREREQ 'setup expect' '
+       cat >email-using-qp <<-\EOF
+       From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
+       Message-Id: <bogus-message-id@example.com>
+       From: A U Thor <author@example.com>
+       Date: Sat, 12 Jun 2010 15:53:58 +0200
+       MIME-Version: 1.0
+       Content-Transfer-Encoding: quoted-printable
+       Content-Type: text/plain; charset=UTF-8
+       Subject: Nothing to see here.
+
+       Dieser Betreff enth=C3=A4lt auch einen Umlaut!
+       EOF
+'
+
+test_expect_success $PREREQ 'convert from quoted-printable to base64' '
+       clean_fake_sendmail &&
+       git send-email \
+               --transfer-encoding=base64 \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               email-using-qp \
+               2>errors >out &&
+       sed '1,/^$/d' msgtxt1 >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success $PREREQ 'setup expect' "
+tr -d '\\015' | tr '%' '\\015' >email-using-crlf <<EOF
+From fe6ecc66ece37198fe5db91fa2fc41d9f4fe5cc4 Mon Sep 17 00:00:00 2001
+Message-Id: <bogus-message-id@example.com>
+From: A U Thor <author@example.com>
+Date: Sat, 12 Jun 2010 15:53:58 +0200
+Content-Type: text/plain; charset=UTF-8
+Subject: Nothing to see here.
+
+Look, I have a CRLF and an = sign!%
+EOF
+"
+
+test_expect_success $PREREQ 'setup expect' '
+       cat >expected <<-\EOF
+       Look, I have a CRLF and an =3D sign!=0D
+       EOF
+'
+
+test_expect_success $PREREQ 'CRLF and sendemail.transferencoding=quoted-printable' '
+       clean_fake_sendmail &&
+       git send-email \
+               --transfer-encoding=quoted-printable \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               email-using-crlf \
+               2>errors >out &&
+       sed '1,/^$/d' msgtxt1 >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success $PREREQ 'setup expect' '
+       cat >expected <<-\EOF
+       TG9vaywgSSBoYXZlIGEgQ1JMRiBhbmQgYW4gPSBzaWduIQ0K
+       EOF
+'
+
+test_expect_success $PREREQ 'CRLF and sendemail.transferencoding=base64' '
+       clean_fake_sendmail &&
+       git send-email \
+               --transfer-encoding=base64 \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               email-using-crlf \
+               2>errors >out &&
+       sed '1,/^$/d' msgtxt1 >actual &&
+       test_cmp expected actual
+'
+
+
 # Note that the patches in this test are deliberately out of order; we
 # want to make sure it works even if the cover-letter is not in the
 # first mail.
@@ -1306,13 +1463,13 @@ test_expect_success $PREREQ 'refusing to send cover letter template' '
        rm -fr outdir &&
        git format-patch --cover-letter -2 -o outdir &&
        test_must_fail git send-email \
-         --from="Example <nobody@example.com>" \
-         --to=nobody@example.com \
-         --smtp-server="$(pwd)/fake.sendmail" \
-         outdir/0002-*.patch \
-         outdir/0000-*.patch \
-         outdir/0001-*.patch \
-         2>errors >out &&
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               outdir/0002-*.patch \
+               outdir/0000-*.patch \
+               outdir/0001-*.patch \
+               2>errors >out &&
        grep "SUBJECT HERE" errors &&
        test -z "$(ls msgtxt*)"
 '
@@ -1322,14 +1479,14 @@ test_expect_success $PREREQ '--force sends cover letter template anyway' '
        rm -fr outdir &&
        git format-patch --cover-letter -2 -o outdir &&
        git send-email \
-         --force \
-         --from="Example <nobody@example.com>" \
-         --to=nobody@example.com \
-         --smtp-server="$(pwd)/fake.sendmail" \
-         outdir/0002-*.patch \
-         outdir/0000-*.patch \
-         outdir/0001-*.patch \
-         2>errors >out &&
+               --force \
+               --from="Example <nobody@example.com>" \
+               --to=nobody@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               outdir/0002-*.patch \
+               outdir/0000-*.patch \
+               outdir/0001-*.patch \
+               2>errors >out &&
        ! grep "SUBJECT HERE" errors &&
        test -n "$(ls msgtxt*)"
 '
@@ -1344,15 +1501,15 @@ test_cover_addresses () {
        mv $cover cover-to-edit.patch &&
        perl -pe "s/^From:/$header: extra\@address.com\nFrom:/" cover-to-edit.patch >"$cover" &&
        git send-email \
-         --force \
-         --from="Example <nobody@example.com>" \
-         --no-to --no-cc \
-         "$@" \
-         --smtp-server="$(pwd)/fake.sendmail" \
-         outdir/0000-*.patch \
-         outdir/0001-*.patch \
-         outdir/0002-*.patch \
-         2>errors >out &&
+               --force \
+               --from="Example <nobody@example.com>" \
+               --no-to --no-cc \
+               "$@" \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               outdir/0000-*.patch \
+               outdir/0001-*.patch \
+               outdir/0002-*.patch \
+               2>errors >out &&
        grep "^$header: extra@address.com" msgtxt1 >to1 &&
        grep "^$header: extra@address.com" msgtxt2 >to2 &&
        grep "^$header: extra@address.com" msgtxt3 >to3 &&
@@ -1385,11 +1542,11 @@ test_expect_success $PREREQ 'sendemail.aliasfiletype=mailrc' '
        git config --replace-all sendemail.aliasesfile "$(pwd)/.mailrc" &&
        git config sendemail.aliasfiletype mailrc &&
        git send-email \
-         --from="Example <nobody@example.com>" \
-         --to=sbd \
-         --smtp-server="$(pwd)/fake.sendmail" \
-         outdir/0001-*.patch \
-         2>errors >out &&
+               --from="Example <nobody@example.com>" \
+               --to=sbd \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               outdir/0001-*.patch \
+               2>errors >out &&
        grep "^!somebody@example\.org!$" commandline1
 '
 
@@ -1399,12 +1556,45 @@ test_expect_success $PREREQ 'sendemail.aliasfile=~/.mailrc' '
        git config --replace-all sendemail.aliasesfile "~/.mailrc" &&
        git config sendemail.aliasfiletype mailrc &&
        git send-email \
-         --from="Example <nobody@example.com>" \
-         --to=sbd \
-         --smtp-server="$(pwd)/fake.sendmail" \
-         outdir/0001-*.patch \
-         2>errors >out &&
+               --from="Example <nobody@example.com>" \
+               --to=sbd \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               outdir/0001-*.patch \
+               2>errors >out &&
        grep "^!someone@example\.org!$" commandline1
 '
 
+do_xmailer_test () {
+       expected=$1 params=$2 &&
+       git format-patch -1 &&
+       git send-email \
+               --from="Example <nobody@example.com>" \
+               --to=someone@example.com \
+               --smtp-server="$(pwd)/fake.sendmail" \
+               $params \
+               0001-*.patch \
+               2>errors >out &&
+       { grep '^X-Mailer:' out || :; } >mailer &&
+       test_line_count = $expected mailer
+}
+
+test_expect_success $PREREQ '--[no-]xmailer without any configuration' '
+       do_xmailer_test 1 "--xmailer" &&
+       do_xmailer_test 0 "--no-xmailer"
+'
+
+test_expect_success $PREREQ '--[no-]xmailer with sendemail.xmailer=true' '
+       test_config sendemail.xmailer true &&
+       do_xmailer_test 1 "" &&
+       do_xmailer_test 0 "--no-xmailer" &&
+       do_xmailer_test 1 "--xmailer"
+'
+
+test_expect_success $PREREQ '--[no-]xmailer with sendemail.xmailer=false' '
+       test_config sendemail.xmailer false &&
+       do_xmailer_test 0 "" &&
+       do_xmailer_test 0 "--no-xmailer" &&
+       do_xmailer_test 1 "--xmailer"
+'
+
 test_done
diff --git a/t/t9148-git-svn-propset.sh b/t/t9148-git-svn-propset.sh
new file mode 100755 (executable)
index 0000000..1026390
--- /dev/null
@@ -0,0 +1,95 @@
+#!/bin/sh
+#
+# Copyright (c) 2014 Alfred Perlstein
+#
+
+test_description='git svn propset tests'
+
+. ./lib-git-svn.sh
+
+foo_subdir2="subdir/subdir2/foo_subdir2"
+
+set -e
+mkdir import &&
+(set -e ; cd import
+       mkdir subdir
+       mkdir subdir/subdir2
+       touch foo               # for 'add props top level'
+       touch subdir/foo_subdir # for 'add props relative'
+       touch "$foo_subdir2"    # for 'add props subdir'
+       svn_cmd import -m 'import for git svn' . "$svnrepo" >/dev/null
+)
+rm -rf import
+
+test_expect_success 'initialize git svn' '
+       git svn init "$svnrepo"
+       '
+
+test_expect_success 'fetch revisions from svn' '
+       git svn fetch
+       '
+
+set_props () {
+       subdir="$1"
+       file="$2"
+       shift;shift;
+       (cd "$subdir" &&
+               while [ $# -gt 0 ] ; do
+                       git svn propset "$1" "$2" "$file" || exit 1
+                       shift;shift;
+               done &&
+               echo hello >> "$file" &&
+               git commit -m "testing propset" "$file")
+}
+
+confirm_props () {
+       subdir="$1"
+       file="$2"
+       shift;shift;
+       (set -e ; cd "svn_project/$subdir" &&
+               while [ $# -gt 0 ] ; do
+                       test "$(svn_cmd propget "$1" "$file")" = "$2" || exit 1
+                       shift;shift;
+               done)
+}
+
+
+#The current implementation has a restriction:
+#svn propset will be taken as a delta for svn dcommit only
+#if the file content is also modified
+test_expect_success 'add props top level' '
+       set_props "." "foo" "svn:keywords" "FreeBSD=%H" &&
+       git svn dcommit &&
+       svn_cmd co "$svnrepo" svn_project &&
+       confirm_props "." "foo" "svn:keywords" "FreeBSD=%H" &&
+       rm -rf svn_project
+       '
+
+test_expect_success 'add multiple props' '
+       set_props "." "foo" \
+               "svn:keywords" "FreeBSD=%H" fbsd:nokeywords yes &&
+       git svn dcommit &&
+       svn_cmd co "$svnrepo" svn_project &&
+       confirm_props "." "foo" \
+               "svn:keywords" "FreeBSD=%H" fbsd:nokeywords yes &&
+       rm -rf svn_project
+       '
+
+test_expect_success 'add props subdir' '
+       set_props "." "$foo_subdir2" svn:keywords "FreeBSD=%H" &&
+       git svn dcommit &&
+       svn_cmd co "$svnrepo" svn_project &&
+       confirm_props "." "$foo_subdir2" "svn:keywords" "FreeBSD=%H" &&
+       rm -rf svn_project
+       '
+
+test_expect_success 'add props relative' '
+       set_props "subdir/subdir2" "../foo_subdir" \
+               svn:keywords "FreeBSD=%H" &&
+       git svn dcommit &&
+       svn_cmd co "$svnrepo" svn_project &&
+       confirm_props "subdir/subdir2" "../foo_subdir" \
+               svn:keywords "FreeBSD=%H" &&
+       rm -rf svn_project
+       '
+test_done
index 79e8a33d043e7208c2c1a08ab38fad207049ef4c..9acdc8826fff1aabf9df5182a64109b7bd16cd8d 100644 (file)
@@ -140,6 +140,9 @@ else
        }
 fi
 
+: ${ASAN_OPTIONS=detect_leaks=0}
+export ASAN_OPTIONS
+
 # Protect ourselves from common misconfiguration to export
 # CDPATH into the environment
 unset CDPATH
index 69e3c67b00f482449e77945eb114f58244078b1e..6187dbf4390fc6e28445dd3d988aefb9d1111988 100755 (executable)
@@ -24,7 +24,6 @@ url="$2"
 
 z40=0000000000000000000000000000000000000000
 
-IFS=' '
 while read local_ref local_sha remote_ref remote_sha
 do
        if [ "$local_sha" = $z40 ]
index 07aa7ecdeede64477b424620425826b380bf895d..cc2891dd971edfa70733eb327d12ccb66fd09f3e 100644 (file)
@@ -47,7 +47,7 @@ static struct test_entry *alloc_test_entry(int hash, char *key, int klen,
 
 static unsigned int hash(unsigned int method, unsigned int i, const char *key)
 {
-       unsigned int hash;
+       unsigned int hash = 0;
        switch (method & 3)
        {
        case HASH_METHOD_FNV:
diff --git a/trace.c b/trace.c
index 477860894196e32d7db990459cef47175277c441..f6f9f3a367242f5f3f10e1d33381f0a52d4fbe55 100644 (file)
--- a/trace.c
+++ b/trace.c
@@ -122,9 +122,7 @@ static int prepare_trace_line(const char *file, int line,
 
 static void print_trace_line(struct trace_key *key, struct strbuf *buf)
 {
-       /* append newline if missing */
-       if (buf->len && buf->buf[buf->len - 1] != '\n')
-               strbuf_addch(buf, '\n');
+       strbuf_complete_line(buf);
 
        write_or_whine_pipe(get_trace_fd(key), buf->buf, buf->len, err_msg);
        strbuf_release(buf);
index a905f5c50cef099c23d8a05acefc279168de69ec..623adeb02d0e06a83d7b17a9b605ff8c6475a0bd 100644 (file)
--- a/trailer.c
+++ b/trailer.c
@@ -2,6 +2,7 @@
 #include "string-list.h"
 #include "run-command.h"
 #include "string-list.h"
+#include "commit.h"
 #include "trailer.h"
 /*
  * Copyright (c) 2013, 2014 Christian Couder <chriscool@tuxfamily.org>
@@ -768,6 +769,22 @@ static int find_trailer_start(struct strbuf **lines, int count)
        return only_spaces ? count : 0;
 }
 
+/* Get the index of the end of the trailers */
+static int find_trailer_end(struct strbuf **lines, int patch_start)
+{
+       struct strbuf sb = STRBUF_INIT;
+       int i, ignore_bytes;
+
+       for (i = 0; i < patch_start; i++)
+               strbuf_addbuf(&sb, lines[i]);
+       ignore_bytes = ignore_non_trailer(&sb);
+       strbuf_release(&sb);
+       for (i = patch_start - 1; i >= 0 && ignore_bytes > 0; i--)
+               ignore_bytes -= lines[i]->len;
+
+       return i + 1;
+}
+
 static int has_blank_line_before(struct strbuf **lines, int start)
 {
        for (;start >= 0; start--) {
@@ -790,14 +807,15 @@ static int process_input_file(struct strbuf **lines,
                              struct trailer_item **in_tok_last)
 {
        int count = 0;
-       int patch_start, trailer_start, i;
+       int patch_start, trailer_start, trailer_end, i;
 
        /* Get the line count */
        while (lines[count])
                count++;
 
        patch_start = find_patch_start(lines, count);
-       trailer_start = find_trailer_start(lines, patch_start);
+       trailer_end = find_trailer_end(lines, patch_start);
+       trailer_start = find_trailer_start(lines, trailer_end);
 
        /* Print lines before the trailers as is */
        print_lines(lines, 0, trailer_start);
@@ -806,14 +824,14 @@ static int process_input_file(struct strbuf **lines,
                printf("\n");
 
        /* Parse trailer lines */
-       for (i = trailer_start; i < patch_start; i++) {
+       for (i = trailer_start; i < trailer_end; i++) {
                if (lines[i]->buf[0] != comment_line_char) {
                        struct trailer_item *new = create_trailer_item(lines[i]->buf);
                        add_trailer_item(in_tok_first, in_tok_last, new);
                }
        }
 
-       return patch_start;
+       return trailer_end;
 }
 
 static void free_all(struct trailer_item **first)
@@ -830,7 +848,7 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
        struct trailer_item *in_tok_last = NULL;
        struct trailer_item *arg_tok_first;
        struct strbuf **lines;
-       int patch_start;
+       int trailer_end;
 
        /* Default config must be setup first */
        git_config(git_trailer_default_config, NULL);
@@ -839,7 +857,7 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
        lines = read_input_file(file);
 
        /* Print the lines before the trailers */
-       patch_start = process_input_file(lines, &in_tok_first, &in_tok_last);
+       trailer_end = process_input_file(lines, &in_tok_first, &in_tok_last);
 
        arg_tok_first = process_command_line_args(trailers);
 
@@ -850,7 +868,7 @@ void process_trailers(const char *file, int trim_empty, struct string_list *trai
        free_all(&in_tok_first);
 
        /* Print the lines after the trailers as is */
-       print_lines(lines, patch_start, INT_MAX);
+       print_lines(lines, trailer_end, INT_MAX);
 
        strbuf_list_free(lines);
 }
diff --git a/tree.c b/tree.c
index bb02c1caa4ff6a8af40b89498de3af3381272999..58ebfce1bca609b0f7119eb210345c2065d02f40 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -30,9 +30,12 @@ static int read_one_entry_opt(const unsigned char *sha1, const char *base, int b
        return add_cache_entry(ce, opt);
 }
 
-static int read_one_entry(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *context)
+static int read_one_entry(const unsigned char *sha1, struct strbuf *base,
+                         const char *pathname, unsigned mode, int stage,
+                         void *context)
 {
-       return read_one_entry_opt(sha1, base, baselen, pathname, mode, stage,
+       return read_one_entry_opt(sha1, base->buf, base->len, pathname,
+                                 mode, stage,
                                  ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
 }
 
@@ -40,9 +43,12 @@ static int read_one_entry(const unsigned char *sha1, const char *base, int basel
  * This is used when the caller knows there is no existing entries at
  * the stage that will conflict with the entry being added.
  */
-static int read_one_entry_quick(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *context)
+static int read_one_entry_quick(const unsigned char *sha1, struct strbuf *base,
+                               const char *pathname, unsigned mode, int stage,
+                               void *context)
 {
-       return read_one_entry_opt(sha1, base, baselen, pathname, mode, stage,
+       return read_one_entry_opt(sha1, base->buf, base->len, pathname,
+                                 mode, stage,
                                  ADD_CACHE_JUST_APPEND);
 }
 
@@ -70,7 +76,7 @@ static int read_tree_1(struct tree *tree, struct strbuf *base,
                                continue;
                }
 
-               switch (fn(entry.sha1, base->buf, base->len,
+               switch (fn(entry.sha1, base,
                           entry.path, entry.mode, stage, context)) {
                case 0:
                        continue;
diff --git a/tree.h b/tree.h
index d84ac63e511c30ae4e1c8ee2b9719d67fd9424da..d24125f84f01cddaecbd047b24e3a710014560a4 100644 (file)
--- a/tree.h
+++ b/tree.h
@@ -4,6 +4,7 @@
 #include "object.h"
 
 extern const char *tree_type;
+struct strbuf;
 
 struct tree {
        struct object object;
@@ -22,7 +23,7 @@ void free_tree_buffer(struct tree *tree);
 struct tree *parse_tree_indirect(const unsigned char *sha1);
 
 #define READ_TREE_RECURSIVE 1
-typedef int (*read_tree_fn_t)(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
+typedef int (*read_tree_fn_t)(const unsigned char *, struct strbuf *, const char *, unsigned int, int, void *);
 
 extern int read_tree_recursive(struct tree *tree,
                               const char *base, int baselen,
index 256df47b3533bc085428d3fc5239173200a8e648..be84ba2607ad2dbdb17397869c459418abad78e4 100644 (file)
@@ -1157,6 +1157,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
        if (o->dst_index) {
                discard_index(o->dst_index);
                *o->dst_index = o->result;
+       } else {
+               discard_index(&o->result);
        }
 
 done:
index 000b937e6828d378829cfe8a25e93ce07c531574..27af77c7df63f8a9039d77b332ebb06d69f02f65 100755 (executable)
@@ -27,11 +27,14 @@ fi &&
                fi &&
                make
        ) &&
-       echo "static const struct interval zero_width[] = {" >$UNICODEWIDTH_H &&
-       UNICODE_DIR=. ./uniset/uniset --32 cat:Me,Mn,Cf + U+1160..U+11FF - U+00AD |
-       grep -v plane >>$UNICODEWIDTH_H &&
-       echo "};" >>$UNICODEWIDTH_H &&
-       echo "static const struct interval double_width[] = {" >>$UNICODEWIDTH_H &&
-       UNICODE_DIR=. ./uniset/uniset --32 eaw:F,W >>$UNICODEWIDTH_H &&
-       echo "};" >>$UNICODEWIDTH_H
+       UNICODE_DIR=. && export UNICODE_DIR &&
+       cat >$UNICODEWIDTH_H <<-EOF
+       static const struct interval zero_width[] = {
+               $(uniset/uniset --32 cat:Me,Mn,Cf + U+1160..U+11FF - U+00AD |
+                 grep -v plane)
+       };
+       static const struct interval double_width[] = {
+               $(uniset/uniset --32 eaw:F,W)
+       };
+       EOF
 )
index cdbc8d798aaff6fff833224ff94b83af49289a5a..b54eac5af6233de183144230259bd317cf24513a 100644 (file)
@@ -726,7 +726,6 @@ static void wt_status_print_changed(struct wt_status *s)
 static void wt_status_print_submodule_summary(struct wt_status *s, int uncommitted)
 {
        struct child_process sm_summary = CHILD_PROCESS_INIT;
-       struct argv_array argv = ARGV_ARRAY_INIT;
        struct strbuf cmd_stdout = STRBUF_INIT;
        struct strbuf summary = STRBUF_INIT;
        char *summary_content;
@@ -735,23 +734,21 @@ static void wt_status_print_submodule_summary(struct wt_status *s, int uncommitt
        argv_array_pushf(&sm_summary.env_array, "GIT_INDEX_FILE=%s",
                         s->index_file);
 
-       argv_array_push(&argv, "submodule");
-       argv_array_push(&argv, "summary");
-       argv_array_push(&argv, uncommitted ? "--files" : "--cached");
-       argv_array_push(&argv, "--for-status");
-       argv_array_push(&argv, "--summary-limit");
-       argv_array_pushf(&argv, "%d", s->submodule_summary);
+       argv_array_push(&sm_summary.args, "submodule");
+       argv_array_push(&sm_summary.args, "summary");
+       argv_array_push(&sm_summary.args, uncommitted ? "--files" : "--cached");
+       argv_array_push(&sm_summary.args, "--for-status");
+       argv_array_push(&sm_summary.args, "--summary-limit");
+       argv_array_pushf(&sm_summary.args, "%d", s->submodule_summary);
        if (!uncommitted)
-               argv_array_push(&argv, s->amend ? "HEAD^" : "HEAD");
+               argv_array_push(&sm_summary.args, s->amend ? "HEAD^" : "HEAD");
 
-       sm_summary.argv = argv.argv;
        sm_summary.git_cmd = 1;
        sm_summary.no_stdin = 1;
        fflush(s->fp);
        sm_summary.out = -1;
 
        run_command(&sm_summary);
-       argv_array_clear(&argv);
 
        len = strbuf_read(&cmd_stdout, sm_summary.out, 1024);