Merge branch 'mh/expire-updateref-fixes'
authorJunio C Hamano <gitster@pobox.com>
Tue, 10 Mar 2015 20:52:39 +0000 (13:52 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 10 Mar 2015 20:52:40 +0000 (13:52 -0700)
Various issues around "reflog expire", e.g. using --updateref when
expiring a reflog for a symbolic reference, have been corrected
and/or made saner.

* mh/expire-updateref-fixes:
reflog_expire(): never update a reference to null_sha1
reflog_expire(): ignore --updateref for symbolic references
reflog: improve and update documentation
struct ref_lock: delete the force_write member
lock_ref_sha1_basic(): do not set force_write for missing references
write_ref_sha1(): move write elision test to callers
write_ref_sha1(): remove check for lock == NULL

196 files changed:
Documentation/CodingGuidelines
Documentation/RelNotes/2.3.1.txt [new file with mode: 0644]
Documentation/RelNotes/2.3.2.txt [new file with mode: 0644]
Documentation/config.txt
Documentation/diff-format.txt
Documentation/git-am.txt
Documentation/git-apply.txt
Documentation/git-clean.txt
Documentation/git-p4.txt
Documentation/git-push.txt
Documentation/git-remote.txt
Documentation/git-submodule.txt
Documentation/git.txt
Documentation/githooks.txt
Documentation/gitmodules.txt
Documentation/pretty-options.txt
Documentation/rev-list-options.txt
Documentation/technical/api-error-handling.txt [new file with mode: 0644]
Documentation/technical/api-strbuf.txt [deleted file]
GIT-VERSION-GEN
Makefile
RelNotes [changed from symlink to file mode: 0644]
advice.c
archive.c
attr.c
branch.c
builtin/add.c
builtin/apply.c
builtin/blame.c
builtin/branch.c
builtin/cat-file.c
builtin/check-attr.c
builtin/check-ignore.c
builtin/check-mailmap.c
builtin/check-ref-format.c
builtin/checkout-index.c
builtin/checkout.c
builtin/clean.c
builtin/clone.c
builtin/column.c
builtin/commit.c
builtin/config.c
builtin/describe.c
builtin/diff-files.c
builtin/diff-index.c
builtin/diff-tree.c
builtin/fetch-pack.c
builtin/fetch.c
builtin/fmt-merge-msg.c
builtin/for-each-ref.c
builtin/fsck.c
builtin/gc.c
builtin/grep.c
builtin/hash-object.c
builtin/help.c
builtin/init-db.c
builtin/log.c
builtin/ls-files.c
builtin/ls-remote.c
builtin/mailinfo.c
builtin/merge-base.c
builtin/merge-file.c
builtin/merge-index.c
builtin/merge.c
builtin/mv.c
builtin/name-rev.c
builtin/notes.c
builtin/pack-redundant.c
builtin/pack-refs.c
builtin/prune-packed.c
builtin/receive-pack.c
builtin/remote.c
builtin/repack.c
builtin/replace.c
builtin/rerere.c
builtin/rev-parse.c
builtin/revert.c
builtin/rm.c
builtin/shortlog.c
builtin/show-branch.c
builtin/show-ref.c
builtin/symbolic-ref.c
builtin/tag.c
builtin/update-index.c
builtin/update-ref.c
builtin/verify-commit.c
builtin/verify-pack.c
builtin/verify-tag.c
cache.h
check-builtins.sh
commit.h
config.c
connect.c
contrib/completion/git-completion.bash
contrib/credential/wincred/git-credential-wincred.c
credential-store.c
ctype.c
daemon.c
diff-lib.c
diff.c
diffcore-rename.c
ewah/ewok.h
fast-import.c
gettext.c
gettext.h
git-add--interactive.perl
git-bisect.sh
git-compat-util.h
git-p4.py
git-rebase--interactive.sh
git-remote-testgit.sh
git-send-email.perl
git-submodule.sh
git-svn.perl
git.c
grep.c
hex.c
http.c
http.h
kwset.c
kwset.h
line-log.c
line-log.h
notes.c
pack-bitmap.c
pack-bitmap.h
pager.c
perl/Git.pm
perl/Git/SVN.pm
perl/Git/SVN/Editor.pm
perl/Git/SVN/Fetcher.pm
perl/Git/SVN/Ra.pm
pretty.c
prompt.c
prompt.h
read-cache.c
refs.c
refs.h
remote-curl.c
remote.c
remote.h
rerere.c
revision.c
revision.h
sequencer.c
sha1_file.c
sha1_name.c
shallow.c
strbuf.h
t/diff-lib.sh
t/diff-lib/COPYING [new file with mode: 0644]
t/diff-lib/README [new file with mode: 0644]
t/lib-gpg.sh
t/lib-gpg/keyring.gpg
t/lib-httpd.sh
t/lib-terminal.sh
t/t0061-run-command.sh
t/t1307-config-blob.sh
t/t1509-root-worktree.sh
t/t3404-rebase-interactive.sh
t/t4003-diff-rename-1.sh
t/t4005-diff-rename-2.sh
t/t4007-rename-3.sh
t/t4008-diff-break-rewrite.sh
t/t4009-diff-rename-4.sh
t/t4010-diff-pathspec.sh
t/t4047-diff-dirstat.sh
t/t4058-diff-duplicates.sh [new file with mode: 0755]
t/t4122-apply-symlink-inside.sh
t/t4138-apply-ws-expansion.sh [new file with mode: 0755]
t/t4139-apply-escape.sh [new file with mode: 0755]
t/t4202-log.sh
t/t4255-am-submodule.sh
t/t5304-prune.sh
t/t5500-fetch-pack.sh
t/t5516-fetch-push.sh
t/t5550-http-fetch-dumb.sh
t/t5570-git-daemon.sh
t/t5601-clone.sh
t/t5801-remote-helpers.sh
t/t6023-merge-file.sh
t/t7400-submodule-basic.sh
t/t7516-commit-races.sh [new file with mode: 0755]
t/t9001-send-email.sh
t/t9300-fast-import.sh
t/t9817-git-p4-exclude.sh [new file with mode: 0755]
t/test-lib-functions.sh
t/test-lib.sh
trailer.c
transport-helper.c
urlmatch.c
urlmatch.h
userdiff.c
walker.c
wrapper.c
wt-status.c
index 894546dd75416fcf09542096a67b2f22a7d0de7a..7636199fe8815b09730cd0877f230797ada364ed 100644 (file)
@@ -328,9 +328,14 @@ For C programs:
 
  - When you come up with an API, document it.
 
- - The first #include in C files, except in platform specific
-   compat/ implementations, should be git-compat-util.h or another
-   header file that includes it, such as cache.h or builtin.h.
+ - The first #include in C files, except in platform specific compat/
+   implementations, must be either "git-compat-util.h", "cache.h" or
+   "builtin.h".  You do not have to include more than one of these.
+
+ - A C file must directly include the header files that declare the
+   functions and the types it uses, except for the functions and types
+   that are made available to it by including one of the header files
+   it must include by the previous rule.
 
  - If you are planning a new command, consider writing it in shell
    or perl first, so that changes in semantics can be easily
@@ -413,6 +418,29 @@ Error Messages
  - Say what the error is first ("cannot open %s", not "%s: cannot open")
 
 
+Externally Visible Names
+
+ - For configuration variable names, follow the existing convention:
+
+   . The section name indicates the affected subsystem.
+
+   . The subsection name, if any, indicates which of an unbounded set
+     of things to set the value for.
+
+   . The variable name describes the effect of tweaking this knob.
+
+   The section and variable names that consist of multiple words are
+   formed by concatenating the words without punctuations (e.g. `-`),
+   and are broken using bumpyCaps in documentation as a hint to the
+   reader.
+
+   When choosing the variable namespace, do not use variable name for
+   specifying possibly unbounded set of things, most notably anything
+   an end user can freely come up with (e.g. branch names).  Instead,
+   use subsection names or variable values, like the existing variable
+   branch.<name>.description does.
+
+
 Writing Documentation:
 
  Most (if not all) of the documentation pages are written in the
@@ -441,6 +469,10 @@ Writing Documentation:
    --sort=<key>
    --abbrev[=<n>]
 
+ If a placeholder has multiple words, they are separated by dashes:
+   <new-branch-name>
+   --template=<template-directory>
+
  Possibility of multiple occurrences is indicated by three dots:
    <file>...
    (One or more of <file>.)
@@ -457,12 +489,12 @@ Writing Documentation:
    (Zero or more of <patch>.  Note that the dots are inside, not
    outside the brackets.)
 
- Multiple alternatives are indicated with vertical bar:
+ Multiple alternatives are indicated with vertical bars:
    [-q | --quiet]
    [--utf8 | --no-utf8]
 
  Parentheses are used for grouping:
-   [(<rev>|<range>)...]
+   [(<rev> | <range>)...]
    (Any number of either <rev> or <range>.  Parens are needed to make
    it clear that "..." pertains to both <rev> and <range>.)
 
diff --git a/Documentation/RelNotes/2.3.1.txt b/Documentation/RelNotes/2.3.1.txt
new file mode 100644 (file)
index 0000000..cf96186
--- /dev/null
@@ -0,0 +1,52 @@
+Git v2.3.1 Release Notes
+========================
+
+Fixes since v2.3
+----------------
+
+ * The interactive "show a list and let the user choose from it"
+   interface "add -i" used showed and prompted to the user even when
+   the candidate list was empty, against which the only "choice" the
+   user could have made was to choose nothing.
+
+ * "git apply --whitespace=fix" used to under-allocate the memory
+   when the fix resulted in a longer text than the original patch.
+
+ * "git log --help" used to show rev-list options that are irrelevant
+   to the "log" command.
+
+ * The error message from "git commit", when a non-existing author
+   name was given as value to the "--author=" parameter, has been
+   reworded to avoid misunderstanding.
+
+ * A broken pack .idx file in the receiving repository prevented the
+   dumb http transport from fetching a good copy of it from the other
+   side.
+
+ * The documentation incorrectly said that C(opy) and R(ename) are the
+   only ones that can be followed by the score number in the output in
+   the --raw format.
+
+ * Fix a misspelled conditional that is always true.
+
+ * Code to read branch name from various files in .git/ directory
+   would have misbehaved if the code to write them left an empty file.
+
+ * The "git push" documentation made the "--repo=<there>" option
+   easily misunderstood.
+
+ * After attempting and failing a password-less authentication
+   (e.g. kerberos), libcURL refuses to fall back to password based
+   Basic authentication without a bit of help/encouragement.
+
+ * Setting diff.submodule to 'log' made "git format-patch" produce
+   broken patches.
+
+ * "git rerere" (invoked internally from many mergy operations) did
+   not correctly signal errors when told to update the working tree
+   files and failed to do so for whatever reason.
+
+ * "git blame HEAD -- missing" failed to correctly say "HEAD" when it
+   tried to say "No such path 'missing' in HEAD".
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/2.3.2.txt b/Documentation/RelNotes/2.3.2.txt
new file mode 100644 (file)
index 0000000..f4caf54
--- /dev/null
@@ -0,0 +1,79 @@
+Git v2.3.2 Release Notes
+========================
+
+Fixes since v2.3.1
+------------------
+
+ * "update-index --refresh" used to leak when an entry cannot be
+   refreshed for whatever reason.
+
+ * "git fast-import" used to crash when it could not close and
+   conclude the resulting packfile cleanly.
+
+ * "git blame" died, trying to free an uninitialized piece of memory.
+
+ * "git merge-file" did not work correctly in a subdirectory.
+
+ * "git submodule add" failed to squash "path/to/././submodule" to
+   "path/to/submodule".
+
+ * In v2.2.0, we broke "git prune" that runs in a repository that
+   borrows from an alternate object store.
+
+ * Certain older vintages of cURL give irregular output from
+   "curl-config --vernum", which confused our build system.
+
+ * An earlier workaround to squelch unhelpful deprecation warnings
+   from the complier on Mac OSX unnecessarily set minimum required
+   version of the OS, which the user might want to raise (or lower)
+   for other reasons.
+
+ * Longstanding configuration variable naming rules has been added to
+   the documentation.
+
+ * The credential helper for Windows (in contrib/) used to mishandle
+   a user name with an at-sign in it.
+
+ * Older GnuPG implementations may not correctly import the keyring
+   material we prepare for the tests to use.
+
+ * Clarify in the documentation that "remote.<nick>.pushURL" and
+   "remote.<nick>.URL" are there to name the same repository accessed
+   via different transports, not two separate repositories.
+
+ * The pack bitmap support did not build with older versions of GCC.
+
+ * Reading configuration from a blob object, when it ends with a lone
+   CR, use to confuse the configuration parser.
+
+ * We didn't format an integer that wouldn't fit in "int" but in
+   "uintmax_t" correctly.
+
+ * "git push --signed" gave an incorrectly worded error message when
+   the other side did not support the capability.
+
+ * "git fetch" over a remote-helper that cannot respond to "list"
+   command could not fetch from a symbolic reference e.g. HEAD.
+
+ * The insn sheet "git rebase -i" creates did not fully honor
+   core.abbrev settings.
+
+ * The tests that wanted to see that file becomes unreadable after
+   running "chmod a-r file", and the tests that wanted to make sure it
+   is not run as root, we used "can we write into the / directory?" as
+   a cheap substitute, but on some platforms that is not a good
+   heuristics.  The tests and their prerequisites have been updated to
+   check what they really require.
+
+ * The configuration variable 'mailinfo.scissors' was hard to
+   discover in the documentation.
+
+ * Correct a breakage to git-svn around v2.2 era that triggers
+   premature closing of FileHandle.
+
+ * Even though we officially haven't dropped Perl 5.8 support, the
+   Getopt::Long package that came with it does not support "--no-"
+   prefix to negate a boolean option; manually add support to help
+   people with older Getopt::Long package.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
index 1a54eae8f82da26f8b9190d2ce5530bacf09f771..1530255567dc31036b4f06c9a1737bfcfee2ac59 100644 (file)
@@ -683,14 +683,13 @@ core.abbrev::
        for abbreviated object names to stay unique for sufficiently long
        time.
 
-add.ignore-errors::
 add.ignoreErrors::
+add.ignore-errors (deprecated)::
        Tells 'git add' to continue adding files when some files cannot be
        added due to indexing errors. Equivalent to the '--ignore-errors'
-       option of linkgit:git-add[1].  Older versions of Git accept only
-       `add.ignore-errors`, which does not follow the usual naming
-       convention for configuration variables.  Newer versions of Git
-       honor `add.ignoreErrors` as well.
+       option of linkgit:git-add[1].  `add.ignore-errors` is deprecated,
+       as it does not follow the usual naming convention for configuration
+       variables.
 
 alias.*::
        Command aliases for the linkgit:git[1] command wrapper - e.g.
@@ -1740,6 +1739,13 @@ log.mailmap::
        If true, makes linkgit:git-log[1], linkgit:git-show[1], and
        linkgit:git-whatchanged[1] assume `--use-mailmap`.
 
+mailinfo.scissors::
+       If true, makes linkgit:git-mailinfo[1] (and therefore
+       linkgit:git-am[1]) act by default as if the --scissors option
+       was provided on the command-line. When active, this features
+       removes everything from the message body before a scissors
+       line (i.e. consisting mainly of ">8", "8<" and "-").
+
 mailmap.file::
        The location of an augmenting mailmap file. The default
        mailmap, located in the root of the repository, is loaded
@@ -1960,7 +1966,7 @@ pack.useBitmaps::
        true. You should not generally need to turn this off unless
        you are debugging pack bitmaps.
 
-pack.writebitmaps::
+pack.writebitmaps (deprecated)::
        This is a deprecated synonym for `repack.writeBitmaps`.
 
 pack.writeBitmapHashCache::
@@ -2158,11 +2164,15 @@ receive.denyCurrentBranch::
        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
+tree 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.
++
+By default, "updateInstead" will refuse the push if the working tree or
+the index have any difference from the HEAD, but the `push-to-checkout`
+hook can be used to customize this.  See linkgit:githooks[5].
 
 receive.denyNonFastForwards::
        If set to true, git-receive-pack will deny a ref update which is
@@ -2302,7 +2312,7 @@ sendemail.smtpencryption::
        See linkgit:git-send-email[1] for description.  Note that this
        setting is not subject to the 'identity' mechanism.
 
-sendemail.smtpssl::
+sendemail.smtpssl (deprecated)::
        Deprecated alias for 'sendemail.smtpencryption = ssl'.
 
 sendemail.smtpsslcertpath::
@@ -2342,7 +2352,7 @@ sendemail.validate::
 sendemail.xmailer::
        See linkgit:git-send-email[1] for description.
 
-sendemail.signedoffcc::
+sendemail.signedoffcc (deprecated)::
        Deprecated alias for 'sendemail.signedoffbycc'.
 
 showbranch.default::
@@ -2407,12 +2417,16 @@ status.submodulesummary::
 
 submodule.<name>.path::
 submodule.<name>.url::
+       The path within this project and URL for a submodule. These
+       variables are initially populated by 'git submodule init'. See
+       linkgit:git-submodule[1] and linkgit:gitmodules[5] for
+       details.
+
 submodule.<name>.update::
-       The path within this project, URL, and the updating strategy
-       for a submodule.  These variables are initially populated
-       by 'git submodule init'; edit them to override the
-       URL and other values found in the `.gitmodules` file.  See
-       linkgit:git-submodule[1] and linkgit:gitmodules[5] for details.
+       The default update procedure for a submodule. This variable
+       is populated by `git submodule init` from the
+       linkgit:gitmodules[5] file. See description of 'update'
+       command in linkgit:git-submodule[1].
 
 submodule.<name>.branch::
        The remote branch name for a submodule, used by `git submodule
index 15c7e794f4adaccb8885683946a9f4e7e4dc92c2..85b08909ce25acc5f9deae9a3e0ade2bd679bc94 100644 (file)
@@ -66,7 +66,8 @@ be committed)
 
 Status letters C and R are always followed by a score (denoting the
 percentage of similarity between the source and target of the move or
-copy), and are the only ones to be so.
+copy).  Status letter M may be followed by a score (denoting the
+percentage of dissimilarity) for file rewrites.
 
 <sha1> is shown as all 0's if a file is new on the filesystem
 and it is out of sync with the index.
index f4eea28dc4d03e02f9af3eedba5d15743b8553f6..0d8ba48f792ae82237a56aa0dd2aca03f4e16020 100644 (file)
@@ -52,7 +52,8 @@ OPTIONS
 -c::
 --scissors::
        Remove everything in body before a scissors line (see
-       linkgit:git-mailinfo[1]).
+       linkgit:git-mailinfo[1]). Can be activated by default using
+       the `mailinfo.scissors` configuration variable.
 
 --no-scissors::
        Ignore scissors lines (see linkgit:git-mailinfo[1]).
index f605327946f1bc72a62a6129d7e783162853ad51..9489664cfa6c15725a5153ed3856b70061c6787f 100644 (file)
@@ -16,7 +16,7 @@ SYNOPSIS
          [--ignore-space-change | --ignore-whitespace ]
          [--whitespace=(nowarn|warn|fix|error|error-all)]
          [--exclude=<path>] [--include=<path>] [--directory=<root>]
-         [--verbose] [<patch>...]
+         [--verbose] [--unsafe-paths] [<patch>...]
 
 DESCRIPTION
 -----------
@@ -229,6 +229,16 @@ For example, a patch that talks about updating `a/git-gui.sh` to `b/git-gui.sh`
 can be applied to the file in the working tree `modules/git-gui/git-gui.sh` by
 running `git apply --directory=modules/git-gui`.
 
+--unsafe-paths::
+       By default, a patch that affects outside the working area
+       (either a Git controlled working tree, or the current working
+       directory when "git apply" is used as a replacement of GNU
+       patch) is rejected as a mistake (or a mischief).
++
+When `git apply` is used as a "better GNU patch", the user can pass
+the `--unsafe-paths` option to override this safety check.  This option
+has no effect when `--index` or `--cached` is in use.
+
 Configuration
 -------------
 
index 94b6d19cf2a658a9258ee54b141b4eb9b1a6cae3..641681f61ad360fcfd5aa98f81a9e3d49c44c8a7 100644 (file)
@@ -34,8 +34,12 @@ OPTIONS
 -f::
 --force::
        If the Git configuration variable clean.requireForce is not set
-       to false, 'git clean' will refuse to run unless given -f, -n or
-       -i.
+       to false, 'git clean' will refuse to delete files or directories
+       unless given -f, -n or -i. Git will refuse to delete directories
+       with .git sub directory or file unless a second -f
+       is given. This affects also git submodules where the storage area
+       of the removed submodule under .git/modules/ is not removed until
+       -f is given twice.
 
 -i::
 --interactive::
index 6ab5f9497ab353e38c15708443527e1d047d39e8..a1664b9f684bae0d3e715b36760ce62f4745ed06 100644 (file)
@@ -241,6 +241,9 @@ Git repository:
        Use a client spec to find the list of interesting files in p4.
        See the "CLIENT SPEC" section below.
 
+-/ <path>::
+       Exclude selected depot paths when cloning or syncing.
+
 Clone options
 ~~~~~~~~~~~~~
 These options can be used in an initial 'clone', along with the 'sync'
@@ -254,9 +257,6 @@ options described above.
 --bare::
        Perform a bare clone.  See linkgit:git-clone[1].
 
--/ <path>::
-       Exclude selected depot paths when cloning.
-
 Submit options
 ~~~~~~~~~~~~~~
 These options can be used to modify 'git p4 submit' behavior.
index ea9757692ac6fa7f58eb8a150f9eef9e30875333..e1a46a79581d62596625f9896a77538f6f42faff 100644 (file)
@@ -219,22 +219,8 @@ origin +master` to force a push to the `master` branch). See the
 `<refspec>...` section above for details.
 
 --repo=<repository>::
-       This option is only relevant if no <repository> argument is
-       passed in the invocation. In this case, 'git push' derives the
-       remote name from the current branch: If it tracks a remote
-       branch, then that remote repository is pushed to. Otherwise,
-       the name "origin" is used. For this latter case, this option
-       can be used to override the name "origin". In other words,
-       the difference between these two commands
-+
---------------------------
-git push public         #1
-git push --repo=public  #2
---------------------------
-+
-is that #1 always pushes to "public" whereas #2 pushes to "public"
-only if the current branch does not track a remote branch. This is
-useful if you write an alias or script around 'git push'.
+       This option is equivalent to the <repository> argument. If both
+       are specified, the command-line argument takes precedence.
 
 -u::
 --set-upstream::
index cb103c8b6f8fe4fd89ad5e1a37b551f9f54d75c7..4c6d6de7b77c2f1a70e2335fed0e65e956f99c6f 100644 (file)
@@ -58,6 +58,9 @@ remote repository.
 With `--no-tags` option, `git fetch <name>` does not import tags from
 the remote repository.
 +
+By default, only tags on fetched branches are imported
+(see linkgit:git-fetch[1]).
++
 With `-t <branch>` option, instead of the default glob
 refspec for the remote to track all branches under
 the `refs/remotes/<name>/` namespace, a refspec to track only `<branch>`
@@ -130,17 +133,25 @@ branches, adds to that list.
 
 'set-url'::
 
-Changes URL remote points to. Sets first URL remote points to matching
+Changes URLs for the remote. Sets first URL for remote <name> that matches
 regex <oldurl> (first URL if no <oldurl> is given) to <newurl>. If
-<oldurl> doesn't match any URL, error occurs and nothing is changed.
+<oldurl> doesn't match any URL, an error occurs and nothing is changed.
 +
 With '--push', push URLs are manipulated instead of fetch URLs.
 +
-With '--add', instead of changing some URL, new URL is added.
+With '--add', instead of changing existing URLs, new URL is added.
++
+With '--delete', instead of changing existing URLs, all URLs matching
+regex <url> are deleted for remote <name>.  Trying to delete all
+non-push URLs is an error.
 +
-With '--delete', instead of changing some URL, all URLs matching
-regex <url> are deleted. Trying to delete all non-push URLs is an
-error.
+Note that the push URL and the fetch URL, even though they can
+be set differently, must still refer to the same place.  What you
+pushed to the push URL should be what you would see if you
+immediately fetched from the fetch URL.  If you are trying to
+fetch from one place (e.g. your upstream) and push to another (e.g.
+your publishing repository), use two separate remotes.
+
 
 'show'::
 
index 8e6af65da0e0f234315c42391a8bab42fc39abb6..2c25916f8f7cd0a7ca69c3b980d85251a29b681b 100644 (file)
@@ -154,27 +154,51 @@ If `--force` is specified, the submodule's work tree will be removed even if
 it contains local modifications.
 
 update::
-       Update the registered submodules, i.e. clone missing submodules and
-       checkout the commit specified in the index of the containing repository.
-       This will make the submodules HEAD be detached unless `--rebase` or
-       `--merge` is specified or the key `submodule.$name.update` is set to
-       `rebase`, `merge` or `none`. `none` can be overridden by specifying
-       `--checkout`. Setting the key `submodule.$name.update` to `!command`
-       will cause `command` to be run. `command` can be any arbitrary shell
-       command that takes a single argument, namely the sha1 to update to.
 +
+--
+Update the registered submodules to match what the superproject
+expects by cloning missing submodules and updating the working tree of
+the submodules. The "updating" can be done in several ways depending
+on command line options and the value of `submodule.<name>.update`
+configuration variable. Supported update procedures are:
+
+       checkout;; the commit recorded in the superproject will be
+           checked out in the submodule on a detached HEAD. This is
+           done when `--checkout` option is given, or no option is
+           given, and `submodule.<name>.update` is unset, or if it is
+           set to 'checkout'.
++
+If `--force` is specified, the submodule will be checked out (using
+`git checkout --force` if appropriate), even if the commit specified
+in the index of the containing repository already matches the commit
+checked out in the submodule.
+
+       rebase;; the current branch of the submodule will be rebased
+           onto the commit recorded in the superproject. This is done
+           when `--rebase` option is given, or no option is given, and
+           `submodule.<name>.update` is set to 'rebase'.
+
+       merge;; the commit recorded in the superproject will be merged
+           into the current branch in the submodule. This is done
+           when `--merge` option is given, or no option is given, and
+           `submodule.<name>.update` is set to 'merge'.
+
+       custom command;; arbitrary shell command that takes a single
+           argument (the sha1 of the commit recorded in the
+           superproject) is executed. This is done when no option is
+           given, and `submodule.<name>.update` has the form of
+           '!command'.
+
+When no option is given and `submodule.<name>.update` is set to 'none',
+the submodule is not updated.
+
 If the submodule is not yet initialized, and you just want to use the
 setting as stored in .gitmodules, you can automatically initialize the
 submodule with the `--init` option.
-+
+
 If `--recursive` is specified, this command will recurse into the
 registered submodules, and update any nested submodules within.
-+
-If `--force` is specified, the submodule will be checked out (using
-`git checkout --force` if appropriate), even if the commit specified in the
-index of the containing repository already matches the commit checked out in
-the submodule.
-
+--
 summary::
        Show commit summary between the given commit (defaults to HEAD) and
        working tree/index. For a submodule in question, a series of commits
@@ -238,10 +262,12 @@ OPTIONS
        When running add, allow adding an otherwise ignored submodule path.
        When running deinit the submodule work trees will be removed even if
        they contain local changes.
-       When running update, throw away local changes in submodules when
-       switching to a different commit; and always run a checkout operation
-       in the submodule, even if the commit listed in the index of the
-       containing repository matches the commit checked out in the submodule.
+       When running update (only effective with the checkout procedure),
+       throw away local changes in submodules when switching to a
+       different commit; and always run a checkout operation in the
+       submodule, even if the commit listed in the index of the
+       containing repository matches the commit checked out in the
+       submodule.
 
 --cached::
        This option is only valid for status and summary commands.  These
@@ -302,7 +328,7 @@ the submodule itself.
        Checkout the commit recorded in the superproject on a detached HEAD
        in the submodule. This is the default behavior, the main use of
        this option is to override `submodule.$name.update` when set to
-       `merge`, `rebase` or `none`.
+       a value other than `checkout`.
        If the key `submodule.$name.update` is either not explicitly set or
        set to `checkout`, this option is implicit.
 
index eadbd05356398a3c85884efc6779bba0e923b311..52c4d2a7c9e4112734e43af7dcf12a9e9c385aa2 100644 (file)
@@ -43,9 +43,11 @@ unreleased) version of Git, that is available from the 'master'
 branch of the `git.git` repository.
 Documentation for older releases are available here:
 
-* link:v2.3.0/git.html[documentation for release 2.3]
+* link:v2.3.2/git.html[documentation for release 2.3.2]
 
 * release notes for
+  link:RelNotes/2.3.2.txt[2.3.2],
+  link:RelNotes/2.3.1.txt[2.3.1],
   link:RelNotes/2.3.0.txt[2.3].
 
 * link:v2.2.2/git.html[documentation for release 2.2.2]
index 9ef2469373a5d7ddc511d9569ed57ca587cc2c6d..7ba0ac965dd6266404d4b3fad74d59a4e79be0dd 100644 (file)
@@ -341,6 +341,36 @@ Both standard output and standard error output are forwarded to
 'git send-pack' on the other end, so you can simply `echo` messages
 for the user.
 
+push-to-checkout
+~~~~~~~~~~~~~~~~
+
+This hook is invoked by 'git-receive-pack' on the remote repository,
+which happens when a 'git push' is done on a local repository, when
+the push tries to update the branch that is currently checked out
+and the `receive.denyCurrentBranch` configuration variable is set to
+`updateInstead`.  Such a push by default is refused if the working
+tree and the index of the remote repository has any difference from
+the currently checked out commit; when both the working tree and the
+index match the current commit, they are updated to match the newly
+pushed tip of the branch.  This hook is to be used to override the
+default behaviour.
+
+The hook receives the commit with which the tip of the current
+branch is going to be updated.  It can exit with a non-zero status
+to refuse the push (when it does so, it must not modify the index or
+the working tree).  Or it can make any necessary changes to the
+working tree and to the index to bring them to the desired state
+when the tip of the current branch is updated to the new commit, and
+exit with a zero status.
+
+For example, the hook can simply run `git read-tree -u -m HEAD "$1"`
+in order to emulate 'git fetch' that is run in the reverse direction
+with `git push`, as the two-tree form of `read-tree -u -m` is
+essentially the same as `git checkout` that switches branches while
+keeping the local changes in the working tree that do not interfere
+with the difference between the branches.
+
+
 pre-auto-gc
 ~~~~~~~~~~~
 
index f6c0dfd0290a9b2174c645630998d2a62cdb9f5e..ac70eca321cd1747e2916646c691ac18cb4dbd97 100644 (file)
@@ -38,18 +38,15 @@ submodule.<name>.url::
 In addition, there are a number of optional keys:
 
 submodule.<name>.update::
-       Defines what to do when the submodule is updated by the superproject.
-       If 'checkout' (the default), the new commit specified in the
-       superproject will be checked out in the submodule on a detached HEAD.
-       If 'rebase', the current branch of the submodule will be rebased onto
-       the commit specified in the superproject. If 'merge', the commit
-       specified in the superproject will be merged into the current branch
-       in the submodule.
-       If 'none', the submodule with name `$name` will not be updated
-       by default.
-
-       This config option is overridden if 'git submodule update' is given
-       the '--merge', '--rebase' or '--checkout' options.
+       Defines the default update procedure for the named submodule,
+       i.e. how the submodule is updated by "git submodule update"
+       command in the superproject. This is only used by `git
+       submodule init` to initialize the configuration variable of
+       the same name. Allowed values here are 'checkout', 'rebase',
+       'merge' or 'none'. See description of 'update' command in
+       linkgit:git-submodule[1] for their meaning. Note that the
+       '!command' form is intentionally ignored here for security
+       reasons.
 
 submodule.<name>.branch::
        A remote branch name for tracking updates in the upstream submodule.
index 8569e29d08784cb5eb053af919e4b7514b1c296b..74aa01a0ec27b6cc0fbb9763b8e583a3f996da25 100644 (file)
@@ -3,9 +3,13 @@
 
        Pretty-print the contents of the commit logs in a given format,
        where '<format>' can be one of 'oneline', 'short', 'medium',
-       'full', 'fuller', 'email', 'raw' and 'format:<string>'.  See
-       the "PRETTY FORMATS" section for some additional details for each
-       format.  When omitted, the format defaults to 'medium'.
+       'full', 'fuller', 'email', 'raw', 'format:<string>'
+       and 'tformat:<string>'.  When '<format>' is none of the above,
+       and has '%placeholder' in it, it acts as if
+       '--pretty=tformat:<format>' were given.
++
+See the "PRETTY FORMATS" section for some additional details for each
+format.  When '=<format>' part is omitted, it defaults to 'medium'.
 +
 Note: you can specify the default pretty format in the repository
 configuration (see linkgit:git-config[1]).
index 2984f407a9f3084235fd0207a82ea44a424942ed..4ed8587c846d78a03e154ec6a4716d78882840b5 100644 (file)
@@ -66,6 +66,10 @@ if it is part of the log message.
        Limit the commits output to ones that match all given `--grep`,
        instead of ones that match at least one.
 
+--invert-grep::
+       Limit the commits output to ones with log message that do not
+       match the pattern specified with `--grep=<pattern>`.
+
 -i::
 --regexp-ignore-case::
        Match the regular expression limiting patterns without regard to letter
@@ -172,11 +176,6 @@ explicitly.
        Pretend as if all objects mentioned by reflogs are listed on the
        command line as `<commit>`.
 
---indexed-objects::
-       Pretend as if all trees and blobs used by the index are listed
-       on the command line.  Note that you probably want to use
-       `--objects`, too.
-
 --ignore-missing::
        Upon seeing an invalid object name in the input, pretend as if
        the bad input was not given.
@@ -644,6 +643,7 @@ Object Traversal
 
 These options are mostly targeted for packing of Git repositories.
 
+ifdef::git-rev-list[]
 --objects::
        Print the object IDs of any object referenced by the listed
        commits.  `--objects foo ^bar` thus means ``send me
@@ -662,9 +662,15 @@ These options are mostly targeted for packing of Git repositories.
        commits at the cost of increased time.  This is used instead of
        `--objects-edge` to build ``thin'' packs for shallow repositories.
 
+--indexed-objects::
+       Pretend as if all trees and blobs used by the index are listed
+       on the command line.  Note that you probably want to use
+       `--objects`, too.
+
 --unpacked::
        Only useful with `--objects`; print the object IDs that are not
        in packs.
+endif::git-rev-list[]
 
 --no-walk[=(sorted|unsorted)]::
        Only show the given commits, but do not traverse their ancestors.
diff --git a/Documentation/technical/api-error-handling.txt b/Documentation/technical/api-error-handling.txt
new file mode 100644 (file)
index 0000000..fc68db1
--- /dev/null
@@ -0,0 +1,75 @@
+Error reporting in git
+======================
+
+`die`, `usage`, `error`, and `warning` report errors of various
+kinds.
+
+- `die` is for fatal application errors.  It prints a message to
+  the user and exits with status 128.
+
+- `usage` is for errors in command line usage.  After printing its
+  message, it exits with status 129.  (See also `usage_with_options`
+  in the link:api-parse-options.html[parse-options API].)
+
+- `error` is for non-fatal library errors.  It prints a message
+  to the user and returns -1 for convenience in signaling the error
+  to the caller.
+
+- `warning` is for reporting situations that probably should not
+  occur but which the user (and Git) can continue to work around
+  without running into too many problems.  Like `error`, it
+  returns -1 after reporting the situation to the caller.
+
+Customizable error handlers
+---------------------------
+
+The default behavior of `die` and `error` is to write a message to
+stderr and then exit or return as appropriate.  This behavior can be
+overridden using `set_die_routine` and `set_error_routine`.  For
+example, "git daemon" uses set_die_routine to write the reason `die`
+was called to syslog before exiting.
+
+Library errors
+--------------
+
+Functions return a negative integer on error.  Details beyond that
+vary from function to function:
+
+- Some functions return -1 for all errors.  Others return a more
+  specific value depending on how the caller might want to react
+  to the error.
+
+- Some functions report the error to stderr with `error`,
+  while others leave that for the caller to do.
+
+- errno is not meaningful on return from most functions (except
+  for thin wrappers for system calls).
+
+Check the function's API documentation to be sure.
+
+Caller-handled errors
+---------------------
+
+An increasing number of functions take a parameter 'struct strbuf *err'.
+On error, such functions append a message about what went wrong to the
+'err' strbuf.  The message is meant to be complete enough to be passed
+to `die` or `error` as-is.  For example:
+
+       if (ref_transaction_commit(transaction, &err))
+               die("%s", err.buf);
+
+The 'err' parameter will be untouched if no error occured, so multiple
+function calls can be chained:
+
+       t = ref_transaction_begin(&err);
+       if (!t ||
+           ref_transaction_update(t, "HEAD", ..., &err) ||
+           ret_transaction_commit(t, &err))
+               die("%s", err.buf);
+
+The 'err' parameter must be a pointer to a valid strbuf.  To silence
+a message, pass a strbuf that is explicitly ignored:
+
+       if (thing_that_can_fail_in_an_ignorable_way(..., &err))
+               /* This failure is okay. */
+               strbuf_reset(&err);
diff --git a/Documentation/technical/api-strbuf.txt b/Documentation/technical/api-strbuf.txt
deleted file mode 100644 (file)
index cca6543..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-strbuf API
-==========
-
-strbuf's are meant to be used with all the usual C string and memory
-APIs. Given that the length of the buffer is known, it's often better to
-use the mem* functions than a str* one (memchr vs. strchr e.g.).
-Though, one has to be careful about the fact that str* functions often
-stop on NULs and that strbufs may have embedded NULs.
-
-A strbuf is NUL terminated for convenience, but no function in the
-strbuf API actually relies on the string being free of NULs.
-
-strbufs have some invariants that are very important to keep in mind:
-
-. The `buf` member is never NULL, so it can be used in any usual C
-string operations safely. strbuf's _have_ to be initialized either by
-`strbuf_init()` or by `= STRBUF_INIT` before the invariants, though.
-+
-Do *not* assume anything on what `buf` really is (e.g. if it is
-allocated memory or not), use `strbuf_detach()` to unwrap a memory
-buffer from its strbuf shell in a safe way. That is the sole supported
-way. This will give you a malloced buffer that you can later `free()`.
-+
-However, it is totally safe to modify anything in the string pointed by
-the `buf` member, between the indices `0` and `len-1` (inclusive).
-
-. The `buf` member is a byte array that has at least `len + 1` bytes
-  allocated. The extra byte is used to store a `'\0'`, allowing the
-  `buf` member to be a valid C-string. Every strbuf function ensure this
-  invariant is preserved.
-+
-NOTE: It is OK to "play" with the buffer directly if you work it this
-      way:
-+
-----
-strbuf_grow(sb, SOME_SIZE); <1>
-strbuf_setlen(sb, sb->len + SOME_OTHER_SIZE);
-----
-<1> Here, the memory array starting at `sb->buf`, and of length
-`strbuf_avail(sb)` is all yours, and you can be sure that
-`strbuf_avail(sb)` is at least `SOME_SIZE`.
-+
-NOTE: `SOME_OTHER_SIZE` must be smaller or equal to `strbuf_avail(sb)`.
-+
-Doing so is safe, though if it has to be done in many places, adding the
-missing API to the strbuf module is the way to go.
-+
-WARNING: Do _not_ assume that the area that is yours is of size `alloc
-- 1` even if it's true in the current implementation. Alloc is somehow a
-"private" member that should not be messed with. Use `strbuf_avail()`
-instead.
-
-Data structures
----------------
-
-* `struct strbuf`
-
-This is the string buffer structure. The `len` member can be used to
-determine the current length of the string, and `buf` member provides
-access to the string itself.
-
-Functions
----------
-
-* Life cycle
-
-`strbuf_init`::
-
-       Initialize the structure. The second parameter can be zero or a bigger
-       number to allocate memory, in case you want to prevent further reallocs.
-
-`strbuf_release`::
-
-       Release a string buffer and the memory it used. You should not use the
-       string buffer after using this function, unless you initialize it again.
-
-`strbuf_detach`::
-
-       Detach the string from the strbuf and returns it; you now own the
-       storage the string occupies and it is your responsibility from then on
-       to release it with `free(3)` when you are done with it.
-
-`strbuf_attach`::
-
-       Attach a string to a buffer. You should specify the string to attach,
-       the current length of the string and the amount of allocated memory.
-       The amount must be larger than the string length, because the string you
-       pass is supposed to be a NUL-terminated string.  This string _must_ be
-       malloc()ed, and after attaching, the pointer cannot be relied upon
-       anymore, and neither be free()d directly.
-
-`strbuf_swap`::
-
-       Swap the contents of two string buffers.
-
-* Related to the size of the buffer
-
-`strbuf_avail`::
-
-       Determine the amount of allocated but unused memory.
-
-`strbuf_grow`::
-
-       Ensure that at least this amount of unused memory is available after
-       `len`. This is used when you know a typical size for what you will add
-       and want to avoid repetitive automatic resizing of the underlying buffer.
-       This is never a needed operation, but can be critical for performance in
-       some cases.
-
-`strbuf_setlen`::
-
-       Set the length of the buffer to a given value. This function does *not*
-       allocate new memory, so you should not perform a `strbuf_setlen()` to a
-       length that is larger than `len + strbuf_avail()`. `strbuf_setlen()` is
-       just meant as a 'please fix invariants from this strbuf I just messed
-       with'.
-
-`strbuf_reset`::
-
-       Empty the buffer by setting the size of it to zero.
-
-* Related to the contents of the buffer
-
-`strbuf_trim`::
-
-       Strip whitespace from the beginning and end of a string.
-       Equivalent to performing `strbuf_rtrim()` followed by `strbuf_ltrim()`.
-
-`strbuf_rtrim`::
-
-       Strip whitespace from the end of a string.
-
-`strbuf_ltrim`::
-
-       Strip whitespace from the beginning of a string.
-
-`strbuf_reencode`::
-
-       Replace the contents of the strbuf with a reencoded form.  Returns -1
-       on error, 0 on success.
-
-`strbuf_tolower`::
-
-       Lowercase each character in the buffer using `tolower`.
-
-`strbuf_cmp`::
-
-       Compare two buffers. Returns an integer less than, equal to, or greater
-       than zero if the first buffer is found, respectively, to be less than,
-       to match, or be greater than the second buffer.
-
-* Adding data to the buffer
-
-NOTE: All of the functions in this section will grow the buffer as necessary.
-If they fail for some reason other than memory shortage and the buffer hadn't
-been allocated before (i.e. the `struct strbuf` was set to `STRBUF_INIT`),
-then they will free() it.
-
-`strbuf_addch`::
-
-       Add a single character to the buffer.
-
-`strbuf_addchars`::
-
-       Add a character the specified number of times to the buffer.
-
-`strbuf_insert`::
-
-       Insert data to the given position of the buffer. The remaining contents
-       will be shifted, not overwritten.
-
-`strbuf_remove`::
-
-       Remove given amount of data from a given position of the buffer.
-
-`strbuf_splice`::
-
-       Remove the bytes between `pos..pos+len` and replace it with the given
-       data.
-
-`strbuf_add_commented_lines`::
-
-       Add a NUL-terminated string to the buffer. Each line will be prepended
-       by a comment character and a blank.
-
-`strbuf_add`::
-
-       Add data of given length to the buffer.
-
-`strbuf_addstr`::
-
-Add a NUL-terminated string to the buffer.
-+
-NOTE: This function will *always* be implemented as an inline or a macro
-that expands to:
-+
-----
-strbuf_add(..., s, strlen(s));
-----
-+
-Meaning that this is efficient to write things like:
-+
-----
-strbuf_addstr(sb, "immediate string");
-----
-
-`strbuf_addbuf`::
-
-       Copy the contents of another buffer at the end of the current one.
-
-`strbuf_adddup`::
-
-       Copy part of the buffer from a given position till a given length to the
-       end of the buffer.
-
-`strbuf_expand`::
-
-       This function can be used to expand a format string containing
-       placeholders. To that end, it parses the string and calls the specified
-       function for every percent sign found.
-+
-The callback function is given a pointer to the character after the `%`
-and a pointer to the struct strbuf.  It is expected to add the expanded
-version of the placeholder to the strbuf, e.g. to add a newline
-character if the letter `n` appears after a `%`.  The function returns
-the length of the placeholder recognized and `strbuf_expand()` skips
-over it.
-+
-The format `%%` is automatically expanded to a single `%` as a quoting
-mechanism; callers do not need to handle the `%` placeholder themselves,
-and the callback function will not be invoked for this placeholder.
-+
-All other characters (non-percent and not skipped ones) are copied
-verbatim to the strbuf.  If the callback returned zero, meaning that the
-placeholder is unknown, then the percent sign is copied, too.
-+
-In order to facilitate caching and to make it possible to give
-parameters to the callback, `strbuf_expand()` passes a context pointer,
-which can be used by the programmer of the callback as she sees fit.
-
-`strbuf_expand_dict_cb`::
-
-       Used as callback for `strbuf_expand()`, expects an array of
-       struct strbuf_expand_dict_entry as context, i.e. pairs of
-       placeholder and replacement string.  The array needs to be
-       terminated by an entry with placeholder set to NULL.
-
-`strbuf_addbuf_percentquote`::
-
-       Append the contents of one strbuf to another, quoting any
-       percent signs ("%") into double-percents ("%%") in the
-       destination. This is useful for literal data to be fed to either
-       strbuf_expand or to the *printf family of functions.
-
-`strbuf_humanise_bytes`::
-
-       Append the given byte size as a human-readable string (i.e. 12.23 KiB,
-       3.50 MiB).
-
-`strbuf_addf`::
-
-       Add a formatted string to the buffer.
-
-`strbuf_commented_addf`::
-
-       Add a formatted string prepended by a comment character and a
-       blank to the buffer.
-
-`strbuf_fread`::
-
-       Read a given size of data from a FILE* pointer to the buffer.
-+
-NOTE: The buffer is rewound if the read fails. If -1 is returned,
-`errno` must be consulted, like you would do for `read(3)`.
-`strbuf_read()`, `strbuf_read_file()` and `strbuf_getline()` has the
-same behaviour as well.
-
-`strbuf_read`::
-
-       Read the contents of a given file descriptor. The third argument can be
-       used to give a hint about the file size, to avoid reallocs.
-
-`strbuf_read_file`::
-
-       Read the contents of a file, specified by its path. The third argument
-       can be used to give a hint about the file size, to avoid reallocs.
-
-`strbuf_readlink`::
-
-       Read the target of a symbolic link, specified by its path.  The third
-       argument can be used to give a hint about the size, to avoid reallocs.
-
-`strbuf_getline`::
-
-       Read a line from a FILE *, overwriting the existing contents
-       of the strbuf. The second argument specifies the line
-       terminator character, typically `'\n'`.
-       Reading stops after the terminator or at EOF.  The terminator
-       is removed from the buffer before returning.  Returns 0 unless
-       there was nothing left before EOF, in which case it returns `EOF`.
-
-`strbuf_getwholeline`::
-
-       Like `strbuf_getline`, but keeps the trailing terminator (if
-       any) in the buffer.
-
-`strbuf_getwholeline_fd`::
-
-       Like `strbuf_getwholeline`, but operates on a file descriptor.
-       It reads one character at a time, so it is very slow.  Do not
-       use it unless you need the correct position in the file
-       descriptor.
-
-`strbuf_getcwd`::
-
-       Set the buffer to the path of the current working directory.
-
-`strbuf_add_absolute_path`
-
-       Add a path to a buffer, converting a relative path to an
-       absolute one in the process.  Symbolic links are not
-       resolved.
-
-`stripspace`::
-
-       Strip whitespace from a buffer. The second parameter controls if
-       comments are considered contents to be removed or not.
-
-`strbuf_split_buf`::
-`strbuf_split_str`::
-`strbuf_split_max`::
-`strbuf_split`::
-
-       Split a string or strbuf into a list of strbufs at a specified
-       terminator character.  The returned substrings include the
-       terminator characters.  Some of these functions take a `max`
-       parameter, which, if positive, limits the output to that
-       number of substrings.
-
-`strbuf_list_free`::
-
-       Free a list of strbufs (for example, the return values of the
-       `strbuf_split()` functions).
-
-`launch_editor`::
-
-       Launch the user preferred editor to edit a file and fill the buffer
-       with the file's contents upon the user completing their editing. The
-       third argument can be used to set the environment which the editor is
-       run in. If the buffer is NULL the editor is launched as usual but the
-       file's contents are not read into the buffer upon completion.
index 780064ad7173fd5be40b3b5e419db5c3e53f96f2..50078659fcec88359310e9db691ed6b2ae9ade0e 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 GVF=GIT-VERSION-FILE
-DEF_VER=v2.3.0
+DEF_VER=v2.3.2
 
 LF='
 '
index c44eb3a8511c1d179113c241245f4a0ba8dc2787..44f1dd10ff508c03d10704f497c32868762243ce 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -348,6 +348,15 @@ all::
 #
 # Define NO_HMAC_CTX_CLEANUP if your OpenSSL is version 0.9.6b or earlier to
 # cleanup the HMAC context with the older HMAC_cleanup function.
+#
+# Define USE_PARENS_AROUND_GETTEXT_N to "yes" if your compiler happily
+# compiles the following initialization:
+#
+#   static const char s[] = ("FOO");
+#
+# and define it to "no" if you need to remove the parentheses () around the
+# constant.  The default is "auto", which means to use parentheses if your
+# compiler is detected to support it.
 
 GIT-VERSION-FILE: FORCE
        @$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -955,6 +964,14 @@ ifneq (,$(SOCKLEN_T))
        BASIC_CFLAGS += -Dsocklen_t=$(SOCKLEN_T)
 endif
 
+ifeq (yes,$(USE_PARENS_AROUND_GETTEXT_N))
+       BASIC_CFLAGS += -DUSE_PARENS_AROUND_GETTEXT_N=1
+else
+ifeq (no,$(USE_PARENS_AROUND_GETTEXT_N))
+       BASIC_CFLAGS += -DUSE_PARENS_AROUND_GETTEXT_N=0
+endif
+endif
+
 ifeq ($(uname_S),Darwin)
        ifndef NO_FINK
                ifeq ($(shell test -d /sw/lib && echo y),y)
@@ -1035,13 +1052,13 @@ else
        REMOTE_CURL_NAMES = $(REMOTE_CURL_PRIMARY) $(REMOTE_CURL_ALIASES)
        PROGRAM_OBJS += http-fetch.o
        PROGRAMS += $(REMOTE_CURL_NAMES)
-       curl_check := $(shell (echo 070908; curl-config --vernum) 2>/dev/null | sort -r | sed -ne 2p)
+       curl_check := $(shell (echo 070908; curl-config --vernum | sed -e '/^70[BC]/s/^/0/') 2>/dev/null | sort -r | sed -ne 2p)
        ifeq "$(curl_check)" "070908"
                ifndef NO_EXPAT
                        PROGRAM_OBJS += http-push.o
                endif
        endif
-       curl_check := $(shell (echo 072200; curl-config --vernum) 2>/dev/null | sort -r | sed -ne 2p)
+       curl_check := $(shell (echo 072200; curl-config --vernum | sed -e '/^70[BC]/s/^/0/') 2>/dev/null | sort -r | sed -ne 2p)
        ifeq "$(curl_check)" "072200"
                USE_CURL_FOR_IMAP_SEND = YesPlease
        endif
deleted file mode 120000 (symlink)
index 9257c74b5cff52da962e55a4f96d0b9d974cf362..0000000000000000000000000000000000000000
--- a/RelNotes
+++ /dev/null
@@ -1 +0,0 @@
-Documentation/RelNotes/2.3.0.txt
\ No newline at end of file
new file mode 100644 (file)
index 0000000000000000000000000000000000000000..44fb26121da20de8d579d6c86bfd5b6e1134efa6
--- /dev/null
+++ b/RelNotes
@@ -0,0 +1,292 @@
+Git ???? Release Notes
+======================
+
+Updates since v2.3
+------------------
+
+Ports
+
+ * Our default I/O size (8 MiB) for large files was too large for some
+   platforms with smaller SSIZE_MAX, leading to read(2)/write(2)
+   failures.
+
+ * We did not check the curl library version before using
+   CURLOPT_PROXYAUTH feature that may not exist.
+
+
+UI, Workflows & Features
+
+ * The command usage info strings given by "git cmd -h" and in
+   documentation have been tweaked for consistency.
+
+ * The "sync" subcommand of "git p4" now allows users to exclude
+   subdirectories like its "clone" subcommand does.
+
+ * "git log --invert-grep --grep=WIP" will show only commits that do
+   not have the string "WIP" in their messages.
+
+ * "git push" has been taught a "--atomic" option that makes push to
+   update more than one ref an "all-or-none" affair.
+
+ * Extending the "push to deploy" added in 2.3, the behaviour of "git
+   push" when updating the branch that is checked out can now be
+   tweaked by push-to-checkout hook.
+
+ * Using environment variable LANGUAGE and friends on the client side,
+   HTTP-based transports now send Accept-Language when making requests.
+
+ * "git send-email" used to accept a mistaken "y" (or "yes") as an
+   answer to "What encoding do you want to use [UTF-8]? " without
+   questioning.  Now it asks for confirmation when the answer looks
+   too short to be a valid encoding name.
+
+ * When "git apply --whitespace=fix" fixed whitespace errors in the
+   common context lines, the command reports that it did so.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Implementation of N_() macro has been updated slightly to help us
+   detect mistakes.
+
+ * Implementation of "reflog expire" has been restructured to fit the
+   reflogs better with the recently updated ref API.
+
+ * The transport-helper did not give transport options such as
+   verbosity, progress, cloning, etc. to import and export based
+   helpers, like it did for fetch and push based helpers, robbing them
+   the chance to honor the wish of the end-users better.
+
+ * The tests that wanted to see that file becomes unreadable after
+   running "chmod a-r file", and the tests that wanted to make sure it
+   is not run as root, we used "can we write into the / directory?" as
+   a cheap substitute, but on some platforms that is not a good
+   heuristics.  The tests and their prerequisites have been updated to
+   check what they really require.
+   (merge f400e51 jk/sanity later to maint).
+
+ * The strbuf API was explained between the API documentation and in
+   the header file.  Move missing bits to strbuf.h so that programmers
+   can check only one place for all necessary information.
+
+ * The error handling functions and conventions are now documented in
+   the API manual.
+
+ * Optimize attribute look-up, mostly useful in "git grep" on a
+   project that does not use many attributes, by avoiding it when we
+   (should) know that the attributes are not defined in the first
+   place.
+
+ * Typofix in comments.
+   (merge ef2956a ak/git-pm-typofix later to maint).
+
+ * Code clean-up.
+   (merge 0b868f0 sb/hex-object-name-is-at-most-41-bytes-long later to maint).
+   (merge 5d30851 dp/remove-duplicated-header-inclusion later to maint).
+
+ * Simplify the ref transaction API around how "the ref should be
+   pointing at this object" is specified.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.3
+----------------
+
+Unless otherwise noted, all the fixes since v2.3 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * "git blame HEAD -- missing" failed to correctly say "HEAD" when it
+   tried to say "No such path 'missing' in HEAD".
+   (merge a46442f jk/blame-commit-label later to maint).
+
+ * "git rerere" (invoked internally from many mergy operations) did
+   not correctly signal errors when told to update the working tree
+   files and failed to do so for whatever reason.
+   (merge 89ea903 jn/rerere-fail-on-auto-update-failure later to maint).
+
+ * Setting diff.submodule to 'log' made "git format-patch" produce
+   broken patches.
+   (merge 339de50 dk/format-patch-ignore-diff-submodule later to maint).
+
+ * After attempting and failing a password-less authentication
+   (e.g. kerberos), libcURL refuses to fall back to password based
+   Basic authentication without a bit of help/encouragement.
+   (merge 4dbe664 bc/http-fallback-to-password-after-krb-fails later to maint).
+
+ * The "git push" documentation made the "--repo=<there>" option
+   easily misunderstood.
+   (merge 57b92a7 mg/push-repo-option-doc later to maint).
+
+ * Code to read branch name from various files in .git/ directory
+   would have misbehaved if the code to write them left an empty file.
+   (merge 66ec904 jk/status-read-branch-name-fix later to maint).
+
+ * A misspelled conditional that is always true has been fixed.
+   (merge 94ee8e2 jk/remote-curl-an-array-in-struct-cannot-be-null later to maint).
+
+ * The documentation incorrectly said that C(opy) and R(ename) are the
+   only ones that can be followed by the score number in the output in
+   the --raw format.
+   (merge ac1c2d9 jc/diff-format-doc later to maint).
+
+ * A broken pack .idx file in the receiving repository prevented the
+   dumb http transport from fetching a good copy of it from the other
+   side.
+   (merge 8b9c2dd jk/dumb-http-idx-fetch-fix later to maint).
+
+ * The error message from "git commit", when a non-existing author
+   name was given as value to the "--author=" parameter, has been
+   reworded to avoid misunderstanding.
+   (merge 1044b1f mg/commit-author-no-match-malformed-message later to maint).
+
+ * "git log --help" used to show rev-list options that are irrelevant
+   to the "log" command.
+   (merge 3cab02d jc/doc-log-rev-list-options later to maint).
+
+ * "git apply --whitespace=fix" used to under-allocate the memory when
+   the fix resulted in a longer text than the original patch.
+   (merge 407a792 jc/apply-ws-fix-expands later to maint).
+
+ * The interactive "show a list and let the user choose from it"
+   interface "add -i" used showed and prompted to the user even when
+   the candidate list was empty, against which the only "choice" the
+   user could have made was to choose nothing.
+   (merge a9c4641 ak/add-i-empty-candidates later to maint).
+
+ * The insn sheet "git rebase -i" creates did not fully honor
+   core.abbrev settings.
+   (merge edb72d5 ks/rebase-i-abbrev later to maint).
+
+ * "git fetch" over a remote-helper that cannot respond to "list"
+   command could not fetch from a symbolic reference e.g. HEAD.
+   (merge 33cae54 mh/deref-symref-over-helper-transport later to maint).
+
+ * "git push --signed" gave an incorrectly worded error message when
+   the other side did not support the capability.
+   (merge 45917f0 jc/push-cert later to maint).
+
+ * We didn't format an integer that wouldn't fit in "int" but in
+   "uintmax_t" correctly.
+   (merge d306f3d jk/decimal-width-for-uintmax later to maint).
+
+ * Reading configuration from a blob object, when it ends with a lone
+   CR, use to confuse the configuration parser.
+   (merge 1d0655c jk/config-no-ungetc-eof later to maint).
+
+ * The pack bitmap support did not build with older versions of GCC.
+   (merge bd4e882 jk/pack-bitmap later to maint).
+
+ * The documentation wasn't clear that "remote.<nick>.pushURL" and
+   "remote.<nick>.URL" are there to name the same repository accessed
+   via different transports, not two separate repositories.
+   (merge 697f652 jc/remote-set-url-doc later to maint).
+
+ * Older GnuPG implementations may not correctly import the keyring
+   material we prepare for the tests to use.
+   (merge 1f985d6 ch/new-gpg-drops-rfc-1991 later to maint).
+
+ * The credential helper for Windows (in contrib/) used to mishandle
+   a user name with an at-sign in it.
+   (merge 13d261e av/wincred-with-at-in-username-fix later to maint).
+
+ * Longstanding configuration variable naming rules has been added to
+   the documentation.
+   (merge 35840a3 jc/conf-var-doc later to maint).
+
+ * An earlier workaround to squelch unhelpful deprecation warnings
+   from the complier on Mac OSX unnecessarily set minimum required
+   version of the OS, which the user might want to raise (or lower)
+   for other reasons.
+   (merge 88c03eb es/squelch-openssl-warnings-on-macosx later to maint).
+
+ * Certain older vintages of cURL give irregular output from
+   "curl-config --vernum", which confused our build system.
+   (merge 3af6792 tc/curl-vernum-output-broken-in-7.11 later to maint).
+
+ * In v2.2.0, we broke "git prune" that runs in a repository that
+   borrows from an alternate object store.
+   (merge b0a4264 jk/prune-mtime later to maint).
+
+ * "git submodule add" failed to squash "path/to/././submodule" to
+   "path/to/submodule".
+   (merge 8196e72 ps/submodule-sanitize-path-upon-add later to maint).
+
+ * "git merge-file" did not work correctly in a subdirectory.
+   (merge 204a8ff ab/merge-file-prefix later to maint).
+
+ * "git blame" died, trying to free an uninitialized piece of memory.
+   (merge e600592 es/blame-commit-info-fix later to maint).
+
+ * "git fast-import" used to crash when it could not close and
+   conclude the resulting packfile cleanly.
+   (merge 5e915f3 jk/fast-import-die-nicely-fix later to maint).
+
+ * "update-index --refresh" used to leak when an entry cannot be
+   refreshed for whatever reason.
+   (merge bc1c2ca sb/plug-leak-in-make-cache-entry later to maint).
+
+ * The "interpolated-path" option of "git daemon" inserted any string
+   client declared on the "host=" capability request without checking.
+   Sanitize and limit %H and %CH to a saner and a valid DNS name.
+   (merge b485373 jk/daemon-interpolate later to maint).
+
+ * "git daemon" looked up the hostname even when "%CH" and "%IP"
+   interpolations are not requested, which was unnecessary.
+   (merge dc8edc8 rs/daemon-interpolate later to maint).
+
+ * Even though we officially haven't dropped Perl 5.8 support, the
+   Getopt::Long package that came with it does not support "--no-"
+   prefix to negate a boolean option; manually add support to help
+   people with older Getopt::Long package.
+   (merge f471494 km/send-email-getopt-long-workarounds later to maint).
+
+ * "git apply" was not very careful about reading from, removing,
+   updating and creating paths outside the working tree (under
+   --index/--cached) or the current directory (when used as a
+   replacement for GNU patch).
+   (merge e0d201b jc/apply-beyond-symlink later to maint).
+
+ * A breakage to git-svn around v2.2 era that triggers premature
+   closing of FileHandle has been corrected.
+   (merge e426311 ew/svn-maint-fixes later to maint).
+
+ * We did not parse username followed by literal IPv6 address in SSH
+   transport URLs, e.g. ssh://user@[2001:db8::1]:22/repo.git
+   correctly.
+   (merge 3f55cca tb/connect-ipv6-parse-fix later to maint).
+
+ * The configuration variable 'mailinfo.scissors' was hard to
+   discover in the documentation.
+   (merge afb5de7 mm/am-c-doc later to maint).
+
+ * The interaction between "git submodule update" and the
+   submodule.*.update configuration was not clearly documented.
+   (merge 5c31acf ms/submodule-update-config-doc later to maint).
+
+ * "git diff --shortstat --dirstat=changes" showed a dirstat based on
+   lines that was never asked by the end user in addition to the
+   dirstat that the user asked for.
+   (merge ab27389 mk/diff-shortstat-dirstat-fix later to maint).
+
+ * "git remote add" mentioned "--tags" and "--no-tags" and was not
+   clear that fetch from the remote in the future will use the default
+   behaviour when neither is given to override it.
+   (merge aaba0ab mg/doc-remote-tags-or-not later to maint).
+
+ * Description given by "grep -h" for its --exclude-standard option
+   was phrased poorly.
+   (merge 77fdb8a nd/grep-exclude-standard-help-fix later to maint).
+
+ * The borrowed code in kwset API did not follow our usual convention
+   to use "unsigned char" to store values that range from 0-255.
+   (merge 189c860 bw/kwset-use-unsigned later to maint).
+
+ * Code cleanups and documentaiton updates.
+   (merge 2ce63e9 rs/simple-cleanups later to maint).
+   (merge 33baa69 rj/no-xopen-source-for-cygwin later to maint).
+   (merge 817d03e jc/diff-test-updates later to maint).
+   (merge eb32c66 ak/t5516-typofix later to maint).
+   (merge bcd57cb mr/doc-clean-f-f later to maint).
index 3b8bf3c6da6afdd5ef4cfcc77131690ccbbf3757..575bec20b35a31e653e49125386f3dcee880c217 100644 (file)
--- a/advice.c
+++ b/advice.c
@@ -105,7 +105,7 @@ void detach_advice(const char *new_name)
        "state without impacting any branches by performing another checkout.\n\n"
        "If you want to create a new branch to retain commits you create, you may\n"
        "do so (now or later) by using -b with the checkout command again. Example:\n\n"
-       "  git checkout -b new_branch_name\n\n";
+       "  git checkout -b <new-branch-name>\n\n";
 
        fprintf(stderr, fmt, new_name);
 }
index 9e30246b6402454e8d92fb6aa24a1a07c534b0ef..96057ed830e521a5f12b0a73b4a04a6b5e581e87 100644 (file)
--- a/archive.c
+++ b/archive.c
@@ -8,9 +8,9 @@
 #include "dir.h"
 
 static char const * const archive_usage[] = {
-       N_("git archive [options] <tree-ish> [<path>...]"),
+       N_("git archive [<options>] <tree-ish> [<path>...]"),
        N_("git archive --list"),
-       N_("git archive --remote <repo> [--exec <cmd>] [options] <tree-ish> [<path>...]"),
+       N_("git archive --remote <repo> [--exec <cmd>] [<options>] <tree-ish> [<path>...]"),
        N_("git archive --remote <repo> [--exec <cmd>] --list"),
        NULL
 };
diff --git a/attr.c b/attr.c
index cd5469770a6f7841ae327e6ba7141dd99d9cacc1..1f9eebd2ddb7fe8a561500c41f33a52d1fb4fdd1 100644 (file)
--- a/attr.c
+++ b/attr.c
@@ -32,9 +32,12 @@ struct git_attr {
        struct git_attr *next;
        unsigned h;
        int attr_nr;
+       int maybe_macro;
+       int maybe_real;
        char name[FLEX_ARRAY];
 };
 static int attr_nr;
+static int cannot_trust_maybe_real;
 
 static struct git_attr_check *check_all_attr;
 static struct git_attr *(git_attr_hash[HASHSIZE]);
@@ -95,6 +98,8 @@ static struct git_attr *git_attr_internal(const char *name, int len)
        a->h = hval;
        a->next = git_attr_hash[pos];
        a->attr_nr = attr_nr++;
+       a->maybe_macro = 0;
+       a->maybe_real = 0;
        git_attr_hash[pos] = a;
 
        REALLOC_ARRAY(check_all_attr, attr_nr);
@@ -244,9 +249,10 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
                      sizeof(*res) +
                      sizeof(struct attr_state) * num_attr +
                      (is_macro ? 0 : namelen + 1));
-       if (is_macro)
+       if (is_macro) {
                res->u.attr = git_attr_internal(name, namelen);
-       else {
+               res->u.attr->maybe_macro = 1;
+       } else {
                char *p = (char *)&(res->state[num_attr]);
                memcpy(p, name, namelen);
                res->u.pat.pattern = p;
@@ -266,6 +272,10 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
        /* Second pass to fill the attr_states */
        for (cp = states, i = 0; *cp; i++) {
                cp = parse_attr(src, lineno, cp, &(res->state[i]));
+               if (!is_macro)
+                       res->state[i].attr->maybe_real = 1;
+               if (res->state[i].attr->maybe_macro)
+                       cannot_trust_maybe_real = 1;
        }
 
        return res;
@@ -681,13 +691,14 @@ static int fill(const char *path, int pathlen, int basename_offset,
        return rem;
 }
 
-static int macroexpand_one(int attr_nr, int rem)
+static int macroexpand_one(int nr, int rem)
 {
        struct attr_stack *stk;
        struct match_attr *a = NULL;
        int i;
 
-       if (check_all_attr[attr_nr].value != ATTR__TRUE)
+       if (check_all_attr[nr].value != ATTR__TRUE ||
+           !check_all_attr[nr].attr->maybe_macro)
                return rem;
 
        for (stk = attr_stack; !a && stk; stk = stk->prev)
@@ -695,7 +706,7 @@ static int macroexpand_one(int attr_nr, int rem)
                        struct match_attr *ma = stk->attrs[i];
                        if (!ma->is_macro)
                                continue;
-                       if (ma->u.attr->attr_nr == attr_nr)
+                       if (ma->u.attr->attr_nr == nr)
                                a = ma;
                }
 
@@ -706,10 +717,13 @@ static int macroexpand_one(int attr_nr, int rem)
 }
 
 /*
- * Collect all attributes for path into the array pointed to by
- * check_all_attr.
+ * Collect attributes for path into the array pointed to by
+ * check_all_attr. If num is non-zero, only attributes in check[] are
+ * collected. Otherwise all attributes are collected.
  */
-static void collect_all_attrs(const char *path)
+static void collect_some_attrs(const char *path, int num,
+                              struct git_attr_check *check)
+
 {
        struct attr_stack *stk;
        int i, pathlen, rem, dirlen;
@@ -732,6 +746,19 @@ static void collect_all_attrs(const char *path)
        prepare_attr_stack(path, dirlen);
        for (i = 0; i < attr_nr; i++)
                check_all_attr[i].value = ATTR__UNKNOWN;
+       if (num && !cannot_trust_maybe_real) {
+               rem = 0;
+               for (i = 0; i < num; i++) {
+                       if (!check[i].attr->maybe_real) {
+                               struct git_attr_check *c;
+                               c = check_all_attr + check[i].attr->attr_nr;
+                               c->value = ATTR__UNSET;
+                               rem++;
+                       }
+               }
+               if (rem == num)
+                       return;
+       }
 
        rem = attr_nr;
        for (stk = attr_stack; 0 < rem && stk; stk = stk->prev)
@@ -742,7 +769,7 @@ int git_check_attr(const char *path, int num, struct git_attr_check *check)
 {
        int i;
 
-       collect_all_attrs(path);
+       collect_some_attrs(path, num, check);
 
        for (i = 0; i < num; i++) {
                const char *value = check_all_attr[check[i].attr->attr_nr].value;
@@ -758,7 +785,7 @@ int git_all_attrs(const char *path, int *num, struct git_attr_check **check)
 {
        int i, count, j;
 
-       collect_all_attrs(path);
+       collect_some_attrs(path, 0, NULL);
 
        /* Count the number of attributes that are set. */
        count = 0;
index 4bab55a9a85e187e2a3906312f1e771f4a214f45..b0024353f4409c8b54c4b569b8fb7c435b26cdae 100644 (file)
--- a/branch.c
+++ b/branch.c
@@ -284,8 +284,9 @@ void create_branch(const char *head,
 
                transaction = ref_transaction_begin(&err);
                if (!transaction ||
-                   ref_transaction_update(transaction, ref.buf, sha1,
-                                          null_sha1, 0, !forcing, msg, &err) ||
+                   ref_transaction_update(transaction, ref.buf,
+                                          sha1, forcing ? NULL : null_sha1,
+                                          0, msg, &err) ||
                    ref_transaction_commit(transaction, &err))
                        die("%s", err.buf);
                ref_transaction_free(transaction);
index 1074e3234964deb279c3a487e9efd164afdb9c6c..3390933d68b2dd6c7296a7d2103d009fa27f2ca8 100644 (file)
@@ -19,7 +19,7 @@
 #include "argv-array.h"
 
 static const char * const builtin_add_usage[] = {
-       N_("git add [options] [--] <pathspec>..."),
+       N_("git add [<options>] [--] <pathspec>..."),
        NULL
 };
 static int patch_interactive, add_interactive, edit_interactive;
index 0aad91283959bce51aba596c6f3d2d0925e5ba92..65b97eee69d4814bf80f87b1fd6857b8ed80cb90 100644 (file)
@@ -51,11 +51,12 @@ static int apply_verbosely;
 static int allow_overlap;
 static int no_add;
 static int threeway;
+static int unsafe_paths;
 static const char *fake_ancestor;
 static int line_termination = '\n';
 static unsigned int p_context = UINT_MAX;
 static const char * const apply_usage[] = {
-       N_("git apply [options] [<patch>...]"),
+       N_("git apply [<options>] [<patch>...]"),
        NULL
 };
 
@@ -657,11 +658,6 @@ static size_t diff_timestamp_len(const char *line, size_t len)
        return line + len - end;
 }
 
-static char *null_strdup(const char *s)
-{
-       return s ? xstrdup(s) : NULL;
-}
-
 static char *find_name_common(const char *line, const char *def,
                              int p_value, const char *end, int terminate)
 {
@@ -684,10 +680,10 @@ static char *find_name_common(const char *line, const char *def,
                        start = line;
        }
        if (!start)
-               return squash_slash(null_strdup(def));
+               return squash_slash(xstrdup_or_null(def));
        len = line - start;
        if (!len)
-               return squash_slash(null_strdup(def));
+               return squash_slash(xstrdup_or_null(def));
 
        /*
         * Generally we prefer the shorter name, especially
@@ -909,7 +905,7 @@ static void parse_traditional_patch(const char *first, const char *second, struc
                        patch->old_name = name;
                } else {
                        patch->old_name = name;
-                       patch->new_name = null_strdup(name);
+                       patch->new_name = xstrdup_or_null(name);
                }
        }
        if (!name)
@@ -998,7 +994,7 @@ static int gitdiff_delete(const char *line, struct patch *patch)
 {
        patch->is_delete = 1;
        free(patch->old_name);
-       patch->old_name = null_strdup(patch->def_name);
+       patch->old_name = xstrdup_or_null(patch->def_name);
        return gitdiff_oldmode(line, patch);
 }
 
@@ -1006,7 +1002,7 @@ static int gitdiff_newfile(const char *line, struct patch *patch)
 {
        patch->is_new = 1;
        free(patch->new_name);
-       patch->new_name = null_strdup(patch->def_name);
+       patch->new_name = xstrdup_or_null(patch->def_name);
        return gitdiff_newmode(line, patch);
 }
 
@@ -1605,6 +1601,9 @@ static int parse_fragment(const char *line, unsigned long size,
                        if (!deleted && !added)
                                leading++;
                        trailing++;
+                       if (!apply_in_reverse &&
+                           ws_error_action == correct_ws_error)
+                               check_whitespace(line, len, patch->ws_rule);
                        break;
                case '-':
                        if (apply_in_reverse &&
@@ -2235,6 +2234,12 @@ static void update_pre_post_images(struct image *preimage,
                ctx++;
        }
 
+       if (postlen
+           ? postlen < new - postimage->buf
+           : postimage->len < new - postimage->buf)
+               die("BUG: caller miscounted postlen: asked %d, orig = %d, used = %d",
+                   (int)postlen, (int) postimage->len, (int)(new - postimage->buf));
+
        /* Fix the length of the whole thing */
        postimage->len = new - postimage->buf;
        postimage->nr -= reduced;
@@ -2390,10 +2395,27 @@ static int match_fragment(struct image *img,
 
        /*
         * The hunk does not apply byte-by-byte, but the hash says
-        * it might with whitespace fuzz. We haven't been asked to
+        * it might with whitespace fuzz. We weren't asked to
         * ignore whitespace, we were asked to correct whitespace
         * errors, so let's try matching after whitespace correction.
         *
+        * While checking the preimage against the target, whitespace
+        * errors in both fixed, we count how large the corresponding
+        * postimage needs to be.  The postimage prepared by
+        * apply_one_fragment() has whitespace errors fixed on added
+        * lines already, but the common lines were propagated as-is,
+        * which may become longer when their whitespace errors are
+        * fixed.
+        */
+
+       /* First count added lines in postimage */
+       postlen = 0;
+       for (i = 0; i < postimage->nr; i++) {
+               if (!(postimage->line[i].flag & LINE_COMMON))
+                       postlen += postimage->line[i].len;
+       }
+
+       /*
         * The preimage may extend beyond the end of the file,
         * but in this loop we will only handle the part of the
         * preimage that falls within the file.
@@ -2401,7 +2423,6 @@ static int match_fragment(struct image *img,
        strbuf_init(&fixed, preimage->len + 1);
        orig = preimage->buf;
        target = img->buf + try;
-       postlen = 0;
        for (i = 0; i < preimage_limit; i++) {
                size_t oldlen = preimage->line[i].len;
                size_t tgtlen = img->line[try_lno + i].len;
@@ -2429,7 +2450,10 @@ static int match_fragment(struct image *img,
                match = (tgtfix.len == fixed.len - fixstart &&
                         !memcmp(tgtfix.buf, fixed.buf + fixstart,
                                             fixed.len - fixstart));
-               postlen += tgtfix.len;
+
+               /* Add the length if this is common with the postimage */
+               if (preimage->line[i].flag & LINE_COMMON)
+                       postlen += tgtfix.len;
 
                strbuf_release(&tgtfix);
                if (!match)
@@ -3201,7 +3225,7 @@ static int load_patch_target(struct strbuf *buf,
                             const char *name,
                             unsigned expected_mode)
 {
-       if (cached) {
+       if (cached || check_index) {
                if (read_file_or_gitlink(ce, buf))
                        return error(_("read of %s failed"), name);
        } else if (name) {
@@ -3210,6 +3234,8 @@ static int load_patch_target(struct strbuf *buf,
                                return read_file_or_gitlink(ce, buf);
                        else
                                return SUBMODULE_PATCH_WITHOUT_INDEX;
+               } else if (has_symlink_leading_path(name, strlen(name))) {
+                       return error(_("reading from '%s' beyond a symbolic link"), name);
                } else {
                        if (read_old_data(st, name, buf))
                                return error(_("read of %s failed"), name);
@@ -3549,6 +3575,121 @@ static int check_to_create(const char *new_name, int ok_if_exists)
        return 0;
 }
 
+/*
+ * We need to keep track of how symlinks in the preimage are
+ * manipulated by the patches.  A patch to add a/b/c where a/b
+ * is a symlink should not be allowed to affect the directory
+ * the symlink points at, but if the same patch removes a/b,
+ * it is perfectly fine, as the patch removes a/b to make room
+ * to create a directory a/b so that a/b/c can be created.
+ */
+static struct string_list symlink_changes;
+#define SYMLINK_GOES_AWAY 01
+#define SYMLINK_IN_RESULT 02
+
+static uintptr_t register_symlink_changes(const char *path, uintptr_t what)
+{
+       struct string_list_item *ent;
+
+       ent = string_list_lookup(&symlink_changes, path);
+       if (!ent) {
+               ent = string_list_insert(&symlink_changes, path);
+               ent->util = (void *)0;
+       }
+       ent->util = (void *)(what | ((uintptr_t)ent->util));
+       return (uintptr_t)ent->util;
+}
+
+static uintptr_t check_symlink_changes(const char *path)
+{
+       struct string_list_item *ent;
+
+       ent = string_list_lookup(&symlink_changes, path);
+       if (!ent)
+               return 0;
+       return (uintptr_t)ent->util;
+}
+
+static void prepare_symlink_changes(struct patch *patch)
+{
+       for ( ; patch; patch = patch->next) {
+               if ((patch->old_name && S_ISLNK(patch->old_mode)) &&
+                   (patch->is_rename || patch->is_delete))
+                       /* the symlink at patch->old_name is removed */
+                       register_symlink_changes(patch->old_name, SYMLINK_GOES_AWAY);
+
+               if (patch->new_name && S_ISLNK(patch->new_mode))
+                       /* the symlink at patch->new_name is created or remains */
+                       register_symlink_changes(patch->new_name, SYMLINK_IN_RESULT);
+       }
+}
+
+static int path_is_beyond_symlink_1(struct strbuf *name)
+{
+       do {
+               unsigned int change;
+
+               while (--name->len && name->buf[name->len] != '/')
+                       ; /* scan backwards */
+               if (!name->len)
+                       break;
+               name->buf[name->len] = '\0';
+               change = check_symlink_changes(name->buf);
+               if (change & SYMLINK_IN_RESULT)
+                       return 1;
+               if (change & SYMLINK_GOES_AWAY)
+                       /*
+                        * This cannot be "return 0", because we may
+                        * see a new one created at a higher level.
+                        */
+                       continue;
+
+               /* otherwise, check the preimage */
+               if (check_index) {
+                       struct cache_entry *ce;
+
+                       ce = cache_file_exists(name->buf, name->len, ignore_case);
+                       if (ce && S_ISLNK(ce->ce_mode))
+                               return 1;
+               } else {
+                       struct stat st;
+                       if (!lstat(name->buf, &st) && S_ISLNK(st.st_mode))
+                               return 1;
+               }
+       } while (1);
+       return 0;
+}
+
+static int path_is_beyond_symlink(const char *name_)
+{
+       int ret;
+       struct strbuf name = STRBUF_INIT;
+
+       assert(*name_ != '\0');
+       strbuf_addstr(&name, name_);
+       ret = path_is_beyond_symlink_1(&name);
+       strbuf_release(&name);
+
+       return ret;
+}
+
+static void die_on_unsafe_path(struct patch *patch)
+{
+       const char *old_name = NULL;
+       const char *new_name = NULL;
+       if (patch->is_delete)
+               old_name = patch->old_name;
+       else if (!patch->is_new && !patch->is_copy)
+               old_name = patch->old_name;
+       if (!patch->is_delete)
+               new_name = patch->new_name;
+
+       if (old_name && !verify_path(old_name))
+               die(_("invalid path '%s'"), old_name);
+       if (new_name && !verify_path(new_name))
+               die(_("invalid path '%s'"), new_name);
+}
+
 /*
  * Check and apply the patch in-core; leave the result in patch->result
  * for the caller to write it out to the final destination.
@@ -3636,6 +3777,22 @@ static int check_patch(struct patch *patch)
                }
        }
 
+       if (!unsafe_paths)
+               die_on_unsafe_path(patch);
+
+       /*
+        * An attempt to read from or delete a path that is beyond a
+        * symbolic link will be prevented by load_patch_target() that
+        * is called at the beginning of apply_data() so we do not
+        * have to worry about a patch marked with "is_delete" bit
+        * here.  We however need to make sure that the patch result
+        * is not deposited to a path that is beyond a symbolic link
+        * here.
+        */
+       if (!patch->is_delete && path_is_beyond_symlink(patch->new_name))
+               return error(_("affected file '%s' is beyond a symbolic link"),
+                            patch->new_name);
+
        if (apply_data(patch, &st, ce) < 0)
                return error(_("%s: patch does not apply"), name);
        patch->rejected = 0;
@@ -3646,6 +3803,7 @@ static int check_patch_list(struct patch *patch)
 {
        int err = 0;
 
+       prepare_symlink_changes(patch);
        prepare_fn_table(patch);
        while (patch) {
                if (apply_verbosely)
@@ -4384,6 +4542,8 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
                        N_("make sure the patch is applicable to the current index")),
                OPT_BOOL(0, "cached", &cached,
                        N_("apply a patch without touching the working tree")),
+               OPT_BOOL(0, "unsafe-paths", &unsafe_paths,
+                       N_("accept a patch that touches outside the working area")),
                OPT_BOOL(0, "apply", &force_apply,
                        N_("also apply the patch (use with --stat/--summary/--check)")),
                OPT_BOOL('3', "3way", &threeway,
@@ -4456,6 +4616,9 @@ int cmd_apply(int argc, const char **argv, const char *prefix_)
                        die(_("--cached outside a repository"));
                check_index = 1;
        }
+       if (check_index)
+               unsafe_paths = 0;
+
        for (i = 0; i < argc; i++) {
                const char *arg = argv[i];
                int fd;
index 303e217ae919f21aa4d4574bd1720b5f4d635c32..06484c2e0e23237bff711bbe3cda6e1382004ef3 100644 (file)
 #include "line-range.h"
 #include "line-log.h"
 
-static char blame_usage[] = N_("git blame [options] [rev-opts] [rev] [--] file");
+static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] file");
 
 static const char *blame_opt_usage[] = {
        blame_usage,
        "",
-       N_("[rev-opts] are documented in git-rev-list(1)"),
+       N_("<rev-opts> are documented in git-rev-list(1)"),
        NULL
 };
 
@@ -2085,7 +2085,6 @@ static void find_alignment(struct scoreboard *sb, int *option)
 
        for (e = sb->ent; e; e = e->next) {
                struct origin *suspect = e->suspect;
-               struct commit_info ci;
                int num;
 
                if (compute_auto_abbrev)
@@ -2096,6 +2095,7 @@ static void find_alignment(struct scoreboard *sb, int *option)
                if (longest_file < num)
                        longest_file = num;
                if (!(suspect->commit->object.flags & METAINFO_SHOWN)) {
+                       struct commit_info ci;
                        suspect->commit->object.flags |= METAINFO_SHOWN;
                        get_commit_info(suspect->commit, &ci, 1);
                        if (*option & OUTPUT_SHOW_EMAIL)
@@ -2104,6 +2104,7 @@ static void find_alignment(struct scoreboard *sb, int *option)
                                num = utf8_strwidth(ci.author.buf);
                        if (longest_author < num)
                                longest_author = num;
+                       commit_info_destroy(&ci);
                }
                num = e->s_lno + e->num_lines;
                if (longest_src_lines < num)
@@ -2113,8 +2114,6 @@ static void find_alignment(struct scoreboard *sb, int *option)
                        longest_dst_lines = num;
                if (largest_score < ent_score(sb, e))
                        largest_score = ent_score(sb, e);
-
-               commit_info_destroy(&ci);
        }
        max_orig_digits = decimal_width(longest_src_lines);
        max_digits = decimal_width(longest_dst_lines);
@@ -2390,7 +2389,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
        return commit;
 }
 
-static const char *prepare_final(struct scoreboard *sb)
+static char *prepare_final(struct scoreboard *sb)
 {
        int i;
        const char *final_commit_name = NULL;
@@ -2415,10 +2414,10 @@ static const char *prepare_final(struct scoreboard *sb)
                sb->final = (struct commit *) obj;
                final_commit_name = revs->pending.objects[i].name;
        }
-       return final_commit_name;
+       return xstrdup_or_null(final_commit_name);
 }
 
-static const char *prepare_initial(struct scoreboard *sb)
+static char *prepare_initial(struct scoreboard *sb)
 {
        int i;
        const char *final_commit_name = NULL;
@@ -2445,7 +2444,7 @@ static const char *prepare_initial(struct scoreboard *sb)
        }
        if (!final_commit_name)
                die("No commit to dig down to?");
-       return final_commit_name;
+       return xstrdup(final_commit_name);
 }
 
 static int blame_copy_callback(const struct option *option, const char *arg, int unset)
@@ -2489,7 +2488,7 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
        struct origin *o;
        struct blame_entry *ent = NULL;
        long dashdash_pos, lno;
-       const char *final_commit_name = NULL;
+       char *final_commit_name = NULL;
        enum object_type type;
 
        static struct string_list range_list;
@@ -2786,6 +2785,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 
        assign_blame(&sb, opt);
 
+       free(final_commit_name);
+
        if (incremental)
                return 0;
 
index dc6f0b266c9cf621486b9dba111c2e7b37d3bc1b..6a25957e9f9daff6ab127f8feb91d9349075741e 100644 (file)
 #include "wt-status.h"
 
 static const char * const builtin_branch_usage[] = {
-       N_("git branch [options] [-r | -a] [--merged | --no-merged]"),
-       N_("git branch [options] [-l] [-f] <branchname> [<start-point>]"),
-       N_("git branch [options] [-r] (-d | -D) <branchname>..."),
-       N_("git branch [options] (-m | -M) [<oldbranch>] <newbranch>"),
+       N_("git branch [<options>] [-r | -a] [--merged | --no-merged]"),
+       N_("git branch [<options>] [-l] [-f] <branch-name> [<start-point>]"),
+       N_("git branch [<options>] [-r] (-d | -D) <branch-name>..."),
+       N_("git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"),
        NULL
 };
 
index 31b133b357f34e9bc0a63dec5ce2dbceba43e765..df99df4db1ddb058368fe88f07c890d87600e6d9 100644 (file)
@@ -323,8 +323,8 @@ static int batch_objects(struct batch_options *opt)
 }
 
 static const char * const cat_file_usage[] = {
-       N_("git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>"),
-       N_("git cat-file (--batch|--batch-check) < <list_of_objects>"),
+       N_("git cat-file (-t | -s | -e | -p | <type> | --textconv) <object>"),
+       N_("git cat-file (--batch | --batch-check) < <list-of-objects>"),
        NULL
 };
 
index 5600ec3f6165ae04682f30481142452438f856af..21d2bedcc930ab216f2a55ec90ba188b2b66dfce 100644 (file)
@@ -8,8 +8,8 @@ static int all_attrs;
 static int cached_attrs;
 static int stdin_paths;
 static const char * const check_attr_usage[] = {
-N_("git check-attr [-a | --all | attr...] [--] pathname..."),
-N_("git check-attr --stdin [-z] [-a | --all | attr...] < <list-of-paths>"),
+N_("git check-attr [-a | --all | <attr>...] [--] <pathname>..."),
+N_("git check-attr --stdin [-z] [-a | --all | <attr>...] < <list-of-paths>"),
 NULL
 };
 
index 594463a11bcba3cf99748ccdaeb055bd79283ddd..dc8d97c56c60991ec5c1b5cc9eb6e20a76e5e405 100644 (file)
@@ -7,8 +7,8 @@
 
 static int quiet, verbose, stdin_paths, show_non_matching, no_index;
 static const char * const check_ignore_usage[] = {
-"git check-ignore [options] pathname...",
-"git check-ignore [options] --stdin < <list-of-paths>",
+"git check-ignore [<options>] <pathname>...",
+"git check-ignore [<options>] --stdin < <list-of-paths>",
 NULL
 };
 
index 8f4d809bd8c00558b34022cc0c46423a6b19243c..eaaea546d30871ad7442456f7eec4ae849f68374 100644 (file)
@@ -5,7 +5,7 @@
 
 static int use_stdin;
 static const char * const check_mailmap_usage[] = {
-N_("git check-mailmap [options] <contact>..."),
+N_("git check-mailmap [<options>] <contact>..."),
 NULL
 };
 
index 28a7320271a9555356170bfdb06ffb4b07bc9b92..fd915d59841ecc1098e2d8a4356947215377d4da 100644 (file)
@@ -8,7 +8,7 @@
 #include "strbuf.h"
 
 static const char builtin_check_ref_format_usage[] =
-"git check-ref-format [--normalize] [options] <refname>\n"
+"git check-ref-format [--normalize] [<options>] <refname>\n"
 "   or: git check-ref-format --branch <branchname-shorthand>";
 
 /*
index 031780f49e0b3a3e7a8e1aa4904e33858f11542d..9ca2da15836d161d5c28b9919eff0edf4347a446 100644 (file)
@@ -123,7 +123,7 @@ static void checkout_all(const char *prefix, int prefix_length)
 }
 
 static const char * const builtin_checkout_index_usage[] = {
-       N_("git checkout-index [options] [--] [<file>...]"),
+       N_("git checkout-index [<options>] [--] [<file>...]"),
        NULL
 };
 
index 52d6cbb0a84e2693fc53c88ca1fb4cd899b26a91..3e141fc1491949a2dbb47c59d7d156ae6fe4eb47 100644 (file)
@@ -22,8 +22,8 @@
 #include "argv-array.h"
 
 static const char * const checkout_usage[] = {
-       N_("git checkout [options] <branch>"),
-       N_("git checkout [options] [<branch>] -- <file>..."),
+       N_("git checkout [<options>] <branch>"),
+       N_("git checkout [<options>] [<branch>] -- <file>..."),
        NULL,
 };
 
@@ -746,7 +746,7 @@ static void suggest_reattach(struct commit *commit, struct rev_info *revs)
                        _(
                        "If you want to keep them by creating a new branch, "
                        "this may be a good time\nto do so with:\n\n"
-                       " git branch new_branch_name %s\n\n"),
+                       " git branch <new-branch-name> %s\n\n"),
                        find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
 }
 
@@ -1127,7 +1127,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "ignore-skip-worktree-bits", &opts.ignore_skipworktree,
                         N_("do not limit pathspecs to sparse entries only")),
                OPT_HIDDEN_BOOL(0, "guess", &dwim_new_local_branch,
-                               N_("second guess 'git checkout no-such-branch'")),
+                               N_("second guess 'git checkout <no-such-branch>'")),
                OPT_END(),
        };
 
index 7e7fdcfe54a547c90a5a6911eb59b0ec22151ac6..98c103fa8b4faa83c33a62e5d7871c1e9d888c38 100644 (file)
@@ -754,7 +754,8 @@ static int ask_each_cmd(void)
                /* Ctrl-D should stop removing files */
                if (!eof) {
                        qname = quote_path_relative(item->string, NULL, &buf);
-                       printf(_("remove %s? "), qname);
+                       /* TRANSLATORS: Make sure to keep [y/N] as is */
+                       printf(_("Remove %s [y/N]? "), qname);
                        if (strbuf_getline(&confirm, stdin, '\n') != EOF) {
                                strbuf_trim(&confirm);
                        } else {
index 316c75d0b342d039696608c18adfabaa3366b0e7..957246723e94ef6ad6df918ec18f8a1e5848a303 100644 (file)
@@ -34,7 +34,7 @@
  *
  */
 static const char * const builtin_clone_usage[] = {
-       N_("git clone [options] [--] <repo> [<dir>]"),
+       N_("git clone [<options>] [--] <repo> [<dir>]"),
        NULL
 };
 
index 75818520e1b74de607620e48d2d3afb131c6e896..449413c8a873ebcfa2ceaccae6b89a3f1245c117 100644 (file)
@@ -6,7 +6,7 @@
 #include "column.h"
 
 static const char * const builtin_column_usage[] = {
-       N_("git column [options]"),
+       N_("git column [<options>]"),
        NULL
 };
 static unsigned int colopts;
index 7d90c3591567d10f9a075ec38048b93923f707d4..961e467242747dac07aa6f5e619e2d1a50570b06 100644 (file)
 #include "mailmap.h"
 
 static const char * const builtin_commit_usage[] = {
-       N_("git commit [options] [--] <pathspec>..."),
+       N_("git commit [<options>] [--] <pathspec>..."),
        NULL
 };
 
 static const char * const builtin_status_usage[] = {
-       N_("git status [options] [--] <pathspec>..."),
+       N_("git status [<options>] [--] <pathspec>..."),
        NULL
 };
 
@@ -559,20 +559,14 @@ static void set_ident_var(char **buf, char *val)
        *buf = val;
 }
 
-static char *envdup(const char *var)
-{
-       const char *val = getenv(var);
-       return val ? xstrdup(val) : NULL;
-}
-
 static void determine_author_info(struct strbuf *author_ident)
 {
        char *name, *email, *date;
        struct ident_split author;
 
-       name = envdup("GIT_AUTHOR_NAME");
-       email = envdup("GIT_AUTHOR_EMAIL");
-       date = envdup("GIT_AUTHOR_DATE");
+       name = xstrdup_or_null(getenv("GIT_AUTHOR_NAME"));
+       email = xstrdup_or_null(getenv("GIT_AUTHOR_EMAIL"));
+       date = xstrdup_or_null(getenv("GIT_AUTHOR_DATE"));
 
        if (author_message) {
                struct ident_split ident;
@@ -1056,7 +1050,7 @@ static const char *find_author_by_nickname(const char *name)
                clear_mailmap(&mailmap);
                return strbuf_detach(&buf, NULL);
        }
-       die(_("No existing author found with '%s'"), name);
+       die(_("--author '%s' is not 'Name <email>' and matches no existing author"), name);
 }
 
 
@@ -1772,8 +1766,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        if (!transaction ||
            ref_transaction_update(transaction, "HEAD", sha1,
                                   current_head
-                                  ? current_head->object.sha1 : NULL,
-                                  0, !!current_head, sb.buf, &err) ||
+                                  ? current_head->object.sha1 : null_sha1,
+                                  0, sb.buf, &err) ||
            ref_transaction_commit(transaction, &err)) {
                rollback_index_files();
                die("%s", err.buf);
index 15a7bea936d667042cef27f83c86a863df2caa8f..d32c5327e53e14a7af72e4ec91efc1b42a414659 100644 (file)
@@ -5,7 +5,7 @@
 #include "urlmatch.h"
 
 static const char *const builtin_config_usage[] = {
-       N_("git config [options]"),
+       N_("git config [<options>]"),
        NULL
 };
 
index 9103193b4f65dc9e224051fb1e19eda6d9c7ae6a..e00a75b121826e89ee70cbedbfad760dc29640a0 100644 (file)
@@ -14,8 +14,8 @@
 #define MAX_TAGS       (FLAG_BITS - 1)
 
 static const char * const describe_usage[] = {
-       N_("git describe [options] <commit-ish>*"),
-       N_("git describe [options] --dirty"),
+       N_("git describe [<options>] [<commit-ish>...]"),
+       N_("git describe [<options>] --dirty"),
        NULL
 };
 
index 9200069363ff016d167f6885688650158c12e507..8ed2eb8813a442b64c8f43ed23acbdbd1c0dd452 100644 (file)
@@ -11,7 +11,7 @@
 #include "submodule.h"
 
 static const char diff_files_usage[] =
-"git diff-files [-q] [-0/-1/2/3 |-c|--cc] [<common diff options>] [<path>...]"
+"git diff-files [-q] [-0 | -1 | -2 | -3 | -c | --cc] [<common-diff-options>] [<path>...]"
 COMMON_DIFF_OPTIONS_HELP;
 
 int cmd_diff_files(int argc, const char **argv, const char *prefix)
index ce15b23042d8472573b88e0ee9a6032673321ea3..d979824f9395a0cbc8ffffa9cede524589710d43 100644 (file)
@@ -7,7 +7,7 @@
 
 static const char diff_cache_usage[] =
 "git diff-index [-m] [--cached] "
-"[<common diff options>] <tree-ish> [<path>...]"
+"[<common-diff-options>] <tree-ish> [<path>...]"
 COMMON_DIFF_OPTIONS_HELP;
 
 int cmd_diff_index(int argc, const char **argv, const char *prefix)
index 1c4ad6223eb9547666ec21f81f410ef1a459ec92..12b683d0217856a23cb4c3271a173ce1b7bfbe68 100644 (file)
@@ -82,7 +82,7 @@ static int diff_tree_stdin(char *line)
 
 static const char diff_tree_usage[] =
 "git diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] [--pretty] [-t] [-r] [--root] "
-"[<common diff options>] <tree-ish> [<tree-ish>] [<path>...]\n"
+"[<common-diff-options>] <tree-ish> [<tree-ish>] [<path>...]\n"
 "  -r            diff recursively\n"
 "  --root        include the initial commit as diff against /dev/null\n"
 COMMON_DIFF_OPTIONS_HELP;
index 1262b405f8212e71d088f4e090b8121fa304699a..4a6b340ab67622a1e0c57a2bd38e2de4f1ad91a5 100644 (file)
@@ -6,7 +6,7 @@
 #include "sha1-array.h"
 
 static const char fetch_pack_usage[] =
-"git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] "
+"git fetch-pack [--all] [--stdin] [--quiet | -q] [--keep | -k] [--thin] "
 "[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] "
 "[--no-progress] [--diag-url] [-v] [<host>:]<directory> [<refs>...]";
 
index 7b84d35d83498bc51b06915818f63d1f365eec91..f9512652cf1389a770bd94fd170d123206e024c5 100644 (file)
@@ -11,7 +11,6 @@
 #include "run-command.h"
 #include "parse-options.h"
 #include "sigchain.h"
-#include "transport.h"
 #include "submodule.h"
 #include "connected.h"
 #include "argv-array.h"
@@ -416,8 +415,10 @@ static int s_update_ref(const char *action,
 
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
-           ref_transaction_update(transaction, ref->name, ref->new_sha1,
-                                  ref->old_sha1, 0, check_old, msg, &err))
+           ref_transaction_update(transaction, ref->name,
+                                  ref->new_sha1,
+                                  check_old ? ref->old_sha1 : NULL,
+                                  0, msg, &err))
                goto fail;
 
        ret = ref_transaction_commit(transaction, &err);
index af7919e51e717923260080f8be3305bbe1b56d39..1d962dc569eaafc8429c4cec815922f382c576b9 100644 (file)
@@ -10,7 +10,7 @@
 #include "gpg-interface.h"
 
 static const char * const fmt_merge_msg_usage[] = {
-       N_("git fmt-merge-msg [-m <message>] [--log[=<n>]|--no-log] [--file <file>]"),
+       N_("git fmt-merge-msg [-m <message>] [--log[=<n>] | --no-log] [--file <file>]"),
        NULL
 };
 
index a0123f6146b53de295d01b438b72fb3dc7d76a0c..83f9cf91633a514e9301762fe774ee91be092848 100644 (file)
@@ -178,11 +178,10 @@ static const char *find_next(const char *cp)
 static int verify_format(const char *format)
 {
        const char *cp, *sp;
-       static const char color_reset[] = "color:reset";
 
        need_color_reset_at_eol = 0;
        for (cp = format; *cp && (sp = find_next(cp)); ) {
-               const char *ep = strchr(sp, ')');
+               const char *color, *ep = strchr(sp, ')');
                int at;
 
                if (!ep)
@@ -191,8 +190,8 @@ static int verify_format(const char *format)
                at = parse_atom(sp + 2, ep);
                cp = ep + 1;
 
-               if (starts_with(used_atom[at], "color:"))
-                       need_color_reset_at_eol = !!strcmp(used_atom[at], color_reset);
+               if (skip_prefix(used_atom[at], "color:", &color))
+                       need_color_reset_at_eol = !!strcmp(color, "reset");
        }
        return 0;
 }
@@ -1061,7 +1060,7 @@ static int opt_parse_sort(const struct option *opt, const char *arg, int unset)
 }
 
 static char const * const for_each_ref_usage[] = {
-       N_("git for-each-ref [options] [<pattern>]"),
+       N_("git for-each-ref [<options>] [<pattern>]"),
        NULL
 };
 
index a27515aeaa2debabdb14a03d271fe423d13b19d2..0c757862e8cd414c087b27a608281b66c8608a4b 100644 (file)
@@ -600,7 +600,7 @@ static int fsck_cache_tree(struct cache_tree *it)
 }
 
 static char const * const fsck_usage[] = {
-       N_("git fsck [options] [<object>...]"),
+       N_("git fsck [<options>] [<object>...]"),
        NULL
 };
 
index 005adbebea80a83a8d0dbb1de744cb50bf689de6..5c634afc0022c0ea7a8cd8c81727935ad79a6333 100644 (file)
@@ -21,7 +21,7 @@
 #define FAILED_RUN "failed to run %s"
 
 static const char * const builtin_gc_usage[] = {
-       N_("git gc [options]"),
+       N_("git gc [<options>]"),
        NULL
 };
 
index 4063882f06536ad5b3f1292a5b66e534ad4688af..335f25d0ad69a41ee2ea1e1e38aecbc2c121cb8c 100644 (file)
@@ -20,7 +20,7 @@
 #include "pathspec.h"
 
 static char const * const grep_usage[] = {
-       N_("git grep [options] [-e] <pattern> [<rev>...] [[--] <path>...]"),
+       N_("git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"),
        NULL
 };
 
@@ -641,7 +641,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "untracked", &untracked,
                        N_("search in both tracked and untracked files")),
                OPT_SET_INT(0, "exclude-standard", &opt_exclude,
-                           N_("search also in ignored files"), 1),
+                           N_("ignore files specified via '.gitignore'"), 1),
                OPT_GROUP(""),
                OPT_BOOL('v', "invert-match", &opt.invert,
                        N_("show non-matching lines")),
index 61583633182da359556fc65795a8eb740167675c..207b90c7b13e103b29305b68aa99d1b9b09342e7 100644 (file)
@@ -79,7 +79,7 @@ static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,
 int cmd_hash_object(int argc, const char **argv, const char *prefix)
 {
        static const char * const hash_object_usage[] = {
-               N_("git hash-object [-t <type>] [-w] [--path=<file>|--no-filters] [--stdin] [--] <file>..."),
+               N_("git hash-object [-t <type>] [-w] [--path=<file> | --no-filters] [--stdin] [--] <file>..."),
                N_("git hash-object  --stdin-paths < <list-of-paths>"),
                NULL
        };
index e78c135e010afa3f9447992ae85a7cc404d0192b..6133fe496b00e30a33d03c2d49b22a6ff81f9c77 100644 (file)
@@ -49,7 +49,7 @@ static struct option builtin_help_options[] = {
 };
 
 static const char * const builtin_help_usage[] = {
-       N_("git help [--all] [--guides] [--man|--web|--info] [command]"),
+       N_("git help [--all] [--guides] [--man | --web | --info] [<command>]"),
        NULL
 };
 
index 9966522b4a97a0d1ae430e581125fbfd1d5609ac..6723d39c3baf3571552a57732e4da16278269edf 100644 (file)
@@ -472,7 +472,7 @@ static int shared_callback(const struct option *opt, const char *arg, int unset)
 }
 
 static const char *const init_db_usage[] = {
-       N_("git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [directory]"),
+       N_("git init [-q | --quiet] [--bare] [--template=<template-directory>] [--shared[=<permissions>]] [<directory>]"),
        NULL
 };
 
index 923ffe72ced41f12a2258f732be418731bc2e4a8..dd8f3fcfc451780b244f6e6fd9e77298f484ad1a 100644 (file)
@@ -39,7 +39,7 @@ static const char *fmt_pretty;
 
 static const char * const builtin_log_usage[] = {
        N_("git log [<options>] [<revision range>] [[--] <path>...]"),
-       N_("git show [options] <object>..."),
+       N_("git show [<options>] <object>..."),
        NULL
 };
 
@@ -705,7 +705,7 @@ static int git_format_config(const char *var, const char *value, void *cb)
                return 0;
        }
        if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff") ||
-           !strcmp(var, "color.ui")) {
+           !strcmp(var, "color.ui") || !strcmp(var, "diff.submodule")) {
                return 0;
        }
        if (!strcmp(var, "format.numbered")) {
@@ -1023,7 +1023,7 @@ static const char *set_outdir(const char *prefix, const char *output_directory)
 }
 
 static const char * const builtin_format_patch_usage[] = {
-       N_("git format-patch [options] [<since> | <revision range>]"),
+       N_("git format-patch [<options>] [<since> | <revision-range>]"),
        NULL
 };
 
index 99cee20fb07ce7ed03da230bfa031c277f584fc1..914054d36734ba1b98c924aa640e748dced8b9fa 100644 (file)
@@ -398,7 +398,7 @@ int report_path_error(const char *ps_matched,
 }
 
 static const char * const ls_files_usage[] = {
-       N_("git ls-files [options] [<file>...]"),
+       N_("git ls-files [<options>] [<file>...]"),
        NULL
 };
 
index b2a4b92992748ab52fc6fd3f31041dd88dca54f8..4554dbc8a98c0daaa67c8ea65f5ddf5c48f19383 100644 (file)
@@ -5,7 +5,7 @@
 
 static const char ls_remote_usage[] =
 "git ls-remote [--heads] [--tags]  [-u <exec> | --upload-pack <exec>]\n"
-"                     [-q|--quiet] [--exit-code] [--get-url] [<repository> [<refs>...]]";
+"                     [-q | --quiet] [--exit-code] [--get-url] [<repository> [<refs>...]]";
 
 /*
  * Is there one among the list of patterns that match the tail part
index c8a47c173d011713a57dc744a5f5e5ea5434eefa..999a5250fbe7e6d38a2c8927fa3c37233142ef19 100644 (file)
@@ -1031,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] [-m | --message-id] [-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)
 {
index fdebef6fa157e920a4560e68c1215665f1e20baf..08a8217890df599100ad0da04dc2cfaabd3a11f6 100644 (file)
@@ -26,8 +26,8 @@ static int show_merge_base(struct commit **rev, int rev_nr, int show_all)
 }
 
 static const char * const merge_base_usage[] = {
-       N_("git merge-base [-a|--all] <commit> <commit>..."),
-       N_("git merge-base [-a|--all] --octopus <commit>..."),
+       N_("git merge-base [-a | --all] <commit> <commit>..."),
+       N_("git merge-base [-a | --all] --octopus <commit>..."),
        N_("git merge-base --independent <commit>..."),
        N_("git merge-base --is-ancestor <commit> <commit>"),
        N_("git merge-base --fork-point <ref> [<commit>]"),
index 844f84f40bf0f8b9d95f4e9f0496c010386a9fb8..ea8093f6769e278c4f7871faf405fe1e3f0a7544 100644 (file)
@@ -5,7 +5,7 @@
 #include "parse-options.h"
 
 static const char *const merge_file_usage[] = {
-       N_("git merge-file [options] [-L name1 [-L orig [-L name2]]] file1 orig_file file2"),
+       N_("git merge-file [<options>] [-L <name1> [-L <orig> [-L <name2>]]] <file1> <orig-file> <file2>"),
        NULL
 };
 
@@ -42,7 +42,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
                            N_("for conflicts, use this marker size")),
                OPT__QUIET(&quiet, N_("do not warn about conflicts")),
                OPT_CALLBACK('L', NULL, names, N_("name"),
-                            N_("set labels for file1/orig_file/file2"), &label_cb),
+                            N_("set labels for file1/orig-file/file2"), &label_cb),
                OPT_END(),
        };
 
@@ -90,7 +90,8 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
 
        if (ret >= 0) {
                const char *filename = argv[0];
-               FILE *f = to_stdout ? stdout : fopen(filename, "wb");
+               const char *fpath = prefix_filename(prefix, prefixlen, argv[0]);
+               FILE *f = to_stdout ? stdout : fopen(fpath, "wb");
 
                if (!f)
                        ret = error("Could not open %s for writing", filename);
index b416d928492c43e78dc7ac0b3bd1d7a99abfe78b..1a1eafa6fdc2e9dc66c98d3a81b7ee50e44727da 100644 (file)
@@ -75,7 +75,7 @@ int cmd_merge_index(int argc, const char **argv, const char *prefix)
        signal(SIGCHLD, SIG_DFL);
 
        if (argc < 3)
-               usage("git merge-index [-o] [-q] <merge-program> (-a | [--] <filename>*)");
+               usage("git merge-index [-o] [-q] <merge-program> (-a | [--] [<filename>...])");
 
        read_cache();
 
index c638fd5a9a8165c58d46d4edeeb0f3bbe8c0f9a1..3b0f8f96d4168463139d15f1cde655facc73426c 100644 (file)
@@ -42,8 +42,8 @@ struct strategy {
 };
 
 static const char * const builtin_merge_usage[] = {
-       N_("git merge [options] [<commit>...]"),
-       N_("git merge [options] <msg> HEAD <commit>"),
+       N_("git merge [<options>] [<commit>...]"),
+       N_("git merge [<options>] <msg> HEAD <commit>"),
        N_("git merge --abort"),
        NULL
 };
index 563d05ba1af21c9ae73edceba060161969434c76..d1d43168ae79d0157f8adf9dc36a4d2683afe91b 100644 (file)
@@ -12,7 +12,7 @@
 #include "submodule.h"
 
 static const char * const builtin_mv_usage[] = {
-       N_("git mv [options] <source>... <destination>"),
+       N_("git mv [<options>] <source>... <destination>"),
        NULL
 };
 
index 3c8f319be675d14a6ee60d303335190b7bdce9c8..9736d4452f28728b4f970bbf52af502d94edba86 100644 (file)
@@ -252,9 +252,9 @@ static void show_name(const struct object *obj,
 }
 
 static char const * const name_rev_usage[] = {
-       N_("git name-rev [options] <commit>..."),
-       N_("git name-rev [options] --all"),
-       N_("git name-rev [options] --stdin"),
+       N_("git name-rev [<options>] <commit>..."),
+       N_("git name-rev [<options>] --all"),
+       N_("git name-rev [<options>] --stdin"),
        NULL
 };
 
index a9f37d045641236ee910f3eb22be6ac8d04e386a..63f95fc55439060670879fd987033000b8ba3401 100644 (file)
 #include "notes-utils.h"
 
 static const char * const git_notes_usage[] = {
-       N_("git notes [--ref <notes_ref>] [list [<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 [--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 [--ref <notes-ref>] [list [<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 [--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]"),
        N_("git notes merge --abort [-v | -q]"),
-       N_("git notes [--ref <notes_ref>] remove [<object>...]"),
-       N_("git notes [--ref <notes_ref>] prune [-n | -v]"),
-       N_("git notes [--ref <notes_ref>] get-ref"),
+       N_("git notes [--ref <notes-ref>] remove [<object>...]"),
+       N_("git notes [--ref <notes-ref>] prune [-n | -v]"),
+       N_("git notes [--ref <notes-ref>] get-ref"),
        NULL
 };
 
@@ -68,7 +68,7 @@ static const char * const git_notes_show_usage[] = {
 };
 
 static const char * const git_notes_merge_usage[] = {
-       N_("git notes merge [<options>] <notes_ref>"),
+       N_("git notes merge [<options>] <notes-ref>"),
        N_("git notes merge --commit [<options>]"),
        N_("git notes merge --abort [<options>]"),
        NULL
@@ -951,7 +951,7 @@ int cmd_notes(int argc, const char **argv, const char *prefix)
        const char *override_notes_ref = NULL;
        struct option options[] = {
                OPT_STRING(0, "ref", &override_notes_ref, N_("notes-ref"),
-                          N_("use notes from <notes_ref>")),
+                          N_("use notes from <notes-ref>")),
                OPT_END()
        };
 
index 649c3aaa93ccdaae21b7884209bd4f28fb558f3e..d0532f66b1d4a479360263bb031e001f4cb42a46 100644 (file)
@@ -11,7 +11,7 @@
 #define BLKSIZE 512
 
 static const char pack_redundant_usage[] =
-"git pack-redundant [ --verbose ] [ --alt-odb ] < --all | <.pack filename> ...>";
+"git pack-redundant [--verbose] [--alt-odb] (--all | <filename.pack>...)";
 
 static int load_all_packs, verbose, alt_odb;
 
index b20b1ec4c117f7529a1a3f2a8151fa0297dffb6a..39f9a55d16736d93b43e6aa16a33634039e55de4 100644 (file)
@@ -3,7 +3,7 @@
 #include "refs.h"
 
 static char const * const pack_refs_usage[] = {
-       N_("git pack-refs [options]"),
+       N_("git pack-refs [<options>]"),
        NULL
 };
 
index f24a2c2bdca81fd2cb6d7b4968e46ad6922a9c9f..7cf900ea0765e334f02df5600f0911d41563a027 100644 (file)
@@ -4,7 +4,7 @@
 #include "parse-options.h"
 
 static const char * const prune_packed_usage[] = {
-       N_("git prune-packed [-n|--dry-run] [-q|--quiet]"),
+       N_("git prune-packed [-n | --dry-run] [-q | --quiet]"),
        NULL
 };
 
index 4e85e25d0f3cd3108bd4ad1c3be4dba53a30c1a2..70e9ce5f96f3e8da78e4b5746580869f9ae65330 100644 (file)
@@ -743,7 +743,9 @@ static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
        return 0;
 }
 
-static const char *update_worktree(unsigned char *sha1)
+static const char *push_to_deploy(unsigned char *sha1,
+                                 struct argv_array *env,
+                                 const char *work_tree)
 {
        const char *update_refresh[] = {
                "update-index", "-q", "--ignore-submodules", "--refresh", NULL
@@ -758,69 +760,87 @@ static const char *update_worktree(unsigned char *sha1)
        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.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);
+       if (run_command(&child))
                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.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);
+       if (run_command(&child))
                return "Working directory has unstaged changes";
-       }
 
        child_process_init(&child);
        child.argv = diff_index;
-       child.env = env.argv;
+       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);
+       if (run_command(&child))
                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.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);
+       if (run_command(&child))
                return "Could not update working tree to new HEAD";
-       }
 
-       argv_array_clear(&env);
        return NULL;
 }
 
+static const char *push_to_checkout_hook = "push-to-checkout";
+
+static const char *push_to_checkout(unsigned char *sha1,
+                                   struct argv_array *env,
+                                   const char *work_tree)
+{
+       argv_array_pushf(env, "GIT_WORK_TREE=%s", absolute_path(work_tree));
+       if (run_hook_le(env->argv, push_to_checkout_hook,
+                       sha1_to_hex(sha1), NULL))
+               return "push-to-checkout hook declined";
+       else
+               return NULL;
+}
+
+static const char *update_worktree(unsigned char *sha1)
+{
+       const char *retval;
+       const char *work_tree = git_work_tree_cfg ? git_work_tree_cfg : "..";
+       struct argv_array env = ARGV_ARRAY_INIT;
+
+       if (is_bare_repository())
+               return "denyCurrentBranch = updateInstead needs a worktree";
+
+       argv_array_pushf(&env, "GIT_DIR=%s", absolute_path(get_git_dir()));
+
+       if (!find_hook(push_to_checkout_hook))
+               retval = push_to_deploy(sha1, &env, work_tree);
+       else
+               retval = push_to_checkout(sha1, &env, work_tree);
+
+       argv_array_clear(&env);
+       return retval;
+}
+
 static const char *update(struct command *cmd, struct shallow_info *si)
 {
        const char *name = cmd->ref_name;
@@ -933,8 +953,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                if (ref_transaction_delete(transaction,
                                           namespaced_name,
                                           old_sha1,
-                                          0, old_sha1 != NULL,
-                                          "push", &err)) {
+                                          0, "push", &err)) {
                        rp_error("%s", err.buf);
                        strbuf_release(&err);
                        return "failed to delete";
@@ -951,7 +970,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
                if (ref_transaction_update(transaction,
                                           namespaced_name,
                                           new_sha1, old_sha1,
-                                          0, 1, "push",
+                                          0, "push",
                                           &err)) {
                        rp_error("%s", err.buf);
                        strbuf_release(&err);
index b4ff4689770e402675faba2ce400150b4803a360..5d3ab906bc7ef6cc8cc9c65a3b86cf4c1ff443fb 100644 (file)
 
 static const char * const builtin_remote_usage[] = {
        N_("git remote [-v | --verbose]"),
-       N_("git remote add [-t <branch>] [-m <master>] [-f] [--tags|--no-tags] [--mirror=<fetch|push>] <name> <url>"),
+       N_("git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--mirror=<fetch|push>] <name> <url>"),
        N_("git remote rename <old> <new>"),
        N_("git remote remove <name>"),
-       N_("git remote set-head <name> (-a | --auto | -d | --delete |<branch>)"),
+       N_("git remote set-head <name> (-a | --auto | -d | --delete | <branch>)"),
        N_("git remote [-v | --verbose] show [-n] <name>"),
        N_("git remote prune [-n | --dry-run] <name>"),
        N_("git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"),
index 3f852f35d1e786b2584d435d640ae830a9f34639..28fbc7099a84c7406a71128f2a8d3136c145bf57 100644 (file)
@@ -14,7 +14,7 @@ static int write_bitmaps;
 static char *packdir, *packtmp;
 
 static const char *const git_repack_usage[] = {
-       N_("git repack [options]"),
+       N_("git repack [<options>]"),
        NULL
 };
 
index 85d39b58d8aa35f0cd644273821ffd047ac50df0..54bf01acb4ca060a1dae43b399a6aefb1abe4eee 100644 (file)
@@ -172,7 +172,7 @@ static int replace_object_sha1(const char *object_ref,
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
            ref_transaction_update(transaction, ref, repl, prev,
-                                  0, 1, NULL, &err) ||
+                                  0, NULL, &err) ||
            ref_transaction_commit(transaction, &err))
                die("%s", err.buf);
 
index 98eb8c5404914e4046fdb886866b611351deeacf..7afadd2eadd59d8d3f4b77ad902bc24c94af9ec6 100644 (file)
@@ -9,7 +9,7 @@
 #include "pathspec.h"
 
 static const char * const rerere_usage[] = {
-       N_("git rerere [clear | forget path... | status | remaining | diff | gc]"),
+       N_("git rerere [clear | forget <path>... | status | remaining | diff | gc]"),
        NULL,
 };
 
index 95328b80d930260915ad86a30a21ecd3c1b7d1f4..3626c61da67abbe418e492c7828f6e153f6055d8 100644 (file)
@@ -358,7 +358,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
 {
        static int keep_dashdash = 0, stop_at_non_option = 0;
        static char const * const parseopt_usage[] = {
-               N_("git rev-parse --parseopt [options] -- [<args>...]"),
+               N_("git rev-parse --parseopt [<options>] -- [<args>...]"),
                NULL
        };
        static struct option parseopt_opts[] = {
@@ -496,9 +496,9 @@ static void die_no_single_rev(int quiet)
 }
 
 static const char builtin_rev_parse_usage[] =
-N_("git rev-parse --parseopt [options] -- [<args>...]\n"
+N_("git rev-parse --parseopt [<options>] -- [<args>...]\n"
    "   or: git rev-parse --sq-quote [<arg>...]\n"
-   "   or: git rev-parse [options] [<arg>...]\n"
+   "   or: git rev-parse [<options>] [<arg>...]\n"
    "\n"
    "Run \"git rev-parse --parseopt -h\" for more information on the first usage.");
 
index f9ed5bd5d03675931609f533e92da3b0a82f0f46..56a2c366698f838146bcf62d7b2c7a8a115287e1 100644 (file)
  */
 
 static const char * const revert_usage[] = {
-       N_("git revert [options] <commit-ish>..."),
+       N_("git revert [<options>] <commit-ish>..."),
        N_("git revert <subcommand>"),
        NULL
 };
 
 static const char * const cherry_pick_usage[] = {
-       N_("git cherry-pick [options] <commit-ish>..."),
+       N_("git cherry-pick [<options>] <commit-ish>..."),
        N_("git cherry-pick <subcommand>"),
        NULL
 };
index d8a9c86dd135e62583f4aeeb3885012da385960a..3304bff42a2fb91f66b9bbca1117746eaa22352a 100644 (file)
@@ -14,7 +14,7 @@
 #include "pathspec.h"
 
 static const char * const builtin_rm_usage[] = {
-       N_("git rm [options] [--] <file>..."),
+       N_("git rm [<options>] [--] <file>..."),
        NULL
 };
 
index 4b7e53623fc9cf0c86ed0e7e87d4b3357d765d86..c0bab6aaa9755f5a0264601defd0414b0b458e17 100644 (file)
@@ -10,7 +10,7 @@
 #include "parse-options.h"
 
 static char const * const shortlog_usage[] = {
-       N_("git shortlog [<options>] [<revision range>] [[--] [<path>...]]"),
+       N_("git shortlog [<options>] [<revision-range>] [[--] [<path>...]]"),
        NULL
 };
 
index 365228aa8d805bdf86a6eecccdc088068ba000d2..f3fb5fb2bf28019dafcbd2bfbd6b1a024aa6da2f 100644 (file)
@@ -6,11 +6,11 @@
 #include "parse-options.h"
 
 static const char* show_branch_usage[] = {
-    N_("git show-branch [-a|--all] [-r|--remotes] [--topo-order | --date-order]\n"
+    N_("git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
        "               [--current] [--color[=<when>] | --no-color] [--sparse]\n"
        "               [--more=<n> | --list | --independent | --merge-base]\n"
        "               [--no-name | --sha1-name] [--topics] [(<rev> | <glob>)...]"),
-    N_("git show-branch (-g|--reflog)[=<n>[,<base>]] [--list] [<ref>]"),
+    N_("git show-branch (-g | --reflog)[=<n>[,<base>]] [--list] [<ref>]"),
     NULL
 };
 
index 5ba1f3083890c693f8ce82166fe1cb1f6440b106..afb10309d6365a5fbc88ff1a88e26559b5b5f582 100644 (file)
@@ -7,7 +7,7 @@
 #include "parse-options.h"
 
 static const char * const show_ref_usage[] = {
-       N_("git show-ref [-q|--quiet] [--verify] [--head] [-d|--dereference] [-s|--hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [pattern*] "),
+       N_("git show-ref [-q | --quiet] [--verify] [--head] [-d | --dereference] [-s | --hash[=<n>]] [--abbrev[=<n>]] [--tags] [--heads] [--] [<pattern>...]"),
        N_("git show-ref --exclude-existing[=pattern] < ref-list"),
        NULL
 };
index 29fb3f1c201682674f8a473c235dd2f1f539f287..ce0fde705c0350ad99678541f434df5e07f5a263 100644 (file)
@@ -4,8 +4,8 @@
 #include "parse-options.h"
 
 static const char * const git_symbolic_ref_usage[] = {
-       N_("git symbolic-ref [options] name [ref]"),
-       N_("git symbolic-ref -d [-q] name"),
+       N_("git symbolic-ref [<options>] <name> [<ref>]"),
+       N_("git symbolic-ref -d [-q] <name>"),
        NULL
 };
 
index e633f4efdbb8963449fddb5c3357fa657283430e..4194b9a711d88e6d3575cd8896b1a81de74b087f 100644 (file)
@@ -19,9 +19,9 @@
 #include "column.h"
 
 static const char * const git_tag_usage[] = {
-       N_("git tag [-a|-s|-u <key-id>] [-f] [-m <msg>|-F <file>] <tagname> [<head>]"),
+       N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] <tagname> [<head>]"),
        N_("git tag -d <tagname>..."),
-       N_("git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>] "
+       N_("git tag -l [-n[<num>]] [--contains <commit>] [--points-at <object>]"
                "\n\t\t[<pattern>...]"),
        N_("git tag -v <tagname>..."),
        NULL
@@ -733,7 +733,7 @@ int cmd_tag(int argc, const char **argv, const char *prefix)
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
            ref_transaction_update(transaction, ref.buf, object, prev,
-                                  0, 1, NULL, &err) ||
+                                  0, NULL, &err) ||
            ref_transaction_commit(transaction, &err))
                die("%s", err.buf);
        ref_transaction_free(transaction);
index b0e3dc91055ec7e7579fb5f1964879a99fd71606..587898624c0550749a9a241e2742785f20ec1bd5 100644 (file)
@@ -400,7 +400,7 @@ static void read_index_info(int line_termination)
 }
 
 static const char * const update_index_usage[] = {
-       N_("git update-index [options] [--] [<file>...]"),
+       N_("git update-index [<options>] [--] [<file>...]"),
        NULL
 };
 
index 1993529521c0ef20860795168392d1dd7209c991..3d79a46b036fa7bea29bbc0941442b5dd92f648c 100644 (file)
@@ -6,9 +6,9 @@
 #include "argv-array.h"
 
 static const char * const git_update_ref_usage[] = {
-       N_("git update-ref [options] -d <refname> [<oldval>]"),
-       N_("git update-ref [options]    <refname> <newval> [<oldval>]"),
-       N_("git update-ref [options] --stdin [-z]"),
+       N_("git update-ref [<options>] -d <refname> [<old-val>]"),
+       N_("git update-ref [<options>]    <refname> <new-val> [<old-val>]"),
+       N_("git update-ref [<options>] --stdin [-z]"),
        NULL
 };
 
@@ -198,8 +198,9 @@ static const char *parse_cmd_update(struct ref_transaction *transaction,
        if (*next != line_termination)
                die("update %s: extra input: %s", refname, next);
 
-       if (ref_transaction_update(transaction, refname, new_sha1, old_sha1,
-                                  update_flags, have_old, msg, &err))
+       if (ref_transaction_update(transaction, refname,
+                                  new_sha1, have_old ? old_sha1 : NULL,
+                                  update_flags, msg, &err))
                die("%s", err.buf);
 
        update_flags = 0;
@@ -264,8 +265,9 @@ static const char *parse_cmd_delete(struct ref_transaction *transaction,
        if (*next != line_termination)
                die("delete %s: extra input: %s", refname, next);
 
-       if (ref_transaction_delete(transaction, refname, old_sha1,
-                                  update_flags, have_old, msg, &err))
+       if (ref_transaction_delete(transaction, refname,
+                                  have_old ? old_sha1 : NULL,
+                                  update_flags, msg, &err))
                die("%s", err.buf);
 
        update_flags = 0;
@@ -280,7 +282,6 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
 {
        struct strbuf err = STRBUF_INIT;
        char *refname;
-       unsigned char new_sha1[20];
        unsigned char old_sha1[20];
 
        refname = parse_refname(input, &next);
@@ -291,13 +292,11 @@ static const char *parse_cmd_verify(struct ref_transaction *transaction,
                            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, 1, msg, &err))
+       if (ref_transaction_verify(transaction, refname, old_sha1,
+                                  update_flags, &err))
                die("%s", err.buf);
 
        update_flags = 0;
@@ -353,7 +352,8 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
 {
        const char *refname, *oldval;
        unsigned char sha1[20], oldsha1[20];
-       int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0, flags = 0;
+       int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0;
+       unsigned int flags = 0;
        struct option options[] = {
                OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")),
                OPT_BOOL('d', NULL, &delete, N_("delete the reference")),
index b0f85042b234a33ec4b69541e0d6570015551536..ec0c4e3d836f9242a8e34dd7fffa5ddfb835907b 100644 (file)
@@ -14,7 +14,7 @@
 #include "gpg-interface.h"
 
 static const char * const verify_commit_usage[] = {
-               N_("git verify-commit [-v|--verbose] <commit>..."),
+               N_("git verify-commit [-v | --verbose] <commit>..."),
                NULL
 };
 
index 7747537beb72aba52377a13b9b3d61829f3a2fa8..c94e156932c0c8e0ba0c2dc302043c0f3ec0336d 100644 (file)
@@ -51,7 +51,7 @@ static int verify_one_pack(const char *path, unsigned int flags)
 }
 
 static const char * const verify_pack_usage[] = {
-       N_("git verify-pack [-v|--verbose] [-s|--stat-only] <pack>..."),
+       N_("git verify-pack [-v | --verbose] [-s | --stat-only] <pack>..."),
        NULL
 };
 
index 9cdf332333b95b3ab2ea6e133f345105bd67d019..53c68fce3ac182db907224d12d89659469f4b9d6 100644 (file)
@@ -14,7 +14,7 @@
 #include "gpg-interface.h"
 
 static const char * const verify_tag_usage[] = {
-               N_("git verify-tag [-v|--verbose] <tag>..."),
+               N_("git verify-tag [-v | --verbose] <tag>..."),
                NULL
 };
 
diff --git a/cache.h b/cache.h
index f704af5df0984e092fe318e535596921c4ea7122..761c5704b2e21f5dcd68fdcc9c3b1247ab0cfd18 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -568,7 +568,7 @@ extern void update_index_if_able(struct index_state *, struct lock_file *);
 extern int hold_locked_index(struct lock_file *, int);
 extern void set_alternate_index_output(const char *);
 
-extern int delete_ref(const char *, const unsigned char *sha1, int delopt);
+extern int delete_ref(const char *, const unsigned char *sha1, unsigned int flags);
 
 /* Environment bits from configuration mechanism */
 extern int trust_executable_bit;
@@ -1254,6 +1254,10 @@ extern int unpack_object_header(struct packed_git *, struct pack_window **, off_
  *
  * Any callback that is NULL will be ignored. Callbacks returning non-zero
  * will end the iteration.
+ *
+ * In the "buf" variant, "path" is a strbuf which will also be used as a
+ * scratch buffer, but restored to its original contents before
+ * the function returns.
  */
 typedef int each_loose_object_fn(const unsigned char *sha1,
                                 const char *path,
@@ -1269,6 +1273,11 @@ int for_each_loose_file_in_objdir(const char *path,
                                  each_loose_cruft_fn cruft_cb,
                                  each_loose_subdir_fn subdir_cb,
                                  void *data);
+int for_each_loose_file_in_objdir_buf(struct strbuf *path,
+                                     each_loose_object_fn obj_cb,
+                                     each_loose_cruft_fn cruft_cb,
+                                     each_loose_subdir_fn subdir_cb,
+                                     void *data);
 
 /*
  * Iterate over loose and packed objects in both the local
@@ -1498,7 +1507,7 @@ extern const char *pager_program;
 extern int pager_in_use(void);
 extern int pager_use_color;
 extern int term_columns(void);
-extern int decimal_width(int);
+extern int decimal_width(uintmax_t);
 extern int check_pager_config(const char *cmd);
 
 extern const char *editor_program;
index 07cff69d8e5c5fdbca47b603dbc2e9c067d369fd..a0aaf3a3473cadb162f8c39175b0ceb6cee1535a 100755 (executable)
@@ -3,7 +3,7 @@
 {
        cat <<\EOF
 sayIt:
-       $(foreach b,$(BUILT_INS),echo XXX $b YYY;)
+       $(foreach b,$(BUILT_INS),echo XXX $(b:$X=) YYY;)
 EOF
        cat Makefile
 } |
index 5cc1e7ec9ee80965d1669e0f96dfeab03f3b0798..9f189cb054266cd8f8c084853afbb678ca56c9e9 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -254,7 +254,6 @@ extern int for_each_commit_graft(each_commit_graft_fn, void *);
 extern int is_repository_shallow(void);
 extern struct commit_list *get_shallow_commits(struct object_array *heads,
                int depth, int shallow_flag, int not_shallow_flag);
-extern void check_shallow_file_for_update(void);
 extern void set_alternate_shallow_file(const char *path, int override);
 extern int write_shallow_commits(struct strbuf *out, int use_pack_protocol,
                                 const struct sha1_array *extra);
index 752e2e227f56edfb7b2ad168798c110c14a2c5e8..66c0a51bce529e4c027f11017697a62dd737b3bd 100644 (file)
--- a/config.c
+++ b/config.c
@@ -73,8 +73,12 @@ static int config_buf_fgetc(struct config_source *conf)
 
 static int config_buf_ungetc(int c, struct config_source *conf)
 {
-       if (conf->u.buf.pos > 0)
-               return conf->u.buf.buf[--conf->u.buf.pos];
+       if (conf->u.buf.pos > 0) {
+               conf->u.buf.pos--;
+               if (conf->u.buf.buf[conf->u.buf.pos] != c)
+                       die("BUG: config_buf can only ungetc the same character");
+               return c;
+       }
 
        return EOF;
 }
@@ -235,7 +239,8 @@ static int get_next_char(void)
                /* DOS like systems */
                c = cf->do_fgetc(cf);
                if (c != '\n') {
-                       cf->do_ungetc(c, cf);
+                       if (c != EOF)
+                               cf->do_ungetc(c, cf);
                        c = '\r';
                }
        }
@@ -1340,7 +1345,7 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha
                string_list_init(&e->value_list, 1);
                hashmap_add(&cs->config_hash, e);
        }
-       si = string_list_append_nodup(&e->value_list, value ? xstrdup(value) : NULL);
+       si = string_list_append_nodup(&e->value_list, xstrdup_or_null(value));
 
        ALLOC_GROW(cs->list.items, cs->list.nr + 1, cs->list.alloc);
        l_item = &cs->list.items[cs->list.nr++];
index 062e133aa39b9e522bf3a03c5e57ac67c03ad88e..ce0e1214234244236a407e9f3004e619d26c54a8 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -157,8 +157,7 @@ struct ref **get_remote_heads(int in, char *src_buf, size_t src_len,
                        server_capabilities = xstrdup(name + name_len + 1);
                }
 
-               if (extra_have &&
-                   name_len == 5 && !memcmp(".have", name, 5)) {
+               if (extra_have && !strcmp(name, ".have")) {
                        sha1_array_append(extra_have, old_sha1);
                        continue;
                }
@@ -274,28 +273,44 @@ static enum protocol get_protocol(const char *name)
        die("I don't handle protocol '%s'", name);
 }
 
+static char *host_end(char **hoststart, int removebrackets)
+{
+       char *host = *hoststart;
+       char *end;
+       char *start = strstr(host, "@[");
+       if (start)
+               start++; /* Jump over '@' */
+       else
+               start = host;
+       if (start[0] == '[') {
+               end = strchr(start + 1, ']');
+               if (end) {
+                       if (removebrackets) {
+                               *end = 0;
+                               memmove(start, start + 1, end - start);
+                               end++;
+                       }
+               } else
+                       end = host;
+       } else
+               end = host;
+       return end;
+}
+
 #define STR_(s)        # s
 #define STR(s) STR_(s)
 
 static void get_host_and_port(char **host, const char **port)
 {
        char *colon, *end;
-
-       if (*host[0] == '[') {
-               end = strchr(*host + 1, ']');
-               if (end) {
-                       *end = 0;
-                       end++;
-                       (*host)++;
-               } else
-                       end = *host;
-       } else
-               end = *host;
+       end = host_end(host, 1);
        colon = strchr(end, ':');
-
        if (colon) {
-               *colon = 0;
-               *port = colon + 1;
+               long portnr = strtol(colon + 1, &end, 10);
+               if (end != colon + 1 && *end == '\0' && 0 <= portnr && portnr < 65536) {
+                       *colon = 0;
+                       *port = colon + 1;
+               }
        }
 }
 
@@ -547,13 +562,16 @@ static struct child_process *git_proxy_connect(int fd[2], char *host)
        return proxy;
 }
 
-static const char *get_port_numeric(const char *p)
+static char *get_port(char *host)
 {
        char *end;
+       char *p = strchr(host, ':');
+
        if (p) {
                long port = strtol(p + 1, &end, 10);
                if (end != p + 1 && *end == '\0' && 0 <= port && port < 65536) {
-                       return p;
+                       *p = '\0';
+                       return p+1;
                }
        }
 
@@ -595,14 +613,7 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host,
         * Don't do destructive transforms as protocol code does
         * '[]' unwrapping in get_host_and_port()
         */
-       if (host[0] == '[') {
-               end = strchr(host + 1, ']');
-               if (end) {
-                       end++;
-               } else
-                       end = host;
-       } else
-               end = host;
+       end = host_end(&host, 0);
 
        if (protocol == PROTO_LOCAL)
                path = end;
@@ -663,17 +674,27 @@ struct child_process *git_connect(int fd[2], const char *url,
        signal(SIGCHLD, SIG_DFL);
 
        protocol = parse_connect_url(url, &hostandport, &path);
-       if (flags & CONNECT_DIAG_URL) {
+       if ((flags & CONNECT_DIAG_URL) && (protocol != PROTO_SSH)) {
                printf("Diag: url=%s\n", url ? url : "NULL");
                printf("Diag: protocol=%s\n", prot_name(protocol));
                printf("Diag: hostandport=%s\n", hostandport ? hostandport : "NULL");
                printf("Diag: path=%s\n", path ? path : "NULL");
                conn = NULL;
        } else if (protocol == PROTO_GIT) {
+               /*
+                * Set up virtual host information based on where we will
+                * connect, unless the user has overridden us in
+                * the environment.
+                */
+               char *target_host = getenv("GIT_OVERRIDE_VIRTUAL_HOST");
+               if (target_host)
+                       target_host = xstrdup(target_host);
+               else
+                       target_host = xstrdup(hostandport);
+
                /* These underlying connection commands die() if they
                 * cannot connect.
                 */
-               char *target_host = xstrdup(hostandport);
                if (git_use_proxy(hostandport))
                        conn = git_proxy_connect(fd, hostandport);
                else
@@ -705,28 +726,42 @@ struct child_process *git_connect(int fd[2], const char *url,
                        char *ssh_host = hostandport;
                        const char *port = NULL;
                        get_host_and_port(&ssh_host, &port);
-                       port = get_port_numeric(port);
 
-                       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");
-                       }
+                       if (!port)
+                               port = get_port(ssh_host);
+
+                       if (flags & CONNECT_DIAG_URL) {
+                               printf("Diag: url=%s\n", url ? url : "NULL");
+                               printf("Diag: protocol=%s\n", prot_name(protocol));
+                               printf("Diag: userandhost=%s\n", ssh_host ? ssh_host : "NULL");
+                               printf("Diag: port=%s\n", port ? port : "NONE");
+                               printf("Diag: path=%s\n", path ? path : "NULL");
 
-                       argv_array_push(&conn->args, ssh);
-                       if (putty && !strcasestr(ssh, "tortoiseplink"))
-                               argv_array_push(&conn->args, "-batch");
-                       if (port) {
-                               /* P is for PuTTY, p is for OpenSSH */
-                               argv_array_push(&conn->args, putty ? "-P" : "-p");
-                               argv_array_push(&conn->args, port);
+                               free(hostandport);
+                               free(path);
+                               return NULL;
+                       } else {
+                               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"))
+                                       argv_array_push(&conn->args, "-batch");
+                               if (port) {
+                                       /* P is for PuTTY, p is for OpenSSH */
+                                       argv_array_push(&conn->args, putty ? "-P" : "-p");
+                                       argv_array_push(&conn->args, port);
+                               }
+                               argv_array_push(&conn->args, ssh_host);
                        }
-                       argv_array_push(&conn->args, ssh_host);
                } else {
                        /* remove repo-local variables from the environment */
                        conn->env = local_repo_env;
index 8cfee95f88006269e4227f98701b9af8587af0bd..c21190d7510c173482b7784f9e8c4bf0b56cb1e1 100644 (file)
@@ -1425,7 +1425,7 @@ __git_log_gitk_options="
 # Options that go well for log and shortlog (not gitk)
 __git_log_shortlog_options="
        --author= --committer= --grep=
-       --all-match
+       --all-match --invert-grep
 "
 
 __git_log_pretty_formats="oneline short medium full fuller email raw format:"
index a1d38f035bea404aa9a5fa37518f0af21143dbf0..006134043a472edd54720d6d4237e9484476d3a3 100644 (file)
@@ -111,14 +111,23 @@ static void write_item(const char *what, LPCWSTR wbuf, int wlen)
  * Match an (optional) expected string and a delimiter in the target string,
  * consuming the matched text by updating the target pointer.
  */
-static int match_part(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim)
+
+static LPCWSTR wcsstr_last(LPCWSTR str, LPCWSTR find)
+{
+       LPCWSTR res = NULL, pos;
+       for (pos = wcsstr(str, find); pos; pos = wcsstr(pos + 1, find))
+               res = pos;
+       return res;
+}
+
+static int match_part_with_last(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim, int last)
 {
        LPCWSTR delim_pos, start = *ptarget;
        int len;
 
        /* find start of delimiter (or end-of-string if delim is empty) */
        if (*delim)
-               delim_pos = wcsstr(start, delim);
+               delim_pos = last ? wcsstr_last(start, delim) : wcsstr(start, delim);
        else
                delim_pos = start + wcslen(start);
 
@@ -138,6 +147,16 @@ static int match_part(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim)
        return !want || (!wcsncmp(want, start, len) && !want[len]);
 }
 
+static int match_part(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim)
+{
+       return match_part_with_last(ptarget, want, delim, 0);
+}
+
+static int match_part_last(LPCWSTR *ptarget, LPCWSTR want, LPCWSTR delim)
+{
+       return match_part_with_last(ptarget, want, delim, 1);
+}
+
 static int match_cred(const CREDENTIALW *cred)
 {
        LPCWSTR target = cred->TargetName;
@@ -146,7 +165,7 @@ static int match_cred(const CREDENTIALW *cred)
 
        return match_part(&target, L"git", L":") &&
                match_part(&target, protocol, L"://") &&
-               match_part(&target, wusername, L"@") &&
+               match_part_last(&target, wusername, L"@") &&
                match_part(&target, host, L"/") &&
                match_part(&target, path, L"");
 }
index d435514cbe29aa01d9cebadb947a6c6c8a1e2527..925d3f40247d7f41d709b4e6b3eaabaf646572b6 100644 (file)
@@ -118,7 +118,7 @@ static int lookup_credential(const char *fn, struct credential *c)
 int main(int argc, char **argv)
 {
        const char * const usage[] = {
-               "git credential-store [options] <action>",
+               "git credential-store [<options>] <action>",
                NULL
        };
        const char *op;
diff --git a/ctype.c b/ctype.c
index 0bfebb4e75866ba0e97713fab5394490290831c0..fc0225cebd1a4b43654772270826e06fd941a128 100644 (file)
--- a/ctype.c
+++ b/ctype.c
@@ -30,7 +30,7 @@ const unsigned char sane_ctype[256] = {
 };
 
 /* For case-insensitive kwset */
-const char tolower_trans_tbl[256] = {
+const unsigned char tolower_trans_tbl[256] = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
index 54a03bd527a81485b498e33225ed54c54c0dbff7..c3edd960ec5bf686b66fa55dcfea712e455fe772 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -61,6 +61,22 @@ static char *canon_hostname;
 static char *ip_address;
 static char *tcp_port;
 
+static int hostname_lookup_done;
+
+static void lookup_hostname(void);
+
+static const char *get_canon_hostname(void)
+{
+       lookup_hostname();
+       return canon_hostname;
+}
+
+static const char *get_ip_address(void)
+{
+       lookup_hostname();
+       return ip_address;
+}
+
 static void logreport(int priority, const char *err, va_list params)
 {
        if (log_syslog) {
@@ -106,6 +122,46 @@ static void NORETURN daemon_die(const char *err, va_list params)
        exit(1);
 }
 
+static void strbuf_addstr_or_null(struct strbuf *sb, const char *s)
+{
+       if (s)
+               strbuf_addstr(sb, s);
+}
+
+struct expand_path_context {
+       const char *directory;
+};
+
+static size_t expand_path(struct strbuf *sb, const char *placeholder, void *ctx)
+{
+       struct expand_path_context *context = ctx;
+
+       switch (placeholder[0]) {
+       case 'H':
+               strbuf_addstr_or_null(sb, hostname);
+               return 1;
+       case 'C':
+               if (placeholder[1] == 'H') {
+                       strbuf_addstr_or_null(sb, get_canon_hostname());
+                       return 2;
+               }
+               break;
+       case 'I':
+               if (placeholder[1] == 'P') {
+                       strbuf_addstr_or_null(sb, get_ip_address());
+                       return 2;
+               }
+               break;
+       case 'P':
+               strbuf_addstr_or_null(sb, tcp_port);
+               return 1;
+       case 'D':
+               strbuf_addstr(sb, context->directory);
+               return 1;
+       }
+       return 0;
+}
+
 static const char *path_ok(const char *directory)
 {
        static char rpath[PATH_MAX];
@@ -144,14 +200,10 @@ static const char *path_ok(const char *directory)
        }
        else if (interpolated_path && saw_extended_args) {
                struct strbuf expanded_path = STRBUF_INIT;
-               struct strbuf_expand_dict_entry dict[6];
-
-               dict[0].placeholder = "H"; dict[0].value = hostname;
-               dict[1].placeholder = "CH"; dict[1].value = canon_hostname;
-               dict[2].placeholder = "IP"; dict[2].value = ip_address;
-               dict[3].placeholder = "P"; dict[3].value = tcp_port;
-               dict[4].placeholder = "D"; dict[4].value = directory;
-               dict[5].placeholder = NULL; dict[5].value = NULL;
+               struct expand_path_context context;
+
+               context.directory = directory;
+
                if (*dir != '/') {
                        /* Allow only absolute */
                        logerror("'%s': Non-absolute path denied (interpolated-path active)", dir);
@@ -159,7 +211,7 @@ static const char *path_ok(const char *directory)
                }
 
                strbuf_expand(&expanded_path, interpolated_path,
-                               strbuf_expand_dict_cb, &dict);
+                             expand_path, &context);
                strlcpy(interp_path, expanded_path.buf, PATH_MAX);
                strbuf_release(&expanded_path);
                loginfo("Interpolated dir '%s'", interp_path);
@@ -254,8 +306,8 @@ static int run_access_hook(struct daemon_service *service, const char *dir, cons
        *arg++ = service->name;
        *arg++ = path;
        *arg++ = STRARG(hostname);
-       *arg++ = STRARG(canon_hostname);
-       *arg++ = STRARG(ip_address);
+       *arg++ = STRARG(get_canon_hostname());
+       *arg++ = STRARG(get_ip_address());
        *arg++ = STRARG(tcp_port);
        *arg = NULL;
 #undef STRARG
@@ -484,6 +536,45 @@ static void parse_host_and_port(char *hostport, char **host,
        }
 }
 
+/*
+ * Sanitize a string from the client so that it's OK to be inserted into a
+ * filesystem path. Specifically, we disallow slashes, runs of "..", and
+ * trailing and leading dots, which means that the client cannot escape
+ * our base path via ".." traversal.
+ */
+static void sanitize_client_strbuf(struct strbuf *out, const char *in)
+{
+       for (; *in; in++) {
+               if (*in == '/')
+                       continue;
+               if (*in == '.' && (!out->len || out->buf[out->len - 1] == '.'))
+                       continue;
+               strbuf_addch(out, *in);
+       }
+
+       while (out->len && out->buf[out->len - 1] == '.')
+               strbuf_setlen(out, out->len - 1);
+}
+
+static char *sanitize_client(const char *in)
+{
+       struct strbuf out = STRBUF_INIT;
+       sanitize_client_strbuf(&out, in);
+       return strbuf_detach(&out, NULL);
+}
+
+/*
+ * Like sanitize_client, but we also perform any canonicalization
+ * to make life easier on the admin.
+ */
+static char *canonicalize_client(const char *in)
+{
+       struct strbuf out = STRBUF_INIT;
+       sanitize_client_strbuf(&out, in);
+       strbuf_tolower(&out);
+       return strbuf_detach(&out, NULL);
+}
+
 /*
  * Read the host as supplied by the client connection.
  */
@@ -505,10 +596,11 @@ static void parse_host_arg(char *extra_args, int buflen)
                                parse_host_and_port(val, &host, &port);
                                if (port) {
                                        free(tcp_port);
-                                       tcp_port = xstrdup(port);
+                                       tcp_port = sanitize_client(port);
                                }
                                free(hostname);
-                               hostname = xstrdup_tolower(host);
+                               hostname = canonicalize_client(host);
+                               hostname_lookup_done = 0;
                        }
 
                        /* On to the next one */
@@ -517,11 +609,14 @@ static void parse_host_arg(char *extra_args, int buflen)
                if (extra_args < end && *extra_args)
                        die("Invalid request");
        }
+}
 
-       /*
-        * Locate canonical hostname and its IP address.
-        */
-       if (hostname) {
+/*
+ * Locate canonical hostname and its IP address.
+ */
+static void lookup_hostname(void)
+{
+       if (!hostname_lookup_done && hostname) {
 #ifndef NO_IPV6
                struct addrinfo hints;
                struct addrinfo *ai;
@@ -541,8 +636,9 @@ static void parse_host_arg(char *extra_args, int buflen)
                        ip_address = xstrdup(addrbuf);
 
                        free(canon_hostname);
-                       canon_hostname = xstrdup(ai->ai_canonname ?
-                                                ai->ai_canonname : ip_address);
+                       canon_hostname = ai->ai_canonname ?
+                               sanitize_client(ai->ai_canonname) :
+                               xstrdup(ip_address);
 
                        freeaddrinfo(ai);
                }
@@ -564,11 +660,12 @@ static void parse_host_arg(char *extra_args, int buflen)
                                  addrbuf, sizeof(addrbuf));
 
                        free(canon_hostname);
-                       canon_hostname = xstrdup(hent->h_name);
+                       canon_hostname = sanitize_client(hent->h_name);
                        free(ip_address);
                        ip_address = xstrdup(addrbuf);
                }
 #endif
+               hostname_lookup_done = 1;
        }
 }
 
index 875aff864391ed037627462ac39c314f248b5ae6..a85c4971ac8ece6397c05d0674bbac8c75cf219f 100644 (file)
@@ -101,6 +101,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
                struct cache_entry *ce = active_cache[i];
                int changed;
                unsigned dirty_submodule = 0;
+               const unsigned char *old_sha1, *new_sha1;
 
                if (diff_can_quit_early(&revs->diffopt))
                        break;
@@ -224,9 +225,12 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
                                continue;
                }
                oldmode = ce->ce_mode;
+               old_sha1 = ce->sha1;
+               new_sha1 = changed ? null_sha1 : ce->sha1;
                diff_change(&revs->diffopt, oldmode, newmode,
-                           ce->sha1, (changed ? null_sha1 : ce->sha1),
-                           !is_null_sha1(ce->sha1), (changed ? 0 : !is_null_sha1(ce->sha1)),
+                           old_sha1, new_sha1,
+                           !is_null_sha1(old_sha1),
+                           !is_null_sha1(new_sha1),
                            ce->name, 0, dirty_submodule);
 
        }
diff --git a/diff.c b/diff.c
index d1bd534caeaf662b0ee0d547d3aa2012310fff57..abc32c8a7dcaf911c4b9af5168a7da35a5d5e24b 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -4541,7 +4541,7 @@ void diff_flush(struct diff_options *options)
                        show_stats(&diffstat, options);
                if (output_format & DIFF_FORMAT_SHORTSTAT)
                        show_shortstats(&diffstat, options);
-               if (output_format & DIFF_FORMAT_DIRSTAT)
+               if (output_format & DIFF_FORMAT_DIRSTAT && dirstat_by_line)
                        show_dirstat_by_line(&diffstat, options);
                free_diffstat_info(&diffstat);
                separator++;
index 4e132f1fdb68ed3c930ca8224a5403c9b406cc3b..af1fe08861e6862985ac8fb9311b17568cb9e547 100644 (file)
@@ -15,8 +15,7 @@ static struct diff_rename_dst {
 } *rename_dst;
 static int rename_dst_nr, rename_dst_alloc;
 
-static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two,
-                                                int insert_ok)
+static int find_rename_dst(struct diff_filespec *two)
 {
        int first, last;
 
@@ -27,16 +26,33 @@ static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two,
                struct diff_rename_dst *dst = &(rename_dst[next]);
                int cmp = strcmp(two->path, dst->two->path);
                if (!cmp)
-                       return dst;
+                       return next;
                if (cmp < 0) {
                        last = next;
                        continue;
                }
                first = next+1;
        }
-       /* not found */
-       if (!insert_ok)
-               return NULL;
+       return -first - 1;
+}
+
+static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two)
+{
+       int ofs = find_rename_dst(two);
+       return ofs < 0 ? NULL : &rename_dst[ofs];
+}
+
+/*
+ * Returns 0 on success, -1 if we found a duplicate.
+ */
+static int add_rename_dst(struct diff_filespec *two)
+{
+       int first = find_rename_dst(two);
+
+       if (first >= 0)
+               return -1;
+       first = -first - 1;
+
        /* insert to make it at "first" */
        ALLOC_GROW(rename_dst, rename_dst_nr + 1, rename_dst_alloc);
        rename_dst_nr++;
@@ -46,7 +62,7 @@ static struct diff_rename_dst *locate_rename_dst(struct diff_filespec *two,
        rename_dst[first].two = alloc_filespec(two->path);
        fill_filespec(rename_dst[first].two, two->sha1, two->sha1_valid, two->mode);
        rename_dst[first].pair = NULL;
-       return &(rename_dst[first]);
+       return 0;
 }
 
 /* Table of rename/copy src files */
@@ -450,8 +466,12 @@ void diffcore_rename(struct diff_options *options)
                        else if (!DIFF_OPT_TST(options, RENAME_EMPTY) &&
                                 is_empty_blob_sha1(p->two->sha1))
                                continue;
-                       else
-                               locate_rename_dst(p->two, 1);
+                       else if (add_rename_dst(p->two) < 0) {
+                               warning("skipping rename detection, detected"
+                                       " duplicate destination '%s'",
+                                       p->two->path);
+                               goto cleanup;
+                       }
                }
                else if (!DIFF_OPT_TST(options, RENAME_EMPTY) &&
                         is_empty_blob_sha1(p->one->sha1))
@@ -582,8 +602,7 @@ void diffcore_rename(struct diff_options *options)
                         * We would output this create record if it has
                         * not been turned into a rename/copy already.
                         */
-                       struct diff_rename_dst *dst =
-                               locate_rename_dst(p->two, 0);
+                       struct diff_rename_dst *dst = locate_rename_dst(p->two);
                        if (dst && dst->pair) {
                                diff_q(&outq, dst->pair);
                                pair_to_free = p;
@@ -613,8 +632,7 @@ void diffcore_rename(struct diff_options *options)
                         */
                        if (DIFF_PAIR_BROKEN(p)) {
                                /* broken delete */
-                               struct diff_rename_dst *dst =
-                                       locate_rename_dst(p->one, 0);
+                               struct diff_rename_dst *dst = locate_rename_dst(p->one);
                                if (dst && dst->pair)
                                        /* counterpart is now rename/copy */
                                        pair_to_free = p;
index f6ad190a038a55e39a0b8b135c995413192f80e3..13c6e20412591ed3bc56b38b17419a540264f6c5 100644 (file)
@@ -47,7 +47,8 @@ static inline uint32_t ewah_bit_popcount64(uint64_t x)
        return (x * 0x0101010101010101ULL) >> 56;
 }
 
-#ifdef __GNUC__
+/* __builtin_ctzll was not available until 3.4.0 */
+#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3  && __GNUC_MINOR > 3))
 #define ewah_bit_ctz64(x) __builtin_ctzll(x)
 #else
 static inline int ewah_bit_ctz64(uint64_t x)
index d0bd285a16d0161b50d0b43e0315f8fa003e0e32..b82fcdd24e34d9191aae33fed4e8afb3ca4b6f6a 100644 (file)
@@ -947,9 +947,12 @@ static void unkeep_all_packs(void)
 
 static void end_packfile(void)
 {
-       if (!pack_data)
+       static int running;
+
+       if (running || !pack_data)
                return;
 
+       running = 1;
        clear_delta_base_cache();
        if (object_count) {
                struct packed_git *new_p;
@@ -999,6 +1002,7 @@ static void end_packfile(void)
        }
        free(pack_data);
        pack_data = NULL;
+       running = 0;
 
        /* We can't carry a delta across packfiles. */
        strbuf_release(&last_blob.data);
@@ -1716,7 +1720,7 @@ static int update_branch(struct branch *b)
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
            ref_transaction_update(transaction, b->name, b->sha1, old_sha1,
-                                  0, 1, msg, &err) ||
+                                  0, msg, &err) ||
            ref_transaction_commit(transaction, &err)) {
                ref_transaction_free(transaction);
                error("%s", err.buf);
@@ -1756,8 +1760,8 @@ static void dump_tags(void)
                strbuf_reset(&ref_name);
                strbuf_addf(&ref_name, "refs/tags/%s", t->name);
 
-               if (ref_transaction_update(transaction, ref_name.buf, t->sha1,
-                                          NULL, 0, 0, msg, &err)) {
+               if (ref_transaction_update(transaction, ref_name.buf,
+                                          t->sha1, NULL, 0, msg, &err)) {
                        failure |= error("%s", err.buf);
                        goto cleanup;
                }
index 8b2da4641f8b20ff3cc70c63636de878eec72470..7378ba287f0c449810250fb7b019f69e4f6a3497 100644 (file)
--- a/gettext.c
+++ b/gettext.c
 #      endif
 #endif
 
+/*
+ * Guess the user's preferred languages from the value in LANGUAGE environment
+ * variable and LC_MESSAGES locale category if NO_GETTEXT is not defined.
+ *
+ * The result can be a colon-separated list like "ko:ja:en".
+ */
+const char *get_preferred_languages(void)
+{
+       const char *retval;
+
+       retval = getenv("LANGUAGE");
+       if (retval && *retval)
+               return retval;
+
+#ifndef NO_GETTEXT
+       retval = setlocale(LC_MESSAGES, NULL);
+       if (retval && *retval &&
+               strcmp(retval, "C") &&
+               strcmp(retval, "POSIX"))
+               return retval;
+#endif
+
+       return NULL;
+}
+
 #ifdef GETTEXT_POISON
 int use_gettext_poison(void)
 {
index 7671d09d04bb87541b11209b5cdbddbb9e4e59b8..33696a40b8a11262d090a2eec4dfdce0fed6af0f 100644 (file)
--- a/gettext.h
+++ b/gettext.h
@@ -63,6 +63,32 @@ const char *Q_(const char *msgid, const char *plu, unsigned long n)
 }
 
 /* Mark msgid for translation but do not translate it. */
+#if !USE_PARENS_AROUND_GETTEXT_N
 #define N_(msgid) msgid
+#else
+/*
+ * Strictly speaking, this will lead to invalid C when
+ * used this way:
+ *     static const char s[] = N_("FOO");
+ * which will expand to
+ *     static const char s[] = ("FOO");
+ * and in valid C, the initializer on the right hand side must
+ * be without the parentheses.  But many compilers do accept it
+ * as a language extension and it will allow us to catch mistakes
+ * like:
+ *     static const char *msgs[] = {
+ *             N_("one")
+ *             N_("two"),
+ *             N_("three"),
+ *             NULL
+ *     };
+ * (notice the missing comma on one of the lines) by forcing
+ * a compilation error, because parenthesised ("one") ("two")
+ * will not get silently turned into ("onetwo").
+ */
+#define N_(msgid) (msgid)
+#endif
+
+const char *get_preferred_languages(void);
 
 #endif
index c7256741cc2a28f333d6a9be5f12e248df99ed5e..77876d433a1ba2384a690155b51dac8118fa27b4 100755 (executable)
@@ -515,6 +515,9 @@ sub error_msg {
 sub list_and_choose {
        my ($opts, @stuff) = @_;
        my (@chosen, @return);
+       if (!@stuff) {
+           return @return;
+       }
        my $i;
        my @prefixes = find_unique_prefixes(@stuff) unless $opts->{LIST_ONLY};
 
@@ -725,6 +728,8 @@ sub add_untracked_cmd {
        if (@add) {
                system(qw(git update-index --add --), @add);
                say_n_paths('added', @add);
+       } else {
+               print "No untracked files.\n";
        }
        print "\n";
 }
index 2fc07acb0f242154fec868207cfd77f448929200..ae3fec22c48a296cdc1962def9030aa5bb7ce68a 100755 (executable)
@@ -127,7 +127,7 @@ bisect_start() {
                if test "z$mode" != "z--no-checkout"
                then
                        git checkout "$start_head" -- ||
-                       die "$(eval_gettext "Checking out '\$start_head' failed. Try 'git bisect reset <validbranch>'.")"
+                       die "$(eval_gettext "Checking out '\$start_head' failed. Try 'git bisect reset <valid-branch>'.")"
                fi
        else
                # Get rev from where we start.
index eb9b0ff32829ef62bf2d1af432742841b9720906..a3095be962c04d5b55c54ec39c6c3e6989372c36 100644 (file)
 typedef long intptr_t;
 typedef unsigned long uintptr_t;
 #endif
-#if defined(__CYGWIN__)
-#undef _XOPEN_SOURCE
-#include <grp.h>
-#define _XOPEN_SOURCE 600
-#else
 #undef _ALL_SOURCE /* AIX 5.3L defines a struct list with _ALL_SOURCE. */
 #include <grp.h>
 #define _ALL_SOURCE 1
 #endif
-#endif
 
 /* used on Mac OS X */
 #ifdef PRECOMPOSE_UNICODE
@@ -212,12 +206,15 @@ extern char *gitbasename(char *);
 #endif
 
 #ifndef NO_OPENSSL
+#ifdef __APPLE__
 #define __AVAILABILITY_MACROS_USES_AVAILABILITY 0
-#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_6
+#include <AvailabilityMacros.h>
+#undef DEPRECATED_ATTRIBUTE
+#define DEPRECATED_ATTRIBUTE
+#undef __AVAILABILITY_MACROS_USES_AVAILABILITY
+#endif
 #include <openssl/ssl.h>
 #include <openssl/err.h>
-#undef MAC_OS_X_VERSION_MIN_REQUIRED
-#undef __AVAILABILITY_MACROS_USES_AVAILABILITY
 #ifdef NO_HMAC_CTX_CLEANUP
 #define HMAC_CTX_cleanup HMAC_cleanup
 #endif
@@ -678,6 +675,11 @@ extern char *xgetcwd(void);
 
 #define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), (alloc) * sizeof(*(x)))
 
+static inline char *xstrdup_or_null(const char *str)
+{
+       return str ? xstrdup(str) : NULL;
+}
+
 static inline size_t xsize_t(off_t len)
 {
        if (len > (size_t) len)
@@ -686,7 +688,7 @@ static inline size_t xsize_t(off_t len)
 }
 
 /* in ctype.c, for kwset users */
-extern const char tolower_trans_tbl[256];
+extern const unsigned char tolower_trans_tbl[256];
 
 /* Sane ctype - no locale, and works with signed chars */
 #undef isascii
@@ -870,4 +872,8 @@ struct tm *git_gmtime_r(const time_t *, struct tm *);
 #define gmtime_r git_gmtime_r
 #endif
 
+#if !defined(USE_PARENS_AROUND_GETTEXT_N) && defined(__GNUC__)
+#define USE_PARENS_AROUND_GETTEXT_N 1
+#endif
+
 #endif
index ff132b2117c5ed7529d6b1237a9f26069cb4ef8a..549022e97c83e4a2f1898dc005331e5bca3f0ded 100755 (executable)
--- a/git-p4.py
+++ b/git-p4.py
@@ -1442,7 +1442,7 @@ def applyCommit(self, id):
             print "  " + self.clientPath
             print
             print "To submit, use \"p4 submit\" to write a new description,"
-            print "or \"p4 submit -i %s\" to use the one prepared by" \
+            print "or \"p4 submit -i <%s\" to use the one prepared by" \
                   " \"git p4\"." % fileName
             print "You can delete the file \"%s\" when finished." % fileName
 
@@ -1915,7 +1915,10 @@ def __init__(self):
                 optparse.make_option("--keep-path", dest="keepRepoPath", action='store_true',
                                      help="Keep entire BRANCH/DIR/SUBDIR prefix during import"),
                 optparse.make_option("--use-client-spec", dest="useClientSpec", action='store_true',
-                                     help="Only sync files that are included in the Perforce Client Spec")
+                                     help="Only sync files that are included in the Perforce Client Spec"),
+                optparse.make_option("-/", dest="cloneExclude",
+                                     action="append", type="string",
+                                     help="exclude depot path"),
         ]
         self.description = """Imports from Perforce into a git repository.\n
     example:
@@ -1950,6 +1953,12 @@ def __init__(self):
         if gitConfig("git-p4.syncFromOrigin") == "false":
             self.syncWithOrigin = False
 
+    # This is required for the "append" cloneExclude action
+    def ensure_value(self, attr, value):
+        if not hasattr(self, attr) or getattr(self, attr) is None:
+            setattr(self, attr, value)
+        return getattr(self, attr)
+
     # Force a checkpoint in fast-import and wait for it to finish
     def checkpoint(self):
         self.gitStream.write("checkpoint\n\n")
@@ -3101,9 +3110,6 @@ def __init__(self):
             optparse.make_option("--destination", dest="cloneDestination",
                                  action='store', default=None,
                                  help="where to leave result of the clone"),
-            optparse.make_option("-/", dest="cloneExclude",
-                                 action="append", type="string",
-                                 help="exclude depot path"),
             optparse.make_option("--bare", dest="cloneBare",
                                  action="store_true", default=False),
         ]
@@ -3111,12 +3117,6 @@ def __init__(self):
         self.needsGit = False
         self.cloneBare = False
 
-    # This is required for the "append" cloneExclude action
-    def ensure_value(self, attr, value):
-        if not hasattr(self, attr) or getattr(self, attr) is None:
-            setattr(self, attr, value)
-        return getattr(self, attr)
-
     def defaultDestination(self, args):
         ## TODO: use common prefix of args?
         depotPath = args[0]
index c6a4629cbc2b69d3e6dfabe5e124384fe7fe611c..c96b9847e9fc2aaf67997c74a8d5c0abe78b607d 100644 (file)
@@ -961,14 +961,13 @@ else
        revisions=$onto...$orig_head
        shortrevisions=$shorthead
 fi
-git rev-list $merges_option --pretty=oneline --abbrev-commit \
-       --abbrev=7 --reverse --left-right --topo-order \
+git rev-list $merges_option --pretty=oneline --reverse --left-right --topo-order \
        $revisions ${restrict_revision+^$restrict_revision} | \
        sed -n "s/^>//p" |
-while read -r shortsha1 rest
+while read -r sha1 rest
 do
 
-       if test -z "$keep_empty" && is_empty_commit $shortsha1 && ! is_merge_commit $shortsha1
+       if test -z "$keep_empty" && is_empty_commit $sha1 && ! is_merge_commit $sha1
        then
                comment_out="$comment_char "
        else
@@ -977,9 +976,8 @@ do
 
        if test t != "$preserve_merges"
        then
-               printf '%s\n' "${comment_out}pick $shortsha1 $rest" >>"$todo"
+               printf '%s\n' "${comment_out}pick $sha1 $rest" >>"$todo"
        else
-               sha1=$(git rev-parse $shortsha1)
                if test -z "$rebase_root"
                then
                        preserve=t
@@ -996,7 +994,7 @@ do
                if test f = "$preserve"
                then
                        touch "$rewritten"/$sha1
-                       printf '%s\n' "${comment_out}pick $shortsha1 $rest" >>"$todo"
+                       printf '%s\n' "${comment_out}pick $sha1 $rest" >>"$todo"
                fi
        fi
 done
@@ -1020,8 +1018,8 @@ then
                        # just the history of its first-parent for others that will
                        # be rebasing on top of it
                        git rev-list --parents -1 $rev | cut -d' ' -s -f2 > "$dropped"/$rev
-                       short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev)
-                       sane_grep -v "^[a-z][a-z]* $short" <"$todo" > "${todo}2" ; mv "${todo}2" "$todo"
+                       sha1=$(git rev-list -1 $rev)
+                       sane_grep -v "^[a-z][a-z]* $sha1" <"$todo" > "${todo}2" ; mv "${todo}2" "$todo"
                        rm "$rewritten"/$rev
                fi
        done
@@ -1054,6 +1052,7 @@ has_action "$todo" ||
        return 2
 
 cp "$todo" "$todo".backup
+collapse_todo_ids
 git_sequence_editor "$todo" ||
        die_abort "Could not execute editor"
 
index a9c75a2360fec7a9ce5f22877a471f70bc405ff1..752c763eb666e197304efbc7ea006325a36ff870 100755 (executable)
@@ -1,7 +1,13 @@
 #!/bin/sh
 # Copyright (c) 2012 Felipe Contreras
 
-alias=$1
+# The first argument can be a url when the fetch/push command was a url
+# instead of a configured remote. In this case, use a generic alias.
+if test "$1" = "testgit::$2"; then
+       alias=_
+else
+       alias=$1
+fi
 url=$2
 
 dir="$GIT_DIR/testgit/$alias"
index 3092ab356c765cd593d2a988d020665c8b626ea1..e1e9b1460ced5f660b32796890df7336bc3d01af 100755 (executable)
@@ -299,6 +299,7 @@ sub signal_handler {
                    "bcc=s" => \@bcclist,
                    "no-bcc" => \$no_bcc,
                    "chain-reply-to!" => \$chain_reply_to,
+                   "no-chain-reply-to" => sub {$chain_reply_to = 0},
                    "smtp-server=s" => \$smtp_server,
                    "smtp-server-option=s" => \@smtp_server_options,
                    "smtp-server-port=s" => \$smtp_server_port,
@@ -311,25 +312,34 @@ sub signal_handler {
                    "smtp-domain:s" => \$smtp_domain,
                    "identity=s" => \$identity,
                    "annotate!" => \$annotate,
+                   "no-annotate" => sub {$annotate = 0},
                    "compose" => \$compose,
                    "quiet" => \$quiet,
                    "cc-cmd=s" => \$cc_cmd,
                    "suppress-from!" => \$suppress_from,
+                   "no-suppress-from" => sub {$suppress_from = 0},
                    "suppress-cc=s" => \@suppress_cc,
                    "signed-off-cc|signed-off-by-cc!" => \$signed_off_by_cc,
+                   "no-signed-off-cc|no-signed-off-by-cc" => sub {$signed_off_by_cc = 0},
                    "cc-cover|cc-cover!" => \$cover_cc,
+                   "no-cc-cover" => sub {$cover_cc = 0},
                    "to-cover|to-cover!" => \$cover_to,
+                   "no-to-cover" => sub {$cover_to = 0},
                    "confirm=s" => \$confirm,
                    "dry-run" => \$dry_run,
                    "envelope-sender=s" => \$envelope_sender,
                    "thread!" => \$thread,
+                   "no-thread" => sub {$thread = 0},
                    "validate!" => \$validate,
+                   "no-validate" => sub {$validate = 0},
                    "transfer-encoding=s" => \$target_xfer_encoding,
                    "format-patch!" => \$format_patch,
+                   "no-format-patch" => sub {$format_patch = 0},
                    "8bit-encoding=s" => \$auto_8bit_encoding,
                    "compose-encoding=s" => \$compose_encoding,
                    "force" => \$force,
                    "xmailer!" => \$use_xmailer,
+                   "no-xmailer" => sub {$use_xmailer = 0},
         );
 
 usage() if $help;
@@ -752,6 +762,7 @@ sub file_declares_8bit_cte {
                print "    $f\n";
        }
        $auto_8bit_encoding = ask("Which 8bit encoding should I declare [UTF-8]? ",
+                                 valid_re => qr/.{4}/, confirm_only => 1,
                                  default => "UTF-8");
 }
 
index 9245abfd4263881bdd6d0f21f648b46201b52a2d..36797c3c00f4890cfb6f176f298e050da7eb5a34 100755 (executable)
@@ -423,7 +423,7 @@ cmd_add()
                sed -e '
                        s|//*|/|g
                        s|^\(\./\)*||
-                       s|/\./|/|g
+                       s|/\(\./\)*|/|g
                        :start
                        s|\([^/]*\)/\.\./||
                        tstart
index 32d109ebdf89399ac0d834cc98393324dfca7850..36f7240c99249198512689ffecdd9c95f06b8eff 100755 (executable)
 $VERSION = '@@GIT_VERSION@@';
 
 use Carp qw/croak/;
-use Digest::MD5;
-use IO::File qw//;
 use File::Basename qw/dirname basename/;
 use File::Path qw/mkpath/;
 use File::Spec;
-use File::Find;
 use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/;
-use IPC::Open3;
 use Memoize;
 
 use Git::SVN;
@@ -298,7 +294,6 @@ sub _req_svn {
                {} ],
 );
 
-use Term::ReadLine;
 package FakeTerm;
 sub new {
        my ($class, $reason) = @_;
@@ -313,6 +308,7 @@ package main;
 my $term;
 sub term_init {
        $term = eval {
+               require Term::ReadLine;
                $ENV{"GIT_SVN_NOTTY"}
                        ? new Term::ReadLine 'git-svn', \*STDIN, \*STDOUT
                        : new Term::ReadLine 'git-svn';
@@ -1173,6 +1169,7 @@ sub cmd_branch {
        }
 
        ::_req_svn();
+       require SVN::Client;
 
        my $ctx = SVN::Client->new(
                config => SVN::Core::config_get_config(
@@ -1693,11 +1690,13 @@ sub cmd_reset {
 }
 
 sub cmd_gc {
+       require File::Find;
        if (!can_compress()) {
                warn "Compress::Zlib could not be found; unhandled.log " .
                     "files will not be compressed.\n";
        }
-       find({ wanted => \&gc_directory, no_chdir => 1}, "$ENV{GIT_DIR}/svn");
+       File::Find::find({ wanted => \&gc_directory, no_chdir => 1},
+                        "$ENV{GIT_DIR}/svn");
 }
 
 ########################### utility functions #########################
@@ -2122,6 +2121,7 @@ sub find_file_type_and_diff_status {
 sub md5sum {
        my $arg = shift;
        my $ref = ref $arg;
+       require Digest::MD5;
        my $md5 = Digest::MD5->new();
         if ($ref eq 'GLOB' || $ref eq 'IO::File' || $ref eq 'File::Temp') {
                $md5->addfile($arg) or croak $!;
@@ -2148,6 +2148,7 @@ sub gc_directory {
                        $gz->gzwrite($str) or
                                die "Unable to write: ".$gz->gzerror()."!\n";
                }
+               no warnings 'once'; # $File::Find::name would warn
                unlink $_ or die "unlink $File::Find::name: $!\n";
        } elsif (-f $_ && basename($_) eq "index") {
                unlink $_ or die "unlink $_: $!\n";
diff --git a/git.c b/git.c
index 6b5ae6a2ace7fffdd2ec50ce915ad5dc01a9c7da..8c7ee9c83000765afa3808f3dd0941aa484ca1ec 100644 (file)
--- a/git.c
+++ b/git.c
@@ -6,7 +6,7 @@
 const char git_usage_string[] =
        "git [--version] [--help] [-C <path>] [-c name=value]\n"
        "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
-       "           [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]\n"
+       "           [-p | --paginate | --no-pager] [--no-replace-objects] [--bare]\n"
        "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
        "           <command> [<args>]";
 
diff --git a/grep.c b/grep.c
index 6e085f829731146c319fff57da0ae482de97ff77..b58c7c64342698737f9c11b20457bd30ca1fc727 100644 (file)
--- a/grep.c
+++ b/grep.c
@@ -1661,8 +1661,8 @@ void grep_source_init(struct grep_source *gs, enum grep_source_type type,
                      const void *identifier)
 {
        gs->type = type;
-       gs->name = name ? xstrdup(name) : NULL;
-       gs->path = path ? xstrdup(path) : NULL;
+       gs->name = xstrdup_or_null(name);
+       gs->path = xstrdup_or_null(path);
        gs->buf = NULL;
        gs->size = 0;
        gs->driver = NULL;
diff --git a/hex.c b/hex.c
index 9ebc050637532765b775cbd8e3b92951a67ea333..cfd9d722fd92f137a79ee2bf6be44b4b393c6da6 100644 (file)
--- a/hex.c
+++ b/hex.c
@@ -59,7 +59,7 @@ int get_sha1_hex(const char *hex, unsigned char *sha1)
 char *sha1_to_hex(const unsigned char *sha1)
 {
        static int bufno;
-       static char hexbuffer[4][50];
+       static char hexbuffer[4][41];
        static const char hex[] = "0123456789abcdef";
        char *buffer = hexbuffer[3 & ++bufno], *buf = buffer;
        int i;
diff --git a/http.c b/http.c
index 040f362a6a299618288c9249588ceb7aed6f3011..9c825afefdda70b8f8ccda0b9ed06e5d54333a50 100644 (file)
--- a/http.c
+++ b/http.c
@@ -8,6 +8,7 @@
 #include "credential.h"
 #include "version.h"
 #include "pkt-line.h"
+#include "gettext.h"
 
 int active_requests;
 int http_is_verbose;
@@ -62,12 +63,17 @@ static const char *user_agent;
 
 static struct credential cert_auth = CREDENTIAL_INIT;
 static int ssl_cert_password_required;
+#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
+static unsigned long http_auth_methods = CURLAUTH_ANY;
+#endif
 
 static struct curl_slist *pragma_header;
 static struct curl_slist *no_pragma_header;
 
 static struct active_request_slot *active_queue_head;
 
+static char *cached_accept_language;
+
 size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
 {
        size_t size = eltsize * nmemb;
@@ -114,6 +120,37 @@ size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf)
        return eltsize * nmemb;
 }
 
+static void closedown_active_slot(struct active_request_slot *slot)
+{
+       active_requests--;
+       slot->in_use = 0;
+}
+
+static void finish_active_slot(struct active_request_slot *slot)
+{
+       closedown_active_slot(slot);
+       curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code);
+
+       if (slot->finished != NULL)
+               (*slot->finished) = 1;
+
+       /* Store slot results so they can be read after the slot is reused */
+       if (slot->results != NULL) {
+               slot->results->curl_result = slot->curl_result;
+               slot->results->http_code = slot->http_code;
+#if LIBCURL_VERSION_NUM >= 0x070a08
+               curl_easy_getinfo(slot->curl, CURLINFO_HTTPAUTH_AVAIL,
+                                 &slot->results->auth_avail);
+#else
+               slot->results->auth_avail = 0;
+#endif
+       }
+
+       /* Run callback if appropriate */
+       if (slot->callback_func != NULL)
+               slot->callback_func(slot->callback_data);
+}
+
 #ifdef USE_CURL_MULTI
 static void process_curl_messages(void)
 {
@@ -369,7 +406,9 @@ static CURL *get_curl_handle(void)
 
        if (curl_http_proxy) {
                curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy);
+#if LIBCURL_VERSION_NUM >= 0x070a07
                curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
+#endif
        }
 
        set_curl_keepalive(result);
@@ -515,6 +554,9 @@ void http_cleanup(void)
                cert_auth.password = NULL;
        }
        ssl_cert_password_required = 0;
+
+       free(cached_accept_language);
+       cached_accept_language = NULL;
 }
 
 struct active_request_slot *get_active_slot(void)
@@ -580,6 +622,9 @@ struct active_request_slot *get_active_slot(void)
        curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0);
        curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
        curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1);
+#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
+       curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods);
+#endif
        if (http_auth.password)
                init_curl_http_auth(slot->curl);
 
@@ -730,12 +775,6 @@ void run_active_slot(struct active_request_slot *slot)
 #endif
 }
 
-static void closedown_active_slot(struct active_request_slot *slot)
-{
-       active_requests--;
-       slot->in_use = 0;
-}
-
 static void release_active_slot(struct active_request_slot *slot)
 {
        closedown_active_slot(slot);
@@ -752,31 +791,6 @@ static void release_active_slot(struct active_request_slot *slot)
 #endif
 }
 
-void finish_active_slot(struct active_request_slot *slot)
-{
-       closedown_active_slot(slot);
-       curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code);
-
-       if (slot->finished != NULL)
-               (*slot->finished) = 1;
-
-       /* Store slot results so they can be read after the slot is reused */
-       if (slot->results != NULL) {
-               slot->results->curl_result = slot->curl_result;
-               slot->results->http_code = slot->http_code;
-#if LIBCURL_VERSION_NUM >= 0x070a08
-               curl_easy_getinfo(slot->curl, CURLINFO_HTTPAUTH_AVAIL,
-                                 &slot->results->auth_avail);
-#else
-               slot->results->auth_avail = 0;
-#endif
-       }
-
-       /* Run callback if appropriate */
-       if (slot->callback_func != NULL)
-               slot->callback_func(slot->callback_data);
-}
-
 void finish_all_active_slots(void)
 {
        struct active_request_slot *slot = active_queue_head;
@@ -839,7 +853,7 @@ char *get_remote_object_url(const char *url, const char *hex,
        return strbuf_detach(&buf, NULL);
 }
 
-int handle_curl_result(struct slot_results *results)
+static int handle_curl_result(struct slot_results *results)
 {
        /*
         * If we see a failing http code with CURLE_OK, we have turned off
@@ -870,6 +884,9 @@ int handle_curl_result(struct slot_results *results)
                        credential_reject(&http_auth);
                        return HTTP_NOAUTH;
                } else {
+#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
+                       http_auth_methods &= ~CURLAUTH_GSSNEGOTIATE;
+#endif
                        return HTTP_REAUTH;
                }
        } else {
@@ -986,6 +1003,117 @@ static void extract_content_type(struct strbuf *raw, struct strbuf *type,
                strbuf_addstr(charset, "ISO-8859-1");
 }
 
+static void write_accept_language(struct strbuf *buf)
+{
+       /*
+        * MAX_DECIMAL_PLACES must not be larger than 3. If it is larger than
+        * that, q-value will be smaller than 0.001, the minimum q-value the
+        * HTTP specification allows. See
+        * http://tools.ietf.org/html/rfc7231#section-5.3.1 for q-value.
+        */
+       const int MAX_DECIMAL_PLACES = 3;
+       const int MAX_LANGUAGE_TAGS = 1000;
+       const int MAX_ACCEPT_LANGUAGE_HEADER_SIZE = 4000;
+       char **language_tags = NULL;
+       int num_langs = 0;
+       const char *s = get_preferred_languages();
+       int i;
+       struct strbuf tag = STRBUF_INIT;
+
+       /* Don't add Accept-Language header if no language is preferred. */
+       if (!s)
+               return;
+
+       /*
+        * Split the colon-separated string of preferred languages into
+        * language_tags array.
+        */
+       do {
+               /* collect language tag */
+               for (; *s && (isalnum(*s) || *s == '_'); s++)
+                       strbuf_addch(&tag, *s == '_' ? '-' : *s);
+
+               /* skip .codeset, @modifier and any other unnecessary parts */
+               while (*s && *s != ':')
+                       s++;
+
+               if (tag.len) {
+                       num_langs++;
+                       REALLOC_ARRAY(language_tags, num_langs);
+                       language_tags[num_langs - 1] = strbuf_detach(&tag, NULL);
+                       if (num_langs >= MAX_LANGUAGE_TAGS - 1) /* -1 for '*' */
+                               break;
+               }
+       } while (*s++);
+
+       /* write Accept-Language header into buf */
+       if (num_langs) {
+               int last_buf_len = 0;
+               int max_q;
+               int decimal_places;
+               char q_format[32];
+
+               /* add '*' */
+               REALLOC_ARRAY(language_tags, num_langs + 1);
+               language_tags[num_langs++] = "*"; /* it's OK; this won't be freed */
+
+               /* compute decimal_places */
+               for (max_q = 1, decimal_places = 0;
+                    max_q < num_langs && decimal_places <= MAX_DECIMAL_PLACES;
+                    decimal_places++, max_q *= 10)
+                       ;
+
+               sprintf(q_format, ";q=0.%%0%dd", decimal_places);
+
+               strbuf_addstr(buf, "Accept-Language: ");
+
+               for (i = 0; i < num_langs; i++) {
+                       if (i > 0)
+                               strbuf_addstr(buf, ", ");
+
+                       strbuf_addstr(buf, language_tags[i]);
+
+                       if (i > 0)
+                               strbuf_addf(buf, q_format, max_q - i);
+
+                       if (buf->len > MAX_ACCEPT_LANGUAGE_HEADER_SIZE) {
+                               strbuf_remove(buf, last_buf_len, buf->len - last_buf_len);
+                               break;
+                       }
+
+                       last_buf_len = buf->len;
+               }
+       }
+
+       /* free language tags -- last one is a static '*' */
+       for (i = 0; i < num_langs - 1; i++)
+               free(language_tags[i]);
+       free(language_tags);
+}
+
+/*
+ * Get an Accept-Language header which indicates user's preferred languages.
+ *
+ * Examples:
+ *   LANGUAGE= -> ""
+ *   LANGUAGE=ko:en -> "Accept-Language: ko, en; q=0.9, *; q=0.1"
+ *   LANGUAGE=ko_KR.UTF-8:sr@latin -> "Accept-Language: ko-KR, sr; q=0.9, *; q=0.1"
+ *   LANGUAGE=ko LANG=en_US.UTF-8 -> "Accept-Language: ko, *; q=0.1"
+ *   LANGUAGE= LANG=en_US.UTF-8 -> "Accept-Language: en-US, *; q=0.1"
+ *   LANGUAGE= LANG=C -> ""
+ */
+static const char *get_accept_language(void)
+{
+       if (!cached_accept_language) {
+               struct strbuf buf = STRBUF_INIT;
+               write_accept_language(&buf);
+               if (buf.len > 0)
+                       cached_accept_language = strbuf_detach(&buf, NULL);
+       }
+
+       return cached_accept_language;
+}
+
 /* http_request() targets */
 #define HTTP_REQUEST_STRBUF    0
 #define HTTP_REQUEST_FILE      1
@@ -998,6 +1126,7 @@ static int http_request(const char *url,
        struct slot_results results;
        struct curl_slist *headers = NULL;
        struct strbuf buf = STRBUF_INIT;
+       const char *accept_language;
        int ret;
 
        slot = get_active_slot();
@@ -1023,6 +1152,11 @@ static int http_request(const char *url,
                                         fwrite_buffer);
        }
 
+       accept_language = get_accept_language();
+
+       if (accept_language)
+               headers = curl_slist_append(headers, accept_language);
+
        strbuf_addstr(&buf, "Pragma:");
        if (options && options->no_cache)
                strbuf_addstr(&buf, " no-cache");
@@ -1240,7 +1374,7 @@ static int fetch_and_setup_pack_index(struct packed_git **packs_head,
        int ret;
 
        if (has_pack_index(sha1)) {
-               new_pack = parse_pack_index(sha1, NULL);
+               new_pack = parse_pack_index(sha1, sha1_pack_index_name(sha1));
                if (!new_pack)
                        return -1; /* parse_pack_index() already issued error message */
                goto add_pack;
diff --git a/http.h b/http.h
index 473179b14d5648635853af4c5bf425116c32b6fe..49afe39279d02785f3567aad2fec55c623a53d5f 100644 (file)
--- a/http.h
+++ b/http.h
@@ -85,9 +85,7 @@ extern curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp);
 extern struct active_request_slot *get_active_slot(void);
 extern int start_active_slot(struct active_request_slot *slot);
 extern void run_active_slot(struct active_request_slot *slot);
-extern void finish_active_slot(struct active_request_slot *slot);
 extern void finish_all_active_slots(void);
-extern int handle_curl_result(struct slot_results *results);
 
 /*
  * This will run one slot to completion in a blocking manner, similar to how
diff --git a/kwset.c b/kwset.c
index a0f49b3aca934008465842dd37e52d11d099e23e..e6236a0359cb3661acb8b1e609be236f6fb9d4bf 100644 (file)
--- a/kwset.c
+++ b/kwset.c
@@ -80,13 +80,13 @@ struct kwset
   struct trie *next[NCHAR];    /* Table of children of the root. */
   char *target;                        /* Target string if there's only one. */
   int mind2;                   /* Used in Boyer-Moore search for one string. */
-  char const *trans;           /* Character translation table. */
+  unsigned char const *trans;  /* Character translation table. */
 };
 
 /* Allocate and initialize a keyword set object, returning an opaque
    pointer to it.  Return NULL if memory is not available. */
 kwset_t
-kwsalloc (char const *trans)
+kwsalloc (unsigned char const *trans)
 {
   struct kwset *kwset;
 
@@ -381,7 +381,7 @@ kwsprep (kwset_t kws)
   register struct kwset *kwset;
   register int i;
   register struct trie *curr;
-  register char const *trans;
+  register unsigned char const *trans;
   unsigned char delta[NCHAR];
 
   kwset = (struct kwset *) kws;
@@ -590,7 +590,7 @@ cwexec (kwset_t kws, char const *text, size_t len, struct kwsmatch *kwsmatch)
   register int d;
   register char const *end, *qlim;
   register struct tree const *tree;
-  register char const *trans;
+  register unsigned char const *trans;
 
   accept = NULL;
 
diff --git a/kwset.h b/kwset.h
index a21b2eadfdf9f760c170f10c069a06853105eee5..61a134f256cee951f726c9619861b614fb66f9d6 100644 (file)
--- a/kwset.h
+++ b/kwset.h
@@ -39,7 +39,7 @@ typedef struct kwset_t* kwset_t;
    if enough memory cannot be obtained.  The argument if non-NULL
    specifies a table of character translations to be applied to all
    pattern and search text. */
-extern kwset_t kwsalloc(char const *);
+extern kwset_t kwsalloc(unsigned char const *);
 
 /* Incrementally extend the keyword set to include the given string.
    Return NULL for success, or an error message.  Remember an index
index b7864ad5869eb076e778c352e2f64666dc77a525..a490efea07519edb006e515c8a0fdf60241e546d 100644 (file)
@@ -237,7 +237,7 @@ static void diff_ranges_release(struct diff_ranges *diff)
        range_set_release(&diff->target);
 }
 
-void line_log_data_init(struct line_log_data *r)
+static void line_log_data_init(struct line_log_data *r)
 {
        memset(r, 0, sizeof(struct line_log_data));
        range_set_init(&r->ranges, 0);
index a9212d84e492304b4e57da1e0327189b3b6434ed..7a5c24e2df40c09274077928574bc91349d475d1 100644 (file)
@@ -54,8 +54,6 @@ struct line_log_data {
        struct diff_ranges diff;
 };
 
-extern void line_log_data_init(struct line_log_data *r);
-
 extern void line_log_init(struct rev_info *rev, const char *prefix, struct string_list *args);
 
 extern int line_log_filter(struct rev_info *rev);
diff --git a/notes.c b/notes.c
index c763a21eef5b64c984c22d18cd5f21c1bd32e5a3..2be4d7f3fd081476001212b103f011e45b4a9c41 100644 (file)
--- a/notes.c
+++ b/notes.c
@@ -1006,7 +1006,7 @@ void init_notes(struct notes_tree *t, const char *notes_ref,
        t->root = (struct int_node *) xcalloc(1, sizeof(struct int_node));
        t->first_non_note = NULL;
        t->prev_non_note = NULL;
-       t->ref = notes_ref ? xstrdup(notes_ref) : NULL;
+       t->ref = xstrdup_or_null(notes_ref);
        t->combine_notes = combine_notes;
        t->initialized = 1;
        t->dirty = 0;
index 6a818419ca46f8d66adbeb0027da49e6bab1bfa3..365f9d92ed8b57c1e766a126b6e6571009eedde5 100644 (file)
@@ -60,7 +60,7 @@ static struct bitmap_index {
        struct ewah_bitmap *blobs;
        struct ewah_bitmap *tags;
 
-       /* Map from SHA1 -> `stored_bitmap` for all the bitmapped comits */
+       /* Map from SHA1 -> `stored_bitmap` for all the bitmapped commits */
        khash_sha1 *bitmaps;
 
        /* Number of bitmapped commits */
@@ -252,6 +252,20 @@ static int load_bitmap_entries_v1(struct bitmap_index *index)
        return 0;
 }
 
+static char *pack_bitmap_filename(struct packed_git *p)
+{
+       char *idx_name;
+       int len;
+
+       len = strlen(p->pack_name) - strlen(".pack");
+       idx_name = xmalloc(len + strlen(".bitmap") + 1);
+
+       memcpy(idx_name, p->pack_name, len);
+       memcpy(idx_name + len, ".bitmap", strlen(".bitmap") + 1);
+
+       return idx_name;
+}
+
 static int open_pack_bitmap_1(struct packed_git *packfile)
 {
        int fd;
@@ -322,20 +336,6 @@ static int load_pack_bitmap(void)
        return -1;
 }
 
-char *pack_bitmap_filename(struct packed_git *p)
-{
-       char *idx_name;
-       int len;
-
-       len = strlen(p->pack_name) - strlen(".pack");
-       idx_name = xmalloc(len + strlen(".bitmap") + 1);
-
-       memcpy(idx_name, p->pack_name, len);
-       memcpy(idx_name + len, ".bitmap", strlen(".bitmap") + 1);
-
-       return idx_name;
-}
-
 static int open_pack_bitmap(void)
 {
        struct packed_git *p;
index 487600b18c79be22c4c611fc4c3d29d817f1f304..0adcef77b58cc13822f1b400d5418ec6f8b34421 100644 (file)
@@ -38,7 +38,6 @@ int prepare_bitmap_git(void);
 void count_bitmap_commit_list(uint32_t *commits, uint32_t *trees, uint32_t *blobs, uint32_t *tags);
 void traverse_bitmap_commit_list(show_reachable_fn show_reachable);
 void test_bitmap_walk(struct rev_info *revs);
-char *pack_bitmap_filename(struct packed_git *p);
 int prepare_bitmap_walk(struct rev_info *revs);
 int reuse_partial_packfile_from_bitmap(struct packed_git **packfile, uint32_t *entries, off_t *up_to);
 int rebuild_existing_bitmaps(struct packing_data *mapping, khash_sha1 *reused_bitmaps, int show_progress);
diff --git a/pager.c b/pager.c
index f6e8c331924496ca6656cd05d7de6497310502ab..98b26823c9e0c0bd220a7a41a97675626c8e65ec 100644 (file)
--- a/pager.c
+++ b/pager.c
@@ -133,12 +133,12 @@ int term_columns(void)
 /*
  * How many columns do we need to show this number in decimal?
  */
-int decimal_width(int number)
+int decimal_width(uintmax_t number)
 {
-       int i, width;
+       int width;
 
-       for (width = 1, i = 10; i <= number; width++)
-               i *= 10;
+       for (width = 1; number >= 10; width++)
+               number /= 10;
        return width;
 }
 
index b5905ee1ad03fe9973e3cf7d46fa29c5cf184215..9026a7bb980a984086a62536f46ec3837588f277 100644 (file)
@@ -695,7 +695,7 @@ sub config_path {
 is simple decimal number.  An optional value suffix of 'k', 'm',
 or 'g' in the config file will cause the value to be multiplied
 by 1024, 1048576 (1024^2), or 1073741824 (1024^3) prior to output.
-It would return C<undef> if configuration variable is not defined,
+It would return C<undef> if configuration variable is not defined.
 
 =cut
 
@@ -704,7 +704,7 @@ sub config_int {
 }
 
 # Common subroutine to implement bulk of what the config* family of methods
-# do. This curently wraps command('config') so it is not so fast.
+# do. This currently wraps command('config') so it is not so fast.
 sub _config_common {
        my ($opts) = shift @_;
        my ($self, $var) = _maybe_self(@_);
index 8e4af7153eb8a8957bd4172e0c044c1bfc748ddb..152fb7e9274c779cb66de099878b4de40e5406e4 100644 (file)
@@ -9,11 +9,10 @@ package Git::SVN;
            $_use_log_author $_add_author_from $_localtime/;
 use Carp qw/croak/;
 use File::Path qw/mkpath/;
-use File::Copy qw/copy/;
 use IPC::Open3;
 use Memoize;  # core since 5.8.0, Jul 2002
-use Memoize::Storable;
 use POSIX qw(:signal_h);
+use Time::Local;
 
 use Git qw(
     command
@@ -32,11 +31,7 @@ package Git::SVN;
        add_path_to_url
 );
 
-my $can_use_yaml;
-BEGIN {
-       $can_use_yaml = eval { require Git::SVN::Memoize::YAML; 1};
-}
-
+my $memo_backend;
 our $_follow_parent  = 1;
 our $_minimize_url   = 'unset';
 our $default_repo_id = 'svn';
@@ -1332,7 +1327,7 @@ sub parse_svn_date {
                $ENV{TZ} = 'UTC';
 
                my $epoch_in_UTC =
-                   POSIX::strftime('%s', $S, $M, $H, $d, $m - 1, $Y - 1900);
+                   Time::Local::timelocal($S, $M, $H, $d, $m - 1, $Y - 1900);
 
                # Determine our local timezone (including DST) at the
                # time of $epoch_in_UTC.  $Git::SVN::Log::TZ stored the
@@ -1578,7 +1573,16 @@ sub tie_for_persistent_memoization {
        my $hash = shift;
        my $path = shift;
 
-       if ($can_use_yaml) {
+       unless ($memo_backend) {
+               if (eval { require Git::SVN::Memoize::YAML; 1}) {
+                       $memo_backend = 1;
+               } else {
+                       require Memoize::Storable;
+                       $memo_backend = -1;
+               }
+       }
+
+       if ($memo_backend > 0) {
                tie %$hash => 'Git::SVN::Memoize::YAML', "$path.yaml";
        } else {
                tie %$hash => 'Memoize::Storable', "$path.db", 'nstore';
@@ -2188,8 +2192,9 @@ sub rev_map_set {
        # both of these options make our .rev_db file very, very important
        # and we can't afford to lose it because rebuild() won't work
        if ($self->use_svm_props || $self->no_metadata) {
+               require File::Copy;
                $sync = 1;
-               copy($db, $db_lock) or die "rev_map_set(@_): ",
+               File::Copy::copy($db, $db_lock) or die "rev_map_set(@_): ",
                                           "Failed to copy: ",
                                           "$db => $db_lock ($!)\n";
        } else {
index 4088f13e723a51a6e1cee0c616a7c279a780461d..c50176eec9418c50e5c63921c24e76a87b6123ab 100644 (file)
@@ -5,7 +5,6 @@ package Git::SVN::Editor;
 use SVN::Core;
 use SVN::Delta;
 use Carp qw/croak/;
-use IO::File;
 use Git qw/command command_oneline command_noisy command_output_pipe
            command_input_pipe command_close_pipe
            command_bidi_pipe command_close_bidi_pipe/;
@@ -586,7 +585,7 @@ =head1 DESCRIPTION
 =head1 DEPENDENCIES
 
 Subversion perl bindings,
-the core L<Carp> and L<IO::File> modules,
+the core L<Carp> module,
 and git's L<Git> helper module.
 
 C<Git::SVN::Editor> has not been tested using callers other than
index 10edb27732f439e5290a7b354efefeb10d219669..d8c21ad91549b4e52ce95c5e694db2f53f9931c9 100644 (file)
@@ -7,7 +7,6 @@ package Git::SVN::Fetcher;
 use SVN::Delta;
 use Carp qw/croak/;
 use File::Basename qw/dirname/;
-use IO::File qw//;
 use Git qw/command command_oneline command_noisy command_output_pipe
            command_input_pipe command_close_pipe
            command_bidi_pipe command_close_bidi_pipe/;
@@ -322,6 +321,14 @@ sub apply_textdelta {
        # (but $base does not,) so dup() it for reading in close_file
        open my $dup, '<&', $fh or croak $!;
        my $base = $::_repository->temp_acquire("git_blob_${$}_$suffix");
+       # close_file may call temp_acquire on 'svn_hash', but because of the
+       # call chain, if the temp_acquire call from close_file ends up being the
+       # call that first creates the 'svn_hash' temp file, then the FileHandle
+       # that's created as a result will end up in an SVN::Pool that we clear
+       # in SVN::Ra::gs_fetch_loop_common.  Avoid that by making sure the
+       # 'svn_hash' FileHandle is already created before close_file is called.
+       my $tmp_fh = $::_repository->temp_acquire('svn_hash');
+       $::_repository->temp_release($tmp_fh, 1);
 
        if ($fb->{blob}) {
                my ($base_is_link, $size);
@@ -600,7 +607,7 @@ =head1 DESCRIPTION
 =head1 DEPENDENCIES
 
 L<SVN::Delta> from the Subversion perl bindings,
-the core L<Carp>, L<File::Basename>, and L<IO::File> modules,
+the core L<Carp> and L<File::Basename> modules,
 and git's L<Git> helper module.
 
 C<Git::SVN::Fetcher> has not been tested using callers other than
index 622535e21760f9fd5c6b63f97d41b48be9c04db6..4a499fcb38daf4ab8d3e20ca0fa10e5732e684a9 100644 (file)
@@ -3,7 +3,6 @@ package Git::SVN::Ra;
 use strict;
 use warnings;
 use Memoize;
-use SVN::Client;
 use Git::SVN::Utils qw(
        canonicalize_url
        canonicalize_path
@@ -42,6 +41,7 @@ END
 }
 
 sub _auth_providers () {
+       require SVN::Client;
        my @rv = (
          SVN::Client::get_simple_provider(),
          SVN::Client::get_ssl_server_trust_file_provider(),
@@ -247,7 +247,10 @@ sub get_log {
        $ret;
 }
 
+# uncommon, only for ancient SVN (<= 1.4.2)
 sub trees_match {
+       require IO::File;
+       require SVN::Client;
        my ($self, $url1, $rev1, $url2, $rev2) = @_;
        my $ctx = SVN::Client->new(auth => _auth_providers);
        my $out = IO::File->new_tmpfile;
@@ -391,6 +394,9 @@ sub longest_common_path {
 sub gs_fetch_loop_common {
        my ($self, $base, $head, $gsv, $globs) = @_;
        return if ($base > $head);
+       # Make sure the cat_blob open2 FileHandle is created before calling
+       # SVN::Pool::new_default so that it does not incorrectly end up in the pool.
+       $::_repository->_open_cat_blob_if_needed;
        my $gpool = SVN::Pool->new_default;
        my $ra_url = $self->url;
        my $reload_ra = sub {
index 9d34d02db11bd6761d48484327fbc6d1704ad555..7b493041814dc8514bde0778497d39868c8455d7 100644 (file)
--- a/pretty.c
+++ b/pretty.c
@@ -567,7 +567,7 @@ static char *replace_encoding_header(char *buf, const char *encoding)
        char *cp = buf;
 
        /* guess if there is an encoding header before a \n\n */
-       while (strncmp(cp, "encoding ", strlen("encoding "))) {
+       while (!starts_with(cp, "encoding ")) {
                cp = strchr(cp, '\n');
                if (!cp || *++cp == '\n')
                        return buf;
index 8181eebbfcd0080540bc580416336436ced98297..75406390c6fdabf74e74d4c2a90e6ac92afc4ccc 100644 (file)
--- a/prompt.c
+++ b/prompt.c
@@ -73,8 +73,3 @@ char *git_prompt(const char *prompt, int flags)
        }
        return r;
 }
-
-char *git_getpass(const char *prompt)
-{
-       return git_prompt(prompt, PROMPT_ASKPASS);
-}
index 04f321a781d37af780b906c2a4564c08eea830c8..e04cced030ca4df6d729c2132ca4671b959952b4 100644 (file)
--- a/prompt.h
+++ b/prompt.h
@@ -5,6 +5,5 @@
 #define PROMPT_ECHO    (1<<1)
 
 char *git_prompt(const char *prompt, int flags);
-char *git_getpass(const char *prompt);
 
 #endif /* PROMPT_H */
index 9cff715d6b669ecf05f861bc553b61d20d04191d..8d71860f692ffa5deafe7f23774b1b9ab2f31378 100644 (file)
@@ -725,7 +725,7 @@ struct cache_entry *make_cache_entry(unsigned int mode,
                unsigned int refresh_options)
 {
        int size, len;
-       struct cache_entry *ce;
+       struct cache_entry *ce, *ret;
 
        if (!verify_path(path)) {
                error("Invalid path '%s'", path);
@@ -742,7 +742,13 @@ struct cache_entry *make_cache_entry(unsigned int mode,
        ce->ce_namelen = len;
        ce->ce_mode = create_ce_mode(mode);
 
-       return refresh_cache_entry(ce, refresh_options);
+       ret = refresh_cache_entry(ce, refresh_options);
+       if (!ret) {
+               free(ce);
+               return NULL;
+       } else {
+               return ret;
+       }
 }
 
 int ce_same_name(const struct cache_entry *a, const struct cache_entry *b)
diff --git a/refs.c b/refs.c
index 05a4be0c0628098dec80d9bd8a564cfc019c2427..e23542b3869b38e47f59f102d28648d30d506574 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -34,10 +34,29 @@ static unsigned char refname_disposition[256] = {
 };
 
 /*
- * Used as a flag to ref_transaction_delete when a loose ref is being
+ * Flag passed to lock_ref_sha1_basic() telling it to tolerate broken
+ * refs (i.e., because the reference is about to be deleted anyway).
+ */
+#define REF_DELETING   0x02
+
+/*
+ * Used as a flag in ref_update::flags when a loose ref is being
  * pruned.
  */
-#define REF_ISPRUNING  0x0100
+#define REF_ISPRUNING  0x04
+
+/*
+ * Used as a flag in ref_update::flags when the reference should be
+ * updated to new_sha1.
+ */
+#define REF_HAVE_NEW   0x08
+
+/*
+ * Used as a flag in ref_update::flags when old_sha1 should be
+ * checked.
+ */
+#define REF_HAVE_OLD   0x10
+
 /*
  * Try to read one refname component from the front of refname.
  * Return the length of the component found, or -1 if the component is
@@ -1626,8 +1645,7 @@ const char *resolve_ref_unsafe(const char *refname, int resolve_flags, unsigned
 
 char *resolve_refdup(const char *ref, int resolve_flags, unsigned char *sha1, int *flags)
 {
-       const char *ret = resolve_ref_unsafe(ref, resolve_flags, sha1, flags);
-       return ret ? xstrdup(ret) : NULL;
+       return xstrdup_or_null(resolve_ref_unsafe(ref, resolve_flags, sha1, flags));
 }
 
 /* The argument to filter_refs */
@@ -2249,7 +2267,7 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)
 static struct ref_lock *lock_ref_sha1_basic(const char *refname,
                                            const unsigned char *old_sha1,
                                            const struct string_list *skip,
-                                           int flags, int *type_p)
+                                           unsigned int flags, int *type_p)
 {
        char *ref_file;
        const char *orig_refname = refname;
@@ -2558,7 +2576,7 @@ static void prune_ref(struct ref_to_prune *r)
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
            ref_transaction_delete(transaction, r->name, r->sha1,
-                                  REF_ISPRUNING, 1, NULL, &err) ||
+                                  REF_ISPRUNING, NULL, &err) ||
            ref_transaction_commit(transaction, &err)) {
                ref_transaction_free(transaction);
                error("%s", err.buf);
@@ -2728,15 +2746,16 @@ static int delete_ref_loose(struct ref_lock *lock, int flag, struct strbuf *err)
        return 0;
 }
 
-int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
+int delete_ref(const char *refname, const unsigned char *sha1, unsigned int flags)
 {
        struct ref_transaction *transaction;
        struct strbuf err = STRBUF_INIT;
 
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
-           ref_transaction_delete(transaction, refname, sha1, delopt,
-                                  sha1 && !is_null_sha1(sha1), NULL, &err) ||
+           ref_transaction_delete(transaction, refname,
+                                  (sha1 && !is_null_sha1(sha1)) ? sha1 : NULL,
+                                  flags, NULL, &err) ||
            ref_transaction_commit(transaction, &err)) {
                error("%s", err.buf);
                ref_transaction_free(transaction);
@@ -3541,16 +3560,27 @@ int for_each_reflog(each_ref_fn fn, void *cb_data)
 }
 
 /**
- * Information needed for a single ref update.  Set new_sha1 to the
- * new value or to zero to delete the ref.  To check the old value
- * while locking the ref, set have_old to 1 and set old_sha1 to the
- * value or to zero to ensure the ref does not exist before update.
+ * Information needed for a single ref update. Set new_sha1 to the new
+ * value or to null_sha1 to delete the ref. To check the old value
+ * while the ref is locked, set (flags & REF_HAVE_OLD) and set
+ * old_sha1 to the old value, or to null_sha1 to ensure the ref does
+ * not exist before update.
  */
 struct ref_update {
+       /*
+        * If (flags & REF_HAVE_NEW), set the reference to this value:
+        */
        unsigned char new_sha1[20];
+       /*
+        * If (flags & REF_HAVE_OLD), check that the reference
+        * previously had this value:
+        */
        unsigned char old_sha1[20];
-       int flags; /* REF_NODEREF? */
-       int have_old; /* 1 if old_sha1 is valid, 0 otherwise */
+       /*
+        * One or more of REF_HAVE_NEW, REF_HAVE_OLD, REF_NODEREF,
+        * REF_DELETING, and REF_ISPRUNING:
+        */
+       unsigned int flags;
        struct ref_lock *lock;
        int type;
        char *msg;
@@ -3622,7 +3652,7 @@ int ref_transaction_update(struct ref_transaction *transaction,
                           const char *refname,
                           const unsigned char *new_sha1,
                           const unsigned char *old_sha1,
-                          int flags, int have_old, const char *msg,
+                          unsigned int flags, const char *msg,
                           struct strbuf *err)
 {
        struct ref_update *update;
@@ -3632,10 +3662,7 @@ int ref_transaction_update(struct ref_transaction *transaction,
        if (transaction->state != REF_TRANSACTION_OPEN)
                die("BUG: update called for transaction that is not open");
 
-       if (have_old && !old_sha1)
-               die("BUG: have_old is true but old_sha1 is NULL");
-
-       if (!is_null_sha1(new_sha1) &&
+       if (new_sha1 && !is_null_sha1(new_sha1) &&
            check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
                strbuf_addf(err, "refusing to update ref with bad name %s",
                            refname);
@@ -3643,11 +3670,15 @@ int ref_transaction_update(struct ref_transaction *transaction,
        }
 
        update = add_update(transaction, refname);
-       hashcpy(update->new_sha1, new_sha1);
-       update->flags = flags;
-       update->have_old = have_old;
-       if (have_old)
+       if (new_sha1) {
+               hashcpy(update->new_sha1, new_sha1);
+               flags |= REF_HAVE_NEW;
+       }
+       if (old_sha1) {
                hashcpy(update->old_sha1, old_sha1);
+               flags |= REF_HAVE_OLD;
+       }
+       update->flags = flags;
        if (msg)
                update->msg = xstrdup(msg);
        return 0;
@@ -3656,34 +3687,52 @@ int ref_transaction_update(struct ref_transaction *transaction,
 int ref_transaction_create(struct ref_transaction *transaction,
                           const char *refname,
                           const unsigned char *new_sha1,
-                          int flags, const char *msg,
+                          unsigned int flags, const char *msg,
                           struct strbuf *err)
 {
+       if (!new_sha1 || is_null_sha1(new_sha1))
+               die("BUG: create called without valid new_sha1");
        return ref_transaction_update(transaction, refname, new_sha1,
-                                     null_sha1, flags, 1, msg, err);
+                                     null_sha1, flags, msg, err);
 }
 
 int ref_transaction_delete(struct ref_transaction *transaction,
                           const char *refname,
                           const unsigned char *old_sha1,
-                          int flags, int have_old, const char *msg,
+                          unsigned int flags, const char *msg,
                           struct strbuf *err)
 {
-       return ref_transaction_update(transaction, refname, null_sha1,
-                                     old_sha1, flags, have_old, msg, err);
+       if (old_sha1 && is_null_sha1(old_sha1))
+               die("BUG: delete called with old_sha1 set to zeros");
+       return ref_transaction_update(transaction, refname,
+                                     null_sha1, old_sha1,
+                                     flags, msg, err);
 }
 
-int update_ref(const char *action, const char *refname,
-              const unsigned char *sha1, const unsigned char *oldval,
-              int flags, enum action_on_err onerr)
+int ref_transaction_verify(struct ref_transaction *transaction,
+                          const char *refname,
+                          const unsigned char *old_sha1,
+                          unsigned int flags,
+                          struct strbuf *err)
+{
+       if (!old_sha1)
+               die("BUG: verify called with old_sha1 set to NULL");
+       return ref_transaction_update(transaction, refname,
+                                     NULL, old_sha1,
+                                     flags, NULL, err);
+}
+
+int update_ref(const char *msg, const char *refname,
+              const unsigned char *new_sha1, const unsigned char *old_sha1,
+              unsigned int flags, enum action_on_err onerr)
 {
        struct ref_transaction *t;
        struct strbuf err = STRBUF_INIT;
 
        t = ref_transaction_begin(&err);
        if (!t ||
-           ref_transaction_update(t, refname, sha1, oldval, flags,
-                                  !!oldval, action, &err) ||
+           ref_transaction_update(t, refname, new_sha1, old_sha1,
+                                  flags, msg, &err) ||
            ref_transaction_commit(t, &err)) {
                const char *str = "update_ref failed for ref '%s': %s";
 
@@ -3759,17 +3808,17 @@ int ref_transaction_commit(struct ref_transaction *transaction,
        /* Acquire all locks while verifying old values */
        for (i = 0; i < n; i++) {
                struct ref_update *update = updates[i];
-               int flags = update->flags;
+               unsigned int flags = update->flags;
 
-               if (is_null_sha1(update->new_sha1))
+               if ((flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1))
                        flags |= REF_DELETING;
-               update->lock = lock_ref_sha1_basic(update->refname,
-                                                  (update->have_old ?
-                                                   update->old_sha1 :
-                                                   NULL),
-                                                  NULL,
-                                                  flags,
-                                                  &update->type);
+               update->lock = lock_ref_sha1_basic(
+                               update->refname,
+                               ((update->flags & REF_HAVE_OLD) ?
+                                update->old_sha1 : NULL),
+                               NULL,
+                               flags,
+                               &update->type);
                if (!update->lock) {
                        ret = (errno == ENOTDIR)
                                ? TRANSACTION_NAME_CONFLICT
@@ -3783,8 +3832,9 @@ int ref_transaction_commit(struct ref_transaction *transaction,
        /* Perform updates first so live commits remain referenced */
        for (i = 0; i < n; i++) {
                struct ref_update *update = updates[i];
+               int flags = update->flags;
 
-               if (!is_null_sha1(update->new_sha1)) {
+               if ((flags & REF_HAVE_NEW) && !is_null_sha1(update->new_sha1)) {
                        int overwriting_symref = ((update->type & REF_ISSYMREF) &&
                                                  (update->flags & REF_NODEREF));
 
@@ -3813,14 +3863,15 @@ int ref_transaction_commit(struct ref_transaction *transaction,
        /* Perform deletes now that updates are safely completed */
        for (i = 0; i < n; i++) {
                struct ref_update *update = updates[i];
+               int flags = update->flags;
 
-               if (update->lock) {
+               if ((flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1)) {
                        if (delete_ref_loose(update->lock, update->type, err)) {
                                ret = TRANSACTION_GENERIC_ERROR;
                                goto cleanup;
                        }
 
-                       if (!(update->flags & REF_ISPRUNING))
+                       if (!(flags & REF_ISPRUNING))
                                string_list_append(&refs_to_delete,
                                                   update->lock->ref_name);
                }
diff --git a/refs.h b/refs.h
index afa3c4decd5562c85978e49a9e1c2a34c128b055..cf642e6ddc438be77d64797a4dbcf790262a9fed 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -183,12 +183,10 @@ extern int peel_ref(const char *refname, unsigned char *sha1);
  * Flags controlling ref_transaction_update(), ref_transaction_create(), etc.
  * REF_NODEREF: act on the ref directly, instead of dereferencing
  *              symbolic references.
- * REF_DELETING: tolerate broken refs
  *
- * Flags >= 0x100 are reserved for internal use.
+ * Other flags are reserved for internal use.
  */
 #define REF_NODEREF    0x01
-#define REF_DELETING   0x02
 
 /*
  * Setup reflog before using. Set errno to something meaningful on failure.
@@ -257,57 +255,95 @@ enum action_on_err {
 struct ref_transaction *ref_transaction_begin(struct strbuf *err);
 
 /*
- * The following functions add a reference check or update to a
- * ref_transaction.  In all of them, refname is the name of the
- * reference to be affected.  The functions make internal copies of
- * refname and msg, so the caller retains ownership of these parameters.
- * flags can be REF_NODEREF; it is passed to update_ref_lock().
+ * Reference transaction updates
+ *
+ * The following four functions add a reference check or update to a
+ * ref_transaction.  They have some common similar parameters:
+ *
+ *     transaction -- a pointer to an open ref_transaction, obtained
+ *         from ref_transaction_begin().
+ *
+ *     refname -- the name of the reference to be affected.
+ *
+ *     flags -- flags affecting the update, passed to
+ *         update_ref_lock(). Can be REF_NODEREF, which means that
+ *         symbolic references should not be followed.
+ *
+ *     msg -- a message describing the change (for the reflog).
+ *
+ *     err -- a strbuf for receiving a description of any error that
+ *         might have occured.
+ *
+ * The functions make internal copies of refname and msg, so the
+ * caller retains ownership of these parameters.
+ *
+ * The functions return 0 on success and non-zero on failure. A
+ * failure means that the transaction as a whole has failed and needs
+ * to be rolled back.
  */
 
 /*
- * Add a reference update to transaction.  new_sha1 is the value that
- * the reference should have after the update, or null_sha1 if it should
- * be deleted.  If have_old is true, then old_sha1 holds the value
- * that the reference should have had before the update, or zeros if
- * it must not have existed beforehand.
- * Function returns 0 on success and non-zero on failure. A failure to update
- * means that the transaction as a whole has failed and will need to be
- * rolled back.
+ * Add a reference update to transaction. new_sha1 is the value that
+ * the reference should have after the update, or null_sha1 if it
+ * should be deleted. If new_sha1 is NULL, then the reference is not
+ * changed at all. old_sha1 is the value that the reference must have
+ * before the update, or null_sha1 if it must not have existed
+ * beforehand. The old value is checked after the lock is taken to
+ * prevent races. If the old value doesn't agree with old_sha1, the
+ * whole transaction fails. If old_sha1 is NULL, then the previous
+ * value is not checked.
+ *
+ * See the above comment "Reference transaction updates" for more
+ * information.
  */
 int ref_transaction_update(struct ref_transaction *transaction,
                           const char *refname,
                           const unsigned char *new_sha1,
                           const unsigned char *old_sha1,
-                          int flags, int have_old, const char *msg,
+                          unsigned int flags, const char *msg,
                           struct strbuf *err);
 
 /*
- * Add a reference creation to transaction.  new_sha1 is the value
- * that the reference should have after the update; it must not be the
- * null SHA-1.  It is verified that the reference does not exist
+ * Add a reference creation to transaction. new_sha1 is the value that
+ * the reference should have after the update; it must not be
+ * null_sha1. It is verified that the reference does not exist
  * already.
- * Function returns 0 on success and non-zero on failure. A failure to create
- * means that the transaction as a whole has failed and will need to be
- * rolled back.
+ *
+ * See the above comment "Reference transaction updates" for more
+ * information.
  */
 int ref_transaction_create(struct ref_transaction *transaction,
                           const char *refname,
                           const unsigned char *new_sha1,
-                          int flags, const char *msg,
+                          unsigned int flags, const char *msg,
                           struct strbuf *err);
 
 /*
- * Add a reference deletion to transaction.  If have_old is true, then
- * old_sha1 holds the value that the reference should have had before
- * the update (which must not be the null SHA-1).
- * Function returns 0 on success and non-zero on failure. A failure to delete
- * means that the transaction as a whole has failed and will need to be
- * rolled back.
+ * Add a reference deletion to transaction. If old_sha1 is non-NULL,
+ * then it holds the value that the reference should have had before
+ * the update (which must not be null_sha1).
+ *
+ * See the above comment "Reference transaction updates" for more
+ * information.
  */
 int ref_transaction_delete(struct ref_transaction *transaction,
                           const char *refname,
                           const unsigned char *old_sha1,
-                          int flags, int have_old, const char *msg,
+                          unsigned int flags, const char *msg,
+                          struct strbuf *err);
+
+/*
+ * Verify, within a transaction, that refname has the value old_sha1,
+ * or, if old_sha1 is null_sha1, then verify that the reference
+ * doesn't exist. old_sha1 must be non-NULL.
+ *
+ * See the above comment "Reference transaction updates" for more
+ * information.
+ */
+int ref_transaction_verify(struct ref_transaction *transaction,
+                          const char *refname,
+                          const unsigned char *old_sha1,
+                          unsigned int flags,
                           struct strbuf *err);
 
 /*
@@ -328,10 +364,17 @@ int ref_transaction_commit(struct ref_transaction *transaction,
  */
 void ref_transaction_free(struct ref_transaction *transaction);
 
-/** Lock a ref and then write its file */
-int update_ref(const char *action, const char *refname,
-               const unsigned char *sha1, const unsigned char *oldval,
-               int flags, enum action_on_err onerr);
+/**
+ * Lock, update, and unlock a single reference. This function
+ * basically does a transaction containing a single call to
+ * ref_transaction_update(). The parameters to this function have the
+ * same meaning as the corresponding parameters to
+ * ref_transaction_update(). Handle errors as requested by the `onerr`
+ * argument.
+ */
+int update_ref(const char *msg, const char *refname,
+              const unsigned char *new_sha1, const unsigned char *old_sha1,
+              unsigned int flags, enum action_on_err onerr);
 
 extern int parse_hide_refs_config(const char *var, const char *value, const char *);
 extern int ref_is_hidden(const char *);
index dd63bc27abf8ae4b9e480ba1bb88942db11a0e48..deb4bfe684512ea48fbc0d2663270e44722db26b 100644 (file)
@@ -760,7 +760,7 @@ static int fetch_git(struct discovery *heads,
 
        for (i = 0; i < nr_heads; i++) {
                struct ref *ref = to_fetch[i];
-               if (!ref->name || !*ref->name)
+               if (!*ref->name)
                        die("cannot fetch by sha1 over smart http");
                packet_buf_write(&preamble, "%s %s\n",
                                 sha1_to_hex(ref->old_sha1), ref->name);
@@ -962,6 +962,8 @@ int main(int argc, const char **argv)
        struct strbuf buf = STRBUF_INIT;
        int nongit;
 
+       git_setup_gettext();
+
        git_extract_argv0_path(argv[0]);
        setup_git_directory_gently(&nongit);
        if (argc < 2) {
index 5b9c6931c1e66adb03f5d505aa8dd57169452eae..68901b0070d257dc31b59e9292cd7b6d7ef2e952 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -975,8 +975,8 @@ struct ref *copy_ref(const struct ref *ref)
        cpy = xmalloc(sizeof(struct ref) + len + 1);
        memcpy(cpy, ref, sizeof(struct ref) + len + 1);
        cpy->next = NULL;
-       cpy->symref = ref->symref ? xstrdup(ref->symref) : NULL;
-       cpy->remote_status = ref->remote_status ? xstrdup(ref->remote_status) : NULL;
+       cpy->symref = xstrdup_or_null(ref->symref);
+       cpy->remote_status = xstrdup_or_null(ref->remote_status);
        cpy->peer_ref = copy_ref(ref->peer_ref);
        return cpy;
 }
@@ -2156,7 +2156,7 @@ struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fet
 /*
  * Compare-and-swap
  */
-void clear_cas_option(struct push_cas_option *cas)
+static void clear_cas_option(struct push_cas_option *cas)
 {
        int i;
 
index f346524dbd805bca5167337b71e5eff605fcd81b..02d66ceff5c962995de37f351a09fe91055d6364 100644 (file)
--- a/remote.h
+++ b/remote.h
@@ -261,7 +261,6 @@ struct push_cas_option {
 
 extern int parseopt_push_cas_option(const struct option *, const char *arg, int unset);
 extern int parse_push_cas_option(struct push_cas_option *, const char *arg, int unset);
-extern void clear_cas_option(struct push_cas_option *);
 
 extern int is_empty_cas(const struct push_cas_option *);
 void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
index 1b0555f1a5a0233e931b13a088c052a56aef3977..31644dec04fe4a77d43624720ff516de2d746dbc 100644 (file)
--- a/rerere.c
+++ b/rerere.c
@@ -477,27 +477,23 @@ static int merge(const char *name, const char *path)
 
 static struct lock_file index_lock;
 
-static int update_paths(struct string_list *update)
+static void update_paths(struct string_list *update)
 {
        int i;
-       int fd = hold_locked_index(&index_lock, 0);
-       int status = 0;
 
-       if (fd < 0)
-               return -1;
+       hold_locked_index(&index_lock, 1);
 
        for (i = 0; i < update->nr; i++) {
                struct string_list_item *item = &update->items[i];
-               if (add_file_to_cache(item->string, ADD_CACHE_IGNORE_ERRORS))
-                       status = -1;
+               if (add_file_to_cache(item->string, 0))
+                       exit(128);
        }
 
-       if (!status && active_cache_changed) {
+       if (active_cache_changed) {
                if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK))
                        die("Unable to write new index file");
-       } else if (fd >= 0)
+       } else
                rollback_lock_file(&index_lock);
-       return status;
 }
 
 static int do_plain_rerere(struct string_list *rr, int fd)
index 86406a26a2d4599ea401d1faa9a817cadb3b7bcd..66520c671ee1141b1c0edb7ab776dd9d9df04726 100644 (file)
@@ -2017,6 +2017,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
                grep_set_pattern_type_option(GREP_PATTERN_TYPE_PCRE, &revs->grep_filter);
        } else if (!strcmp(arg, "--all-match")) {
                revs->grep_filter.all_match = 1;
+       } else if (!strcmp(arg, "--invert-grep")) {
+               revs->invert_grep = 1;
        } else if ((argcount = parse_long_opt("encoding", argv, &optarg))) {
                if (strcmp(optarg, "none"))
                        git_log_output_encoding = xstrdup(optarg);
@@ -2915,7 +2917,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
                                     (char *)message, strlen(message));
        strbuf_release(&buf);
        unuse_commit_buffer(commit, message);
-       return retval;
+       return opt->invert_grep ? !retval : retval;
 }
 
 static inline int want_ancestry(const struct rev_info *revs)
@@ -2968,6 +2970,61 @@ enum commit_action get_commit_action(struct rev_info *revs, struct commit *commi
        return commit_show;
 }
 
+define_commit_slab(saved_parents, struct commit_list *);
+
+#define EMPTY_PARENT_LIST ((struct commit_list *)-1)
+
+/*
+ * You may only call save_parents() once per commit (this is checked
+ * for non-root commits).
+ */
+static void save_parents(struct rev_info *revs, struct commit *commit)
+{
+       struct commit_list **pp;
+
+       if (!revs->saved_parents_slab) {
+               revs->saved_parents_slab = xmalloc(sizeof(struct saved_parents));
+               init_saved_parents(revs->saved_parents_slab);
+       }
+
+       pp = saved_parents_at(revs->saved_parents_slab, commit);
+
+       /*
+        * When walking with reflogs, we may visit the same commit
+        * several times: once for each appearance in the reflog.
+        *
+        * In this case, save_parents() will be called multiple times.
+        * We want to keep only the first set of parents.  We need to
+        * store a sentinel value for an empty (i.e., NULL) parent
+        * list to distinguish it from a not-yet-saved list, however.
+        */
+       if (*pp)
+               return;
+       if (commit->parents)
+               *pp = copy_commit_list(commit->parents);
+       else
+               *pp = EMPTY_PARENT_LIST;
+}
+
+static void free_saved_parents(struct rev_info *revs)
+{
+       if (revs->saved_parents_slab)
+               clear_saved_parents(revs->saved_parents_slab);
+}
+
+struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit)
+{
+       struct commit_list *parents;
+
+       if (!revs->saved_parents_slab)
+               return commit->parents;
+
+       parents = *saved_parents_at(revs->saved_parents_slab, commit);
+       if (parents == EMPTY_PARENT_LIST)
+               return NULL;
+       return parents;
+}
+
 enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
 {
        enum commit_action action = get_commit_action(revs, commit);
@@ -3267,54 +3324,3 @@ void put_revision_mark(const struct rev_info *revs, const struct commit *commit)
        fputs(mark, stdout);
        putchar(' ');
 }
-
-define_commit_slab(saved_parents, struct commit_list *);
-
-#define EMPTY_PARENT_LIST ((struct commit_list *)-1)
-
-void save_parents(struct rev_info *revs, struct commit *commit)
-{
-       struct commit_list **pp;
-
-       if (!revs->saved_parents_slab) {
-               revs->saved_parents_slab = xmalloc(sizeof(struct saved_parents));
-               init_saved_parents(revs->saved_parents_slab);
-       }
-
-       pp = saved_parents_at(revs->saved_parents_slab, commit);
-
-       /*
-        * When walking with reflogs, we may visit the same commit
-        * several times: once for each appearance in the reflog.
-        *
-        * In this case, save_parents() will be called multiple times.
-        * We want to keep only the first set of parents.  We need to
-        * store a sentinel value for an empty (i.e., NULL) parent
-        * list to distinguish it from a not-yet-saved list, however.
-        */
-       if (*pp)
-               return;
-       if (commit->parents)
-               *pp = copy_commit_list(commit->parents);
-       else
-               *pp = EMPTY_PARENT_LIST;
-}
-
-struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit)
-{
-       struct commit_list *parents;
-
-       if (!revs->saved_parents_slab)
-               return commit->parents;
-
-       parents = *saved_parents_at(revs->saved_parents_slab, commit);
-       if (parents == EMPTY_PARENT_LIST)
-               return NULL;
-       return parents;
-}
-
-void free_saved_parents(struct rev_info *revs)
-{
-       if (revs->saved_parents_slab)
-               clear_saved_parents(revs->saved_parents_slab);
-}
index 033a24460e71b723f95ef91f4b6f0dbfd8c2c390..0ea8b4e25555e30d852f47ce37ec2a75a61043e3 100644 (file)
@@ -169,6 +169,8 @@ struct rev_info {
 
        /* Filter by commit log message */
        struct grep_opt grep_filter;
+       /* Negate the match of grep_filter */
+       int invert_grep;
 
        /* Display history graph */
        struct git_graph *graph;
@@ -298,18 +300,14 @@ extern int rewrite_parents(struct rev_info *revs, struct commit *commit,
        rewrite_parent_fn_t rewrite_parent);
 
 /*
- * Save a copy of the parent list, and return the saved copy.  This is
- * used by the log machinery to retrieve the original parents when
- * commit->parents has been modified by history simpification.
- *
- * You may only call save_parents() once per commit (this is checked
- * for non-root commits).
+ * The log machinery saves the original parent list so that
+ * get_saved_parents() can later tell what the real parents of the
+ * commits are, when commit->parents has been modified by history
+ * simpification.
  *
  * get_saved_parents() will transparently return commit->parents if
  * history simplification is off.
  */
-extern void save_parents(struct rev_info *revs, struct commit *commit);
 extern struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit);
-extern void free_saved_parents(struct rev_info *revs);
 
 #endif
index 77a1266760718b8e5b029636409634e241981888..32aa05ed828dfa3bac79edb83dd8a222560206d3 100644 (file)
@@ -252,7 +252,7 @@ static int fast_forward_to(const unsigned char *to, const unsigned char *from,
        if (!transaction ||
            ref_transaction_update(transaction, "HEAD",
                                   to, unborn ? null_sha1 : from,
-                                  0, 1, sb.buf, &err) ||
+                                  0, sb.buf, &err) ||
            ref_transaction_commit(transaction, &err)) {
                ref_transaction_free(transaction);
                error("%s", err.buf);
index 30995e61b38fbfd1733acc5c3c5866b61d9f09e1..69a60ec88bad190f885cd89a93573236a88ddbd9 100644 (file)
@@ -3359,31 +3359,42 @@ static int for_each_file_in_obj_subdir(int subdir_nr,
        return r;
 }
 
-int for_each_loose_file_in_objdir(const char *path,
+int for_each_loose_file_in_objdir_buf(struct strbuf *path,
                            each_loose_object_fn obj_cb,
                            each_loose_cruft_fn cruft_cb,
                            each_loose_subdir_fn subdir_cb,
                            void *data)
 {
-       struct strbuf buf = STRBUF_INIT;
-       size_t baselen;
+       size_t baselen = path->len;
        int r = 0;
        int i;
 
-       strbuf_addstr(&buf, path);
-       strbuf_addch(&buf, '/');
-       baselen = buf.len;
-
        for (i = 0; i < 256; i++) {
-               strbuf_addf(&buf, "%02x", i);
-               r = for_each_file_in_obj_subdir(i, &buf, obj_cb, cruft_cb,
+               strbuf_addf(path, "/%02x", i);
+               r = for_each_file_in_obj_subdir(i, path, obj_cb, cruft_cb,
                                                subdir_cb, data);
-               strbuf_setlen(&buf, baselen);
+               strbuf_setlen(path, baselen);
                if (r)
                        break;
        }
 
+       return r;
+}
+
+int for_each_loose_file_in_objdir(const char *path,
+                                 each_loose_object_fn obj_cb,
+                                 each_loose_cruft_fn cruft_cb,
+                                 each_loose_subdir_fn subdir_cb,
+                                 void *data)
+{
+       struct strbuf buf = STRBUF_INIT;
+       int r;
+
+       strbuf_addstr(&buf, path);
+       r = for_each_loose_file_in_objdir_buf(&buf, obj_cb, cruft_cb,
+                                             subdir_cb, data);
        strbuf_release(&buf);
+
        return r;
 }
 
@@ -3396,9 +3407,16 @@ static int loose_from_alt_odb(struct alternate_object_database *alt,
                              void *vdata)
 {
        struct loose_alt_odb_data *data = vdata;
-       return for_each_loose_file_in_objdir(alt->base,
-                                            data->cb, NULL, NULL,
-                                            data->data);
+       struct strbuf buf = STRBUF_INIT;
+       int r;
+
+       /* copy base not including trailing '/' */
+       strbuf_add(&buf, alt->base, alt->name - alt->base - 1);
+       r = for_each_loose_file_in_objdir_buf(&buf,
+                                             data->cb, NULL, NULL,
+                                             data->data);
+       strbuf_release(&buf);
+       return r;
 }
 
 int for_each_loose_object(each_loose_object_fn cb, void *data)
index cf2a83b14381ae02e737e6135561aab401f1f7e8..95f9f8fa1a72693757bbafe0f2a7773d8ae2de05 100644 (file)
@@ -1391,9 +1391,7 @@ static int get_sha1_with_context_1(const char *name,
                        namelen = strlen(cp);
                }
 
-               strncpy(oc->path, cp,
-                       sizeof(oc->path));
-               oc->path[sizeof(oc->path)-1] = '\0';
+               strlcpy(oc->path, cp, sizeof(oc->path));
 
                if (!active_cache)
                        read_cache();
@@ -1443,9 +1441,7 @@ static int get_sha1_with_context_1(const char *name,
                                                           name, len);
                        }
                        hashcpy(oc->tree, tree_sha1);
-                       strncpy(oc->path, filename,
-                               sizeof(oc->path));
-                       oc->path[sizeof(oc->path)-1] = '\0';
+                       strlcpy(oc->path, filename, sizeof(oc->path));
 
                        free(new_filename);
                        return ret;
index cdd07751461e69291588dee801c3563644cb1107..d8bf40ad4bed3bc846bb71945f1c2bfce76a202d 100644 (file)
--- a/shallow.c
+++ b/shallow.c
@@ -22,7 +22,7 @@ void set_alternate_shallow_file(const char *path, int override)
        if (alternate_shallow_file && !override)
                return;
        free(alternate_shallow_file);
-       alternate_shallow_file = path ? xstrdup(path) : NULL;
+       alternate_shallow_file = xstrdup_or_null(path);
 }
 
 int register_shallow(const unsigned char *sha1)
@@ -137,7 +137,7 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth,
        return result;
 }
 
-void check_shallow_file_for_update(void)
+static void check_shallow_file_for_update(void)
 {
        if (is_shallow == -1)
                die("BUG: shallow must be initialized by now");
index 652b6c432b325aaed29d7d374994a2a95d11a7c8..1883494ca3ad4931640c2a295c94800e287c1664 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
 #ifndef STRBUF_H
 #define STRBUF_H
 
-/* See Documentation/technical/api-strbuf.txt */
+/**
+ * strbuf's are meant to be used with all the usual C string and memory
+ * APIs. Given that the length of the buffer is known, it's often better to
+ * use the mem* functions than a str* one (memchr vs. strchr e.g.).
+ * Though, one has to be careful about the fact that str* functions often
+ * stop on NULs and that strbufs may have embedded NULs.
+ *
+ * A strbuf is NUL terminated for convenience, but no function in the
+ * strbuf API actually relies on the string being free of NULs.
+ *
+ * strbufs have some invariants that are very important to keep in mind:
+ *
+ *  - The `buf` member is never NULL, so it can be used in any usual C
+ *    string operations safely. strbuf's _have_ to be initialized either by
+ *    `strbuf_init()` or by `= STRBUF_INIT` before the invariants, though.
+ *
+ *    Do *not* assume anything on what `buf` really is (e.g. if it is
+ *    allocated memory or not), use `strbuf_detach()` to unwrap a memory
+ *    buffer from its strbuf shell in a safe way. That is the sole supported
+ *    way. This will give you a malloced buffer that you can later `free()`.
+ *
+ *    However, it is totally safe to modify anything in the string pointed by
+ *    the `buf` member, between the indices `0` and `len-1` (inclusive).
+ *
+ *  - The `buf` member is a byte array that has at least `len + 1` bytes
+ *    allocated. The extra byte is used to store a `'\0'`, allowing the
+ *    `buf` member to be a valid C-string. Every strbuf function ensure this
+ *    invariant is preserved.
+ *
+ *    NOTE: It is OK to "play" with the buffer directly if you work it this
+ *    way:
+ *
+ *        strbuf_grow(sb, SOME_SIZE); <1>
+ *        strbuf_setlen(sb, sb->len + SOME_OTHER_SIZE);
+ *
+ *    <1> Here, the memory array starting at `sb->buf`, and of length
+ *    `strbuf_avail(sb)` is all yours, and you can be sure that
+ *    `strbuf_avail(sb)` is at least `SOME_SIZE`.
+ *
+ *    NOTE: `SOME_OTHER_SIZE` must be smaller or equal to `strbuf_avail(sb)`.
+ *
+ *    Doing so is safe, though if it has to be done in many places, adding the
+ *    missing API to the strbuf module is the way to go.
+ *
+ *    WARNING: Do _not_ assume that the area that is yours is of size `alloc
+ *    - 1` even if it's true in the current implementation. Alloc is somehow a
+ *    "private" member that should not be messed with. Use `strbuf_avail()`
+ *    instead.
+*/
+
+/**
+ * Data Structures
+ * ---------------
+ */
 
-extern char strbuf_slopbuf[];
+/**
+ * This is the string buffer structure. The `len` member can be used to
+ * determine the current length of the string, and `buf` member provides
+ * access to the string itself.
+ */
 struct strbuf {
        size_t alloc;
        size_t len;
        char *buf;
 };
 
+extern char strbuf_slopbuf[];
 #define STRBUF_INIT  { 0, 0, strbuf_slopbuf }
 
-/*----- strbuf life cycle -----*/
+/**
+ * Life Cycle Functions
+ * --------------------
+ */
+
+/**
+ * Initialize the structure. The second parameter can be zero or a bigger
+ * number to allocate memory, in case you want to prevent further reallocs.
+ */
 extern void strbuf_init(struct strbuf *, size_t);
+
+/**
+ * Release a string buffer and the memory it used. You should not use the
+ * string buffer after using this function, unless you initialize it again.
+ */
 extern void strbuf_release(struct strbuf *);
+
+/**
+ * Detach the string from the strbuf and returns it; you now own the
+ * storage the string occupies and it is your responsibility from then on
+ * to release it with `free(3)` when you are done with it.
+ */
 extern char *strbuf_detach(struct strbuf *, size_t *);
+
+/**
+ * Attach a string to a buffer. You should specify the string to attach,
+ * the current length of the string and the amount of allocated memory.
+ * The amount must be larger than the string length, because the string you
+ * pass is supposed to be a NUL-terminated string.  This string _must_ be
+ * malloc()ed, and after attaching, the pointer cannot be relied upon
+ * anymore, and neither be free()d directly.
+ */
 extern void strbuf_attach(struct strbuf *, void *, size_t, size_t);
+
+/**
+ * Swap the contents of two string buffers.
+ */
 static inline void strbuf_swap(struct strbuf *a, struct strbuf *b)
 {
        struct strbuf tmp = *a;
@@ -24,14 +114,36 @@ static inline void strbuf_swap(struct strbuf *a, struct strbuf *b)
        *b = tmp;
 }
 
-/*----- strbuf size related -----*/
+
+/**
+ * Functions related to the size of the buffer
+ * -------------------------------------------
+ */
+
+/**
+ * Determine the amount of allocated but unused memory.
+ */
 static inline size_t strbuf_avail(const struct strbuf *sb)
 {
        return sb->alloc ? sb->alloc - sb->len - 1 : 0;
 }
 
+/**
+ * Ensure that at least this amount of unused memory is available after
+ * `len`. This is used when you know a typical size for what you will add
+ * and want to avoid repetitive automatic resizing of the underlying buffer.
+ * This is never a needed operation, but can be critical for performance in
+ * some cases.
+ */
 extern void strbuf_grow(struct strbuf *, size_t);
 
+/**
+ * Set the length of the buffer to a given value. This function does *not*
+ * allocate new memory, so you should not perform a `strbuf_setlen()` to a
+ * length that is larger than `len + strbuf_avail()`. `strbuf_setlen()` is
+ * just meant as a 'please fix invariants from this strbuf I just messed
+ * with'.
+ */
 static inline void strbuf_setlen(struct strbuf *sb, size_t len)
 {
        if (len > (sb->alloc ? sb->alloc - 1 : 0))
@@ -39,78 +151,58 @@ static inline void strbuf_setlen(struct strbuf *sb, size_t len)
        sb->len = len;
        sb->buf[len] = '\0';
 }
+
+/**
+ * Empty the buffer by setting the size of it to zero.
+ */
 #define strbuf_reset(sb)  strbuf_setlen(sb, 0)
 
-/*----- content related -----*/
+
+/**
+ * Functions related to the contents of the buffer
+ * -----------------------------------------------
+ */
+
+/**
+ * Strip whitespace from the beginning (`ltrim`), end (`rtrim`), or both side
+ * (`trim`) of a string.
+ */
 extern void strbuf_trim(struct strbuf *);
 extern void strbuf_rtrim(struct strbuf *);
 extern void strbuf_ltrim(struct strbuf *);
-extern int strbuf_reencode(struct strbuf *sb, const char *from, const char *to);
-extern void strbuf_tolower(struct strbuf *sb);
-extern int strbuf_cmp(const struct strbuf *, const struct strbuf *);
 
-static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)
-{
-       if (strip_suffix_mem(sb->buf, &sb->len, suffix)) {
-               strbuf_setlen(sb, sb->len);
-               return 1;
-       } else
-               return 0;
-}
-
-/*
- * Split str (of length slen) at the specified terminator character.
- * Return a null-terminated array of pointers to strbuf objects
- * holding the substrings.  The substrings include the terminator,
- * except for the last substring, which might be unterminated if the
- * original string did not end with a terminator.  If max is positive,
- * then split the string into at most max substrings (with the last
- * substring containing everything following the (max-1)th terminator
- * character).
- *
- * For lighter-weight alternatives, see string_list_split() and
- * string_list_split_in_place().
+/**
+ * Replace the contents of the strbuf with a reencoded form.  Returns -1
+ * on error, 0 on success.
  */
-extern struct strbuf **strbuf_split_buf(const char *, size_t,
-                                       int terminator, int max);
+extern int strbuf_reencode(struct strbuf *sb, const char *from, const char *to);
 
-/*
- * Split a NUL-terminated string at the specified terminator
- * character.  See strbuf_split_buf() for more information.
+/**
+ * Lowercase each character in the buffer using `tolower`.
  */
-static inline struct strbuf **strbuf_split_str(const char *str,
-                                              int terminator, int max)
-{
-       return strbuf_split_buf(str, strlen(str), terminator, max);
-}
+extern void strbuf_tolower(struct strbuf *sb);
 
-/*
- * Split a strbuf at the specified terminator character.  See
- * strbuf_split_buf() for more information.
+/**
+ * Compare two buffers. Returns an integer less than, equal to, or greater
+ * than zero if the first buffer is found, respectively, to be less than,
+ * to match, or be greater than the second buffer.
  */
-static inline struct strbuf **strbuf_split_max(const struct strbuf *sb,
-                                               int terminator, int max)
-{
-       return strbuf_split_buf(sb->buf, sb->len, terminator, max);
-}
+extern int strbuf_cmp(const struct strbuf *, const struct strbuf *);
 
-/*
- * Split a strbuf at the specified terminator character.  See
- * strbuf_split_buf() for more information.
- */
-static inline struct strbuf **strbuf_split(const struct strbuf *sb,
-                                          int terminator)
-{
-       return strbuf_split_max(sb, terminator, 0);
-}
 
-/*
- * Free a NULL-terminated list of strbufs (for example, the return
- * values of the strbuf_split*() functions).
+/**
+ * Adding data to the buffer
+ * -------------------------
+ *
+ * NOTE: All of the functions in this section will grow the buffer as
+ * necessary.  If they fail for some reason other than memory shortage and the
+ * buffer hadn't been allocated before (i.e. the `struct strbuf` was set to
+ * `STRBUF_INIT`), then they will free() it.
  */
-extern void strbuf_list_free(struct strbuf **);
 
-/*----- add data in your buffer -----*/
+/**
+ * Add a single character to the buffer.
+ */
 static inline void strbuf_addch(struct strbuf *sb, int c)
 {
        strbuf_grow(sb, 1);
@@ -118,47 +210,276 @@ static inline void strbuf_addch(struct strbuf *sb, int c)
        sb->buf[sb->len] = '\0';
 }
 
+/**
+ * Add a character the specified number of times to the buffer.
+ */
+extern void strbuf_addchars(struct strbuf *sb, int c, size_t n);
+
+/**
+ * Insert data to the given position of the buffer. The remaining contents
+ * will be shifted, not overwritten.
+ */
 extern void strbuf_insert(struct strbuf *, size_t pos, const void *, size_t);
+
+/**
+ * Remove given amount of data from a given position of the buffer.
+ */
 extern void strbuf_remove(struct strbuf *, size_t pos, size_t len);
 
-/* splice pos..pos+len with given data */
+/**
+ * Remove the bytes between `pos..pos+len` and replace it with the given
+ * data.
+ */
 extern void strbuf_splice(struct strbuf *, size_t pos, size_t len,
-                          const void *, size_t);
+                         const void *, size_t);
 
+/**
+ * Add a NUL-terminated string to the buffer. Each line will be prepended
+ * by a comment character and a blank.
+ */
 extern void strbuf_add_commented_lines(struct strbuf *out, const char *buf, size_t size);
 
+
+/**
+ * Add data of given length to the buffer.
+ */
 extern void strbuf_add(struct strbuf *, const void *, size_t);
+
+/**
+ * Add a NUL-terminated string to the buffer.
+ *
+ * NOTE: This function will *always* be implemented as an inline or a macro
+ * using strlen, meaning that this is efficient to write things like:
+ *
+ *     strbuf_addstr(sb, "immediate string");
+ *
+ */
 static inline void strbuf_addstr(struct strbuf *sb, const char *s)
 {
        strbuf_add(sb, s, strlen(s));
 }
+
+/**
+ * Copy the contents of another buffer at the end of the current one.
+ */
 static inline void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2)
 {
        strbuf_grow(sb, sb2->len);
        strbuf_add(sb, sb2->buf, sb2->len);
 }
+
+/**
+ * Copy part of the buffer from a given position till a given length to the
+ * end of the buffer.
+ */
 extern void strbuf_adddup(struct strbuf *sb, size_t pos, size_t len);
-extern void strbuf_addchars(struct strbuf *sb, int c, size_t n);
 
+/**
+ * This function can be used to expand a format string containing
+ * placeholders. To that end, it parses the string and calls the specified
+ * function for every percent sign found.
+ *
+ * The callback function is given a pointer to the character after the `%`
+ * and a pointer to the struct strbuf.  It is expected to add the expanded
+ * version of the placeholder to the strbuf, e.g. to add a newline
+ * character if the letter `n` appears after a `%`.  The function returns
+ * the length of the placeholder recognized and `strbuf_expand()` skips
+ * over it.
+ *
+ * The format `%%` is automatically expanded to a single `%` as a quoting
+ * mechanism; callers do not need to handle the `%` placeholder themselves,
+ * and the callback function will not be invoked for this placeholder.
+ *
+ * All other characters (non-percent and not skipped ones) are copied
+ * verbatim to the strbuf.  If the callback returned zero, meaning that the
+ * placeholder is unknown, then the percent sign is copied, too.
+ *
+ * In order to facilitate caching and to make it possible to give
+ * parameters to the callback, `strbuf_expand()` passes a context pointer,
+ * which can be used by the programmer of the callback as she sees fit.
+ */
 typedef size_t (*expand_fn_t) (struct strbuf *sb, const char *placeholder, void *context);
 extern void strbuf_expand(struct strbuf *sb, const char *format, expand_fn_t fn, void *context);
+
+/**
+ * Used as callback for `strbuf_expand()`, expects an array of
+ * struct strbuf_expand_dict_entry as context, i.e. pairs of
+ * placeholder and replacement string.  The array needs to be
+ * terminated by an entry with placeholder set to NULL.
+ */
 struct strbuf_expand_dict_entry {
        const char *placeholder;
        const char *value;
 };
 extern size_t strbuf_expand_dict_cb(struct strbuf *sb, const char *placeholder, void *context);
+
+/**
+ * Append the contents of one strbuf to another, quoting any
+ * percent signs ("%") into double-percents ("%%") in the
+ * destination. This is useful for literal data to be fed to either
+ * strbuf_expand or to the *printf family of functions.
+ */
 extern void strbuf_addbuf_percentquote(struct strbuf *dst, const struct strbuf *src);
 
+/**
+ * Append the given byte size as a human-readable string (i.e. 12.23 KiB,
+ * 3.50 MiB).
+ */
+extern void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes);
+
+/**
+ * Add a formatted string to the buffer.
+ */
 __attribute__((format (printf,2,3)))
 extern void strbuf_addf(struct strbuf *sb, const char *fmt, ...);
+
+/**
+ * Add a formatted string prepended by a comment character and a
+ * blank to the buffer.
+ */
 __attribute__((format (printf, 2, 3)))
 extern void strbuf_commented_addf(struct strbuf *sb, const char *fmt, ...);
+
 __attribute__((format (printf,2,0)))
 extern void strbuf_vaddf(struct strbuf *sb, const char *fmt, va_list ap);
 
+/**
+ * Read a given size of data from a FILE* pointer to the buffer.
+ *
+ * NOTE: The buffer is rewound if the read fails. If -1 is returned,
+ * `errno` must be consulted, like you would do for `read(3)`.
+ * `strbuf_read()`, `strbuf_read_file()` and `strbuf_getline()` has the
+ * same behaviour as well.
+ */
+extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
+
+/**
+ * Read the contents of a given file descriptor. The third argument can be
+ * used to give a hint about the file size, to avoid reallocs.  If read fails,
+ * any partial read is undone.
+ */
+extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint);
+
+/**
+ * Read the contents of a file, specified by its path. The third argument
+ * can be used to give a hint about the file size, to avoid reallocs.
+ */
+extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint);
+
+/**
+ * Read the target of a symbolic link, specified by its path.  The third
+ * argument can be used to give a hint about the size, to avoid reallocs.
+ */
+extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
+
+/**
+ * Read a line from a FILE *, overwriting the existing contents
+ * of the strbuf. The second argument specifies the line
+ * terminator character, typically `'\n'`.
+ * Reading stops after the terminator or at EOF.  The terminator
+ * is removed from the buffer before returning.  Returns 0 unless
+ * there was nothing left before EOF, in which case it returns `EOF`.
+ */
+extern int strbuf_getline(struct strbuf *, FILE *, int);
+
+/**
+ * Like `strbuf_getline`, but keeps the trailing terminator (if
+ * any) in the buffer.
+ */
+extern int strbuf_getwholeline(struct strbuf *, FILE *, int);
+
+/**
+ * Like `strbuf_getwholeline`, but operates on a file descriptor.
+ * It reads one character at a time, so it is very slow.  Do not
+ * use it unless you need the correct position in the file
+ * descriptor.
+ */
+extern int strbuf_getwholeline_fd(struct strbuf *, int, int);
+
+/**
+ * Set the buffer to the path of the current working directory.
+ */
+extern int strbuf_getcwd(struct strbuf *sb);
+
+/**
+ * Add a path to a buffer, converting a relative path to an
+ * absolute one in the process.  Symbolic links are not
+ * resolved.
+ */
+extern void strbuf_add_absolute_path(struct strbuf *sb, const char *path);
+
+/**
+ * Strip whitespace from a buffer. The second parameter controls if
+ * comments are considered contents to be removed or not.
+ */
+extern void stripspace(struct strbuf *buf, int skip_comments);
+
+static inline int strbuf_strip_suffix(struct strbuf *sb, const char *suffix)
+{
+       if (strip_suffix_mem(sb->buf, &sb->len, suffix)) {
+               strbuf_setlen(sb, sb->len);
+               return 1;
+       } else
+               return 0;
+}
+
+/**
+ * Split str (of length slen) at the specified terminator character.
+ * Return a null-terminated array of pointers to strbuf objects
+ * holding the substrings.  The substrings include the terminator,
+ * except for the last substring, which might be unterminated if the
+ * original string did not end with a terminator.  If max is positive,
+ * then split the string into at most max substrings (with the last
+ * substring containing everything following the (max-1)th terminator
+ * character).
+ *
+ * The most generic form is `strbuf_split_buf`, which takes an arbitrary
+ * pointer/len buffer. The `_str` variant takes a NUL-terminated string,
+ * the `_max` variant takes a strbuf, and just `strbuf_split` is a convenience
+ * wrapper to drop the `max` parameter.
+ *
+ * For lighter-weight alternatives, see string_list_split() and
+ * string_list_split_in_place().
+ */
+extern struct strbuf **strbuf_split_buf(const char *, size_t,
+                                       int terminator, int max);
+
+static inline struct strbuf **strbuf_split_str(const char *str,
+                                              int terminator, int max)
+{
+       return strbuf_split_buf(str, strlen(str), terminator, max);
+}
+
+static inline struct strbuf **strbuf_split_max(const struct strbuf *sb,
+                                               int terminator, int max)
+{
+       return strbuf_split_buf(sb->buf, sb->len, terminator, max);
+}
+
+static inline struct strbuf **strbuf_split(const struct strbuf *sb,
+                                          int terminator)
+{
+       return strbuf_split_max(sb, terminator, 0);
+}
+
+/**
+ * Free a NULL-terminated list of strbufs (for example, the return
+ * values of the strbuf_split*() functions).
+ */
+extern void strbuf_list_free(struct strbuf **);
+
+/**
+ * Launch the user preferred editor to edit a file and fill the buffer
+ * with the file's contents upon the user completing their editing. The
+ * third argument can be used to set the environment which the editor is
+ * run in. If the buffer is NULL the editor is launched as usual but the
+ * file's contents are not read into the buffer upon completion.
+ */
+extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);
+
 extern void strbuf_add_lines(struct strbuf *sb, const char *prefix, const char *buf, size_t size);
 
-/*
+/**
  * Append s to sb, with the characters '<', '>', '&' and '"' converted
  * into XML entities.
  */
@@ -170,28 +491,11 @@ static inline void strbuf_complete_line(struct strbuf *sb)
                strbuf_addch(sb, '\n');
 }
 
-extern size_t strbuf_fread(struct strbuf *, size_t, FILE *);
-/* XXX: if read fails, any partial read is undone */
-extern ssize_t strbuf_read(struct strbuf *, int fd, size_t hint);
-extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint);
-extern int strbuf_readlink(struct strbuf *sb, const char *path, size_t hint);
-extern int strbuf_getcwd(struct strbuf *sb);
-
-extern int strbuf_getwholeline(struct strbuf *, FILE *, int);
-extern int strbuf_getline(struct strbuf *, FILE *, int);
-extern int strbuf_getwholeline_fd(struct strbuf *, int, int);
-
-extern void stripspace(struct strbuf *buf, int skip_comments);
-extern int launch_editor(const char *path, struct strbuf *buffer, const char *const *env);
-
 extern int strbuf_branchname(struct strbuf *sb, const char *name);
 extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);
 
 extern void strbuf_addstr_urlencode(struct strbuf *, const char *,
                                    int reserved);
-extern void strbuf_humanise_bytes(struct strbuf *buf, off_t bytes);
-
-extern void strbuf_add_absolute_path(struct strbuf *sb, const char *path);
 
 __attribute__((format (printf,1,2)))
 extern int printf_ln(const char *fmt, ...);
@@ -200,7 +504,7 @@ extern int fprintf_ln(FILE *fp, const char *fmt, ...);
 
 char *xstrdup_tolower(const char *);
 
-/*
+/**
  * Create a newly allocated string using printf format. You can do this easily
  * with a strbuf, but this provides a shortcut to save a few lines.
  */
index 75a35fcd0699940aea51534b5fe954847bed7bb9..c211dc40eed98fc58c953d2e3b1f7ba752f98a02 100644 (file)
@@ -1,6 +1,6 @@
 :
 
-sanitize_diff_raw='/^:/s/ '"$_x40"' '"$_x40"' \([A-Z]\)[0-9]*  / X X \1#       /'
+sanitize_diff_raw='/^:/s/ '"\($_x40\)"' '"\($_x40\)"' \([A-Z]\)[0-9]*  / \1 \2 \3#     /'
 compare_diff_raw () {
     # When heuristics are improved, the score numbers would change.
     # Ignore them while comparing.
diff --git a/t/diff-lib/COPYING b/t/diff-lib/COPYING
new file mode 100644 (file)
index 0000000..6ff87c4
--- /dev/null
@@ -0,0 +1,361 @@
+
+ Note that the only valid version of the GPL as far as this project
+ is concerned is _this_ particular version of the license (ie v2, not
+ v2.2 or v3.x or whatever), unless explicitly otherwise stated.
+
+ HOWEVER, in order to allow a migration to GPLv3 if that seems like
+ a good idea, I also ask that people involved with the project make
+ their preferences known. In particular, if you trust me to make that
+ decision, you might note so in your copyright message, ie something
+ like
+
+       This file is licensed under the GPL v2, or a later version
+       at the discretion of Linus.
+
+  might avoid issues. But we can also just decide to synchronize and
+  contact all copyright holders on record if/when the occasion arises.
+
+                       Linus Torvalds
+
+----------------------------------------
+
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/t/diff-lib/README b/t/diff-lib/README
new file mode 100644 (file)
index 0000000..548142c
--- /dev/null
@@ -0,0 +1,46 @@
+////////////////////////////////////////////////////////////////
+
+       GIT - the stupid content tracker
+
+////////////////////////////////////////////////////////////////
+
+"git" can mean anything, depending on your mood.
+
+ - random three-letter combination that is pronounceable, and not
+   actually used by any common UNIX command.  The fact that it is a
+   mispronunciation of "get" may or may not be relevant.
+ - stupid. contemptible and despicable. simple. Take your pick from the
+   dictionary of slang.
+ - "global information tracker": you're in a good mood, and it actually
+   works for you. Angels sing, and a light suddenly fills the room.
+ - "goddamn idiotic truckload of sh*t": when it breaks
+
+Git is a fast, scalable, distributed revision control system with an
+unusually rich command set that provides both high-level operations
+and full access to internals.
+
+Git is an Open Source project covered by the GNU General Public License.
+It was originally written by Linus Torvalds with help of a group of
+hackers around the net. It is currently maintained by Junio C Hamano.
+
+Please read the file INSTALL for installation instructions.
+See Documentation/tutorial.txt to get started, then see
+Documentation/everyday.txt for a useful minimum set of commands,
+and "man git-commandname" for documentation of each command.
+CVS users may also want to read Documentation/cvs-migration.txt.
+
+Many Git online resources are accessible from http://git.or.cz/
+including full documentation and Git related tools.
+
+The user discussion and development of Git take place on the Git
+mailing list -- everyone is welcome to post bug reports, feature
+requests, comments and patches to git@vger.kernel.org. To subscribe
+to the list, send an email with just "subscribe git" in the body to
+majordomo@vger.kernel.org. The mailing list archives are available at
+http://marc.theaimsgroup.com/?l=git and other archival sites.
+
+The messages titled "A note from the maintainer", "What's in
+git.git (stable)" and "What's cooking in git.git (topics)" and
+the discussion following them on the mailing list give a good
+reference for project status, development direction and
+remaining tasks.
index d88da29f77d23fe2f3efc86a15daf198dddbeb69..db2ef22e8f76a54c851424dd19c1232f6061392c 100755 (executable)
@@ -23,6 +23,8 @@ else
                # To write armored exported key to keyring:
                #       gpg --homedir /tmp/gpghome --export-secret-keys \
                #               --armor 0xDEADBEEF >> lib-gpg/keyring.gpg
+               #       gpg --homedir /tmp/gpghome --export \
+               #               --armor 0xDEADBEEF >> lib-gpg/keyring.gpg
                # To export ownertrust:
                #       gpg --homedir /tmp/gpghome --export-ownertrust \
                #               > lib-gpg/ownertrust
@@ -34,6 +36,8 @@ else
                        "$TEST_DIRECTORY"/lib-gpg/keyring.gpg &&
                gpg --homedir "${GNUPGHOME}" 2>/dev/null --import-ownertrust \
                        "$TEST_DIRECTORY"/lib-gpg/ownertrust &&
+               gpg --homedir "${GNUPGHOME}" </dev/null >/dev/null 2>&1 \
+                       --sign -u committer@example.com &&
                test_set_prereq GPG
                ;;
        esac
index fb1f048c22fc9bdc32c27ac931f149c65f89ed24..d4754a1f19c7984b3286cfd9dfa9740a790800e0 100644 (file)
@@ -86,3 +86,57 @@ Z9Ei+zj6JD5Pcdi3BJhQo9WOLOVEJ0NHmewTYqk9QVXH/0v1Hdl4LMJtgcbdbDWk
 BOW78WUxzhu0YJTLKy+iKCjg5HS5dx6OC+e4aEEgfhNPCMkbvDsJjtQ=
 =hieJ
 -----END PGP PRIVATE KEY BLOCK-----
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1
+
+mQGiBEZnyykRBACzCPjIpTYNL7Y2tQqlEGTTDlvZcWNLjF5f7ZzuyOqNOidLUgFD
+36qch1LZLSZkShdR3Gae+bsolyjxrlFuFP0eXRPMtqK20aLw7WZvPFpEV1ThMne+
+PRJjYrvghWw3L0VVIAIZ8GXwrVBuU99uEjHEI0ojYloOvFc2jVPgSaoBvwCg48Tj
+fol2foSoJa7XUu9yAL8szg8D/RUsTzNF+I9hSRHl7MYKFMYoKEY9BDgrgAujp7YY
+8qdGsiUb0Ggyzp2kRjZFt4lpcvKhGfHn5GEjmtk+fRbD5qPfMqKFW+T0NPfYlYmL
+JJ4fs4qZ8Lx7x6iG6X51u+YNwsQuIGjMCC3CeNi3F7or651kkNYASbaQ1NROkCIN
+NudyA/0aasvoZUoNJAc2cP5Ifs6WhXMWLfMR2p2XbfKwKNYneec60usnSComcKqh
+sJVk0Gytvr3FOYVhRkXnKAbx+0W2urFP8OFVBTEKO6Ts2VygWGgneQYoHnqzwlUE
+yjOjlr+lyf7u2s/KAxpKA6jnttEdRZAmzWkhuox1wwAUkr27/bQiQyBPIE1pdHRl
+ciA8Y29tbWl0dGVyQGV4YW1wbGUuY29tPoheBBMRAgAeBQJGZ8spAhsDBgsJCAcD
+AgMVAgMDFgIBAh4BAheAAAoJEBO29R7N3kMNdB0AoL3Z/7A6tORuY8R/676oD8a/
+oHFDAJ9DXbwlcKLcykwHy0jYqajXm1iCebkCDQRGZ8tOEAgAzrl5P1Pr6CDR8mf5
+DGGzcUUM+PEroA4FLdKJ5ZaZc7qy1lmmW9vuvb6xdinwcwee2c5fdNE+iUjHV2x2
+S/dbfDzJTN/0uajZcw+xnf+KxZ0Rs4gDSs7cHXHBtA7u8ShYd4Hu7JggXpiwgfSk
+yrGQiZyLAHW2ck8H07Go8eUP8fLIeva+iPqeYQZo9BaPz92R/J6debpeY1lRkv+y
+WTq1GE3C/hxbdBAuHf2duLP2uq9kwoVdfzCRjgV1CQmMIbCrMb7vIlzIe96bb3+K
+r/+NEtmB2I3wHBXcwJMnIOnz9Zv933KNlxSbVF23BGLB+F9D7OanKymbs7Eg18fr
+mt/t/wAEDQgAtGIxGz944Pn2OtheY9JlBRuIAuVskm24/Zz03dZnk6CuEOIBb5IM
+g36GAPKcn1vsLZ0TfE1q53jNpcAAXjgngnRsCjZm1mglqPD4ZfBpl+Hhnuc80fAR
+xsUPj+5c8KP2M+Rws4moaZRjVpd3KCi3ceflT/OjwnE9DzdhslCGTMA5n8cajAs2
+oqAaQssefVf2prLQLGV9NB4Q3lFnKXdvipHMaAYAsW+iF7JkhTDVNuNGlufeSqUm
+igRBjTZXBcVd8sj8vDOCWKUfqxJyS+zRYcotn7QvpvcKAkc3ZGxntDHAIGLVp6ay
++vrkV4Ren8BjFobl25Ruy6Abw+CgnTpuwYhJBBgRAgAJBQJGZ8tOAhsMAAoJEBO2
+9R7N3kMNwewAoNBygC0NYkW6lVGqV4EJ7PHhDaSEAJwKz78u0Twtv2EL7Zy+ve4f
+mnzYApkBDQRRTJZHAQgAyYv8ZwBfMiN+Dx4pUgmzO1bThTte6BTJKbuHIDdkKT7j
+OTFY8nL68ykoLmRbzwgy83gBSVtbj8S+Eh2h0pIrAqxYYox+ziVnDjzT0hQsLvop
+wKALLx5uJ7OqXw2ckY1Ux0mOK3TCEqihUaM2l7vLx3gUcyIRZ7mwQnqSmVtO6Cj5
+65xC1U1VElFSPunpfCRZiSFscSzS4X0UUjxdL+DA1zxf/4glomQyPidaS70OVf3+
+2LX7AxldKD2Ouie9gRSRueeXigbbZzWPdNS5iN6HJ+T+YlZ1w2qjBJcOxSqZwDV7
+nIGNx+JC8jZCN7NydAhm1yO29zAVrY3LboVr9athuQARAQABtCRFcmlzIERpc2Nv
+cmRpYSA8ZGlzY29yZEBleGFtcGxlLm5ldD6JATgEEwECACIFAlFMlkcCGwMGCwkI
+BwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEGEJLoW3InGJWKMH+wfn/hQ3C1X8PF8x
+pSpLtRejyNchgrewDDtvyZJjuC5YB7iIBaanuW/14ypdCLEXG1S4raoiKJHPLvux
+/MmFOuww5Yqu7dYKgcvqk4Uh3IJ+ljCk2qgqjhNo8x8qrpSAM0LCUPnOUkaHxGQC
+k+EGtg8vp7Klg6SBO/GiXdFZ5JPVOh9lbgAb1HjfyDIL8T6+duaPqwQ+y1OCdwrT
+s31frDuvt93WvgZvVIZEeLQuB/59XQzdSWLsQUG4MU6v4fJinuP+/2L8vuVrGHfe
+mUSxNmRVnll7SpMJmG0ONht0mVF2mfEfDrW08lK42xSoqTuML18Ico7tZfXMQLK3
+GusW0gi5AQ0EUUyWRwEIAKk7TxXE16jPlKO2zqKPnXB4vFw3//F0hJmXzCnP1OaU
+kwZO4dYEirhs4xdp98EJugPPtdNb0y2kOj6BQxVvLkAdNJo8phq0Q2BYM/G44Z2n
+pGZwOF04a9UTo334DIbN7k6Qnm3VfpS/CtKCUx3N/Uzy04NtwxXEUgzftwESSUu/
+gkQSG7fS+YDm6YAOB1Gqf6OjeztOK0Dj1PNzAKp8KNiUzvw3ndM6GndFaN9TZpOB
+firxBOdn7Rh23e8qiFBigbdknkwIfOdGnC3jWT/ldWO2rQQq+/85viaR1qvTh+/z
+aJpRCJMS/Fg7fBnwCqKmYKnny/gAhJy2wLdXbt39BbMAEQEAAYkBHwQYAQIACQUC
+UUyWRwIbDAAKCRBhCS6FtyJxiexxCADF5DH+HDlppwLr73EptyqS4IblopPXcn59
+bGPyBuWraCivsqZlf05QZTGahUM7jyCUE/FS25sbS5Q4SRtOC2yOnPGsSGcTjmSi
+8uZ000stes7ahHku3onxyz2YNVBRchBCENV1tAjQwHrliofdBEY8peAoOz51kmfR
+Ivs4+iQ+T3HYtwSYUKPVjizlRCdDR5nsE2KpPUFVx/9L9R3ZeCzCbYHG3Ww1pOFE
+5F24PaZ97pgoJDSd1bPH1pyFjvSM3a9v8KxWNib1E+2L5fsLDSFmrbzhMxsu5wTl
+u/FlMc4btGCUyysvoigo4OR0uXcejgvnuGhBIH4TTwjJG7w7CY7U
+=iYv/
+-----END PGP PUBLIC KEY BLOCK-----
index fd53b5718780e25f03924e38438706acc54598db..d154d1ed1dd8f3449ad21e0aeefdce7d3120e1fb 100644 (file)
@@ -37,7 +37,7 @@ then
        test_done
 fi
 
-if ! test_have_prereq SANITY; then
+if ! test_have_prereq NOT_ROOT; then
        test_skip_or_die $GIT_TEST_HTTPD \
                "Cannot run httpd tests as root"
 fi
index 51845491bb42ee72a1f7ec33c504e65c5bf8b248..cd220e378e201fc5bfbaf9c78b0a3183ebf12d11 100644 (file)
@@ -1,7 +1,7 @@
 # Helpers for terminal output tests.
 
 # Catch tests which should depend on TTY but forgot to. There's no need
-# to aditionally check that the TTY prereq is set here.  If the test declared
+# to additionally check that the TTY prereq is set here.  If the test declared
 # it and we are running the test, then it must have been set.
 test_terminal () {
        if ! test_declared_prereq TTY
index 17e969df609f71b0b4562cff8fda112632d27442..9acf628726fe0c648279fb724f1917435db206f7 100755 (executable)
@@ -34,7 +34,7 @@ test_expect_success POSIXPERM 'run_command reports EACCES' '
        grep "fatal: cannot exec.*hello.sh" err
 '
 
-test_expect_success POSIXPERM 'unreadable directory in PATH' '
+test_expect_success POSIXPERM,SANITY 'unreadable directory in PATH' '
        mkdir local-command &&
        test_when_finished "chmod u+rwx local-command && rm -fr local-command" &&
        git config alias.nitfol "!echo frotz" &&
index fdc257e66fdc121b9f125466bf38431e3233dd19..3c6791e6be705bc823ff180cd481fef3dc939734 100755 (executable)
@@ -67,4 +67,13 @@ test_expect_success 'parse errors in blobs are properly attributed' '
        grep "HEAD:config" err
 '
 
+test_expect_success 'can parse blob ending with CR' '
+       printf "[some]key = value\\r" >config &&
+       git add config &&
+       git commit -m CR &&
+       echo value >expect &&
+       git config --blob=HEAD:config some.key >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 335420fd87f87727f323156f461e520374b7da0b..b6977d4b390ec9a3f4f3b621db88908a2c40f689 100755 (executable)
@@ -98,8 +98,16 @@ test_foobar_foobar() {
        '
 }
 
-if ! test_have_prereq POSIXPERM || ! [ -w / ]; then
-       skip_all="Dangerous test skipped. Read this test if you want to execute it"
+if ! test -w /
+then
+       skip_all="Test requiring writable / skipped. Read this test if you want to run it"
+       test_done
+fi
+
+if  test -e /refs || test -e /objects || test -e /info || test -e /hooks ||
+    test -e /.git || test -e /foo || test -e /me
+then
+       skip_all="Skip test that clobbers existing files in /"
        test_done
 fi
 
@@ -108,8 +116,9 @@ if [ "$IKNOWWHATIAMDOING" != "YES" ]; then
        test_done
 fi
 
-if [ "$UID" = 0 ]; then
-       skip_all="No you can't run this with root"
+if ! test_have_prereq NOT_ROOT
+then
+       skip_all="No you can't run this as root"
        test_done
 fi
 
index 8197ed29a9ecedb43679200f1485a7b50984fdff..a31f7e0430e107c1fbe036ce412d4466fa5bd2c2 100755 (executable)
@@ -1039,4 +1039,11 @@ test_expect_success 'short SHA-1 collide' '
        )
 '
 
+test_expect_success 'respect core.abbrev' '
+       git config core.abbrev 12 &&
+       set_cat_todo_editor &&
+       test_must_fail git rebase -i HEAD~4 >todo-list &&
+       test 4 = $(grep -c "pick [0-9a-f]\{12,\}" todo-list)
+'
+
 test_done
index bfa88356382ab9f37e6e510516bf1fc6a3811961..df2accb6555d4202c789b8ffb13ae3943268586d 100755 (executable)
@@ -11,7 +11,7 @@ test_description='More rename detection
 
 test_expect_success \
     'prepare reference tree' \
-    'cat "$TEST_DIRECTORY"/../COPYING >COPYING &&
+    'cat "$TEST_DIRECTORY"/diff-lib/COPYING >COPYING &&
      echo frotz >rezrov &&
     git update-index --add COPYING rezrov &&
     tree=$(git write-tree) &&
@@ -99,7 +99,7 @@ test_expect_success \
 
 test_expect_success \
     'prepare work tree once again' \
-    'cat "$TEST_DIRECTORY"/../COPYING >COPYING &&
+    'cat "$TEST_DIRECTORY"/diff-lib/COPYING >COPYING &&
      git update-index --add --remove COPYING COPYING.1'
 
 # tree has COPYING and rezrov.  work tree has COPYING and COPYING.1,
index 7d2c6e13a2a7f5d8e9e863d83e6b7b716810c970..135addbfbdae8e39ba0462e71278f41dfc552620 100755 (executable)
@@ -11,7 +11,7 @@ test_description='Same rename detection as t4003 but testing diff-raw.
 
 test_expect_success \
     'prepare reference tree' \
-    'cat "$TEST_DIRECTORY"/../COPYING >COPYING &&
+    'cat "$TEST_DIRECTORY"/diff-lib/COPYING >COPYING &&
      echo frotz >rezrov &&
     git update-index --add COPYING rezrov &&
     tree=$(git write-tree) &&
@@ -71,7 +71,7 @@ test_expect_success \
 
 test_expect_success \
     'prepare work tree once again' \
-    'cat "$TEST_DIRECTORY"/../COPYING >COPYING &&
+    'cat "$TEST_DIRECTORY"/diff-lib/COPYING >COPYING &&
      git update-index --add --remove COPYING COPYING.1'
 
 git diff-index -C --find-copies-harder $tree >current
index 11502b750997aba0ecfb6aa5b07c9aad1c45d592..dae327fabbfe390a3dc707ef2ebc665c9c6e3cb3 100755 (executable)
@@ -11,7 +11,7 @@ test_description='Rename interaction with pathspec.
 
 test_expect_success 'prepare reference tree' '
        mkdir path0 path1 &&
-       cp "$TEST_DIRECTORY"/../COPYING path0/COPYING &&
+       cp "$TEST_DIRECTORY"/diff-lib/COPYING path0/COPYING &&
        git update-index --add path0/COPYING &&
        tree=$(git write-tree) &&
        echo $tree
index 89204648965b2b6b7d7984e3398b3ef21a8d7c7e..9dd1bc5e162bb0b8821337a1e43cd8ad85423507 100755 (executable)
@@ -10,179 +10,145 @@ We have two very different files, file0 and file1, registered in a tree.
 We update file1 so drastically that it is more similar to file0, and
 then remove file0.  With -B, changes to file1 should be broken into
 separate delete and create, resulting in removal of file0, removal of
-original file1 and creation of completely rewritten file1.
+original file1 and creation of completely rewritten file1.  The latter
+two are then merged back into a single "complete rewrite".
 
 Further, with -B and -M together, these three modifications should
 turn into rename-edit of file0 into file1.
 
 Starting from the same two files in the tree, we swap file0 and file1.
-With -B, this should be detected as two complete rewrites, resulting in
-four changes in total.
+With -B, this should be detected as two complete rewrites.
 
 Further, with -B and -M together, these should turn into two renames.
 '
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/diff-lib.sh ;# test-lib chdir's into trash
 
-test_expect_success \
-    setup \
-    'cat "$TEST_DIRECTORY"/../README >file0 &&
-     cat "$TEST_DIRECTORY"/../COPYING >file1 &&
-    git update-index --add file0 file1 &&
-    tree=$(git write-tree) &&
-    echo "$tree"'
-
-test_expect_success \
-    'change file1 with copy-edit of file0 and remove file0' \
-    'sed -e "s/git/GIT/" file0 >file1 &&
-     rm -f file0 &&
-    git update-index --remove file0 file1'
-
-test_expect_success \
-    'run diff with -B' \
-    'git diff-index -B --cached "$tree" >current'
-
-cat >expected <<\EOF
-:100644 000000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 0000000000000000000000000000000000000000 D     file0
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 11e331465a89c394dc25c780de230043750c1ec8 M100  file1
-EOF
-
-test_expect_success \
-    'validate result of -B (#1)' \
-    'compare_diff_raw expected current'
-
-test_expect_success \
-    'run diff with -B and -M' \
-    'git diff-index -B -M "$tree" >current'
-
-cat >expected <<\EOF
-:100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 08bb2fb671deff4c03a4d4a0a1315dff98d5732c R100  file0   file1
-EOF
-
-test_expect_success \
-    'validate result of -B -M (#2)' \
-    'compare_diff_raw expected current'
-
-test_expect_success \
-    'swap file0 and file1' \
-    'rm -f file0 file1 &&
-     git read-tree -m $tree &&
-     git checkout-index -f -u -a &&
-     mv file0 tmp &&
-     mv file1 file0 &&
-     mv tmp file1 &&
-     git update-index file0 file1'
-
-test_expect_success \
-    'run diff with -B' \
-    'git diff-index -B "$tree" >current'
-
-cat >expected <<\EOF
-:100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 6ff87c4664981e4397625791c8ea3bbb5f2279a3 M100  file0
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 M100  file1
-EOF
-
-test_expect_success \
-    'validate result of -B (#3)' \
-    'compare_diff_raw expected current'
-
-test_expect_success \
-    'run diff with -B and -M' \
-    'git diff-index -B -M "$tree" >current'
-
-cat >expected <<\EOF
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 6ff87c4664981e4397625791c8ea3bbb5f2279a3 R100  file1   file0
-:100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 R100  file0   file1
-EOF
-
-test_expect_success \
-    'validate result of -B -M (#4)' \
-    'compare_diff_raw expected current'
-
-test_expect_success \
-    'make file0 into something completely different' \
-    'rm -f file0 &&
-     test_ln_s_add frotz file0 &&
-     git update-index file1'
-
-test_expect_success \
-    'run diff with -B' \
-    'git diff-index -B "$tree" >current'
-
-cat >expected <<\EOF
-:100644 120000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 67be421f88824578857624f7b3dc75e99a8a1481 T     file0
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 M100  file1
-EOF
-
-test_expect_success \
-    'validate result of -B (#5)' \
-    'compare_diff_raw expected current'
-
-test_expect_success \
-    'run diff with -B -M' \
-    'git diff-index -B -M "$tree" >current'
-
-# file0 changed from regular to symlink.  file1 is very close to the preimage of file0.
-# 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 C     file0   file1
-EOF
-
-test_expect_success \
-    'validate result of -B -M (#6)' \
-    'compare_diff_raw expected current'
-
-test_expect_success \
-    'run diff with -M' \
-    'git diff-index -M "$tree" >current'
-
-# This should not mistake file0 as the copy source of new file1
-# due to type differences.
-cat >expected <<\EOF
-:100644 120000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 67be421f88824578857624f7b3dc75e99a8a1481 T     file0
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 M     file1
-EOF
-
-test_expect_success \
-    'validate result of -M (#7)' \
-    'compare_diff_raw expected current'
-
-test_expect_success \
-    'file1 edited to look like file0 and file0 rename-edited to file2' \
-    'rm -f file0 file1 &&
-     git read-tree -m $tree &&
-     git checkout-index -f -u -a &&
-     sed -e "s/git/GIT/" file0 >file1 &&
-     sed -e "s/git/GET/" file0 >file2 &&
-     rm -f file0 &&
-     git update-index --add --remove file0 file1 file2'
-
-test_expect_success \
-    'run diff with -B' \
-    'git diff-index -B "$tree" >current'
-
-cat >expected <<\EOF
-:100644 000000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 0000000000000000000000000000000000000000 D     file0
-:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 08bb2fb671deff4c03a4d4a0a1315dff98d5732c M100  file1
-:000000 100644 0000000000000000000000000000000000000000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 A     file2
-EOF
-
-test_expect_success \
-    'validate result of -B (#8)' \
-    'compare_diff_raw expected current'
-
-test_expect_success \
-    'run diff with -B -C' \
-    'git diff-index -B -C "$tree" >current'
-
-cat >expected <<\EOF
-:100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 08bb2fb671deff4c03a4d4a0a1315dff98d5732c C095  file0   file1
-:100644 100644 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 59f832e5c8b3f7e486be15ad0cd3e95ba9af8998 R095  file0   file2
-EOF
-
-test_expect_success \
-    'validate result of -B -M (#9)' \
-    'compare_diff_raw expected current'
+test_expect_success setup '
+       cat "$TEST_DIRECTORY"/diff-lib/README >file0 &&
+       cat "$TEST_DIRECTORY"/diff-lib/COPYING >file1 &&
+       git update-index --add file0 file1 &&
+       git tag reference $(git write-tree)
+'
+
+test_expect_success 'change file1 with copy-edit of file0 and remove file0' '
+       sed -e "s/git/GIT/" file0 >file1 &&
+       rm -f file0 &&
+       git update-index --remove file0 file1
+'
+
+test_expect_success 'run diff with -B (#1)' '
+       git diff-index -B --cached reference >current &&
+       cat >expect <<-\EOF &&
+       :100644 000000 548142c327a6790ff8821d67c2ee1eff7a656b52 0000000000000000000000000000000000000000 D      file0
+       :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 2fbedd0b5d4b8126e4750c3bee305e8ff79f80ec M100   file1
+       EOF
+       compare_diff_raw expect current
+'
+
+test_expect_success 'run diff with -B and -M (#2)' '
+       git diff-index -B -M reference >current &&
+       cat >expect <<-\EOF &&
+       :100644 100644 548142c327a6790ff8821d67c2ee1eff7a656b52 2fbedd0b5d4b8126e4750c3bee305e8ff79f80ec R100   file0   file1
+       EOF
+       compare_diff_raw expect current
+'
+
+test_expect_success 'swap file0 and file1' '
+       rm -f file0 file1 &&
+       git read-tree -m reference &&
+       git checkout-index -f -u -a &&
+       mv file0 tmp &&
+       mv file1 file0 &&
+       mv tmp file1 &&
+       git update-index file0 file1
+'
+
+test_expect_success 'run diff with -B (#3)' '
+       git diff-index -B reference >current &&
+       cat >expect <<-\EOF &&
+       :100644 100644 548142c327a6790ff8821d67c2ee1eff7a656b52 6ff87c4664981e4397625791c8ea3bbb5f2279a3 M100   file0
+       :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 548142c327a6790ff8821d67c2ee1eff7a656b52 M100   file1
+       EOF
+       compare_diff_raw expect current
+'
+
+test_expect_success 'run diff with -B and -M (#4)' '
+       git diff-index -B -M reference >current &&
+       cat >expect <<-\EOF &&
+       :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 6ff87c4664981e4397625791c8ea3bbb5f2279a3 R100   file1   file0
+       :100644 100644 548142c327a6790ff8821d67c2ee1eff7a656b52 548142c327a6790ff8821d67c2ee1eff7a656b52 R100   file0   file1
+       EOF
+       compare_diff_raw expect current
+'
+
+test_expect_success 'make file0 into something completely different' '
+       rm -f file0 &&
+       test_ln_s_add frotz file0 &&
+       git update-index file1
+'
+
+test_expect_success 'run diff with -B (#5)' '
+       git diff-index -B reference >current &&
+       cat >expect <<-\EOF &&
+       :100644 120000 548142c327a6790ff8821d67c2ee1eff7a656b52 67be421f88824578857624f7b3dc75e99a8a1481 T      file0
+       :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 548142c327a6790ff8821d67c2ee1eff7a656b52 M100   file1
+       EOF
+       compare_diff_raw expect current
+'
+
+test_expect_success 'run diff with -B -M (#6)' '
+       git diff-index -B -M reference >current &&
+
+       # file0 changed from regular to symlink.  file1 is the same as the preimage
+       # of file0.  Because the change does not make file0 disappear, file1 is
+       # denoted as a copy of file0
+       cat >expect <<-\EOF &&
+       :100644 120000 548142c327a6790ff8821d67c2ee1eff7a656b52 67be421f88824578857624f7b3dc75e99a8a1481 T      file0
+       :100644 100644 548142c327a6790ff8821d67c2ee1eff7a656b52 548142c327a6790ff8821d67c2ee1eff7a656b52 C      file0   file1
+       EOF
+       compare_diff_raw expect current
+'
+
+test_expect_success 'run diff with -M (#7)' '
+       git diff-index -M reference >current &&
+
+       # This should not mistake file0 as the copy source of new file1
+       # due to type differences.
+       cat >expect <<-\EOF &&
+       :100644 120000 548142c327a6790ff8821d67c2ee1eff7a656b52 67be421f88824578857624f7b3dc75e99a8a1481 T      file0
+       :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 548142c327a6790ff8821d67c2ee1eff7a656b52 M      file1
+       EOF
+       compare_diff_raw expect current
+'
+
+test_expect_success 'file1 edited to look like file0 and file0 rename-edited to file2' '
+       rm -f file0 file1 &&
+       git read-tree -m reference &&
+       git checkout-index -f -u -a &&
+       sed -e "s/git/GIT/" file0 >file1 &&
+       sed -e "s/git/GET/" file0 >file2 &&
+       rm -f file0 &&
+       git update-index --add --remove file0 file1 file2
+'
+
+test_expect_success 'run diff with -B (#8)' '
+       git diff-index -B reference >current &&
+       cat >expect <<-\EOF &&
+       :100644 000000 548142c327a6790ff8821d67c2ee1eff7a656b52 0000000000000000000000000000000000000000 D      file0
+       :100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 2fbedd0b5d4b8126e4750c3bee305e8ff79f80ec M100   file1
+       :000000 100644 0000000000000000000000000000000000000000 69a939f651686f56322566e2fd76715947a24162 A      file2
+       EOF
+       compare_diff_raw expect current
+'
+
+test_expect_success 'run diff with -B -C (#9)' '
+       git diff-index -B -C reference >current &&
+       cat >expect <<-\EOF &&
+       :100644 100644 548142c327a6790ff8821d67c2ee1eff7a656b52 2fbedd0b5d4b8126e4750c3bee305e8ff79f80ec C095   file0   file1
+       :100644 100644 548142c327a6790ff8821d67c2ee1eff7a656b52 69a939f651686f56322566e2fd76715947a24162 R095   file0   file2
+       EOF
+       compare_diff_raw expect current
+'
 
 test_done
index 57c094fdcea160a7816680d66efac9c05dd57cc8..3641fd84d68612786ab55beb780209c89311e105 100755 (executable)
@@ -11,7 +11,7 @@ test_description='Same rename detection as t4003 but testing diff-raw -z.
 
 test_expect_success \
     'prepare reference tree' \
-    'cat "$TEST_DIRECTORY"/../COPYING >COPYING &&
+    'cat "$TEST_DIRECTORY"/diff-lib/COPYING >COPYING &&
      echo frotz >rezrov &&
     git update-index --add COPYING rezrov &&
     tree=$(git write-tree) &&
@@ -78,7 +78,7 @@ test_expect_success \
 
 test_expect_success \
     'prepare work tree once again' \
-    'cat "$TEST_DIRECTORY"/../COPYING >COPYING &&
+    'cat "$TEST_DIRECTORY"/diff-lib/COPYING >COPYING &&
      git update-index --add --remove COPYING COPYING.1'
 
 git diff-index -z -C --find-copies-harder $tree >current
index bf078418662c4bab4e512be8fc22a5aa76466119..43c488b545e6acc02bab9d496e33c37b99f49c7a 100755 (executable)
@@ -56,7 +56,7 @@ test_expect_success \
      compare_diff_raw current expected'
 
 cat >expected <<\EOF
-:100644 100644 766498d93a4b06057a8e49d23f4068f1170ff38f 0a41e115ab61be0328a19b29f18cdcb49338d516 M     file0
+:100644 100644 8e4020bb5a8d8c873b25de15933e75cc0fc275df dca6b92303befc93086aa025d90a5facd7eb2812 M     file0
 EOF
 test_expect_success \
     'limit to file0 should show file0' \
index ed7e093366bcbdaa177bac4294a07fc52d4233ed..0d50dce97e86a26bac7c798f020a1807936cc3c3 100755 (executable)
@@ -973,4 +973,18 @@ test_expect_success 'diff.dirstat=future_param,0,lines should warn, but still wo
        test_i18ngrep -q "diff\\.dirstat" actual_error
 '
 
+test_expect_success '--shortstat --dirstat should output only one dirstat' '
+       git diff --shortstat --dirstat=changes HEAD^..HEAD >out &&
+       grep " dst/copy/changed/$" out >actual_diff_shortstat_dirstat_changes &&
+       test_line_count = 1 actual_diff_shortstat_dirstat_changes &&
+
+       git diff --shortstat --dirstat=lines HEAD^..HEAD >out &&
+       grep " dst/copy/changed/$" out >actual_diff_shortstat_dirstat_lines &&
+       test_line_count = 1 actual_diff_shortstat_dirstat_lines &&
+
+       git diff --shortstat --dirstat=files HEAD^..HEAD >out &&
+       grep " dst/copy/changed/$" out >actual_diff_shortstat_dirstat_files &&
+       test_line_count = 1 actual_diff_shortstat_dirstat_files
+'
+
 test_done
diff --git a/t/t4058-diff-duplicates.sh b/t/t4058-diff-duplicates.sh
new file mode 100755 (executable)
index 0000000..0a23242
--- /dev/null
@@ -0,0 +1,79 @@
+#!/bin/sh
+
+test_description='test tree diff when trees have duplicate entries'
+. ./test-lib.sh
+
+# make_tree_entry <mode> <mode> <sha1>
+#
+# We have to rely on perl here because not all printfs understand
+# hex escapes (only octal), and xxd is not portable.
+make_tree_entry () {
+       printf '%s %s\0' "$1" "$2" &&
+       perl -e 'print chr(hex($_)) for ($ARGV[0] =~ /../g)' "$3"
+}
+
+# Like git-mktree, but without all of the pesky sanity checking.
+# Arguments come in groups of three, each group specifying a single
+# tree entry (see make_tree_entry above).
+make_tree () {
+       while test $# -gt 2; do
+               make_tree_entry "$1" "$2" "$3"
+               shift; shift; shift
+       done |
+       git hash-object -w -t tree --stdin
+}
+
+# this is kind of a convoluted setup, but matches
+# a real-world case. Each tree contains four entries
+# for the given path, one with one sha1, and three with
+# the other. The first tree has them split across
+# two subtrees (which are themselves duplicate entries in
+# the root tree), and the second has them all in a single subtree.
+test_expect_success 'create trees with duplicate entries' '
+       blob_one=$(echo one | git hash-object -w --stdin) &&
+       blob_two=$(echo two | git hash-object -w --stdin) &&
+       inner_one_a=$(make_tree \
+               100644 inner $blob_one
+       ) &&
+       inner_one_b=$(make_tree \
+               100644 inner $blob_two \
+               100644 inner $blob_two \
+               100644 inner $blob_two
+       ) &&
+       outer_one=$(make_tree \
+               040000 outer $inner_one_a \
+               040000 outer $inner_one_b
+       ) &&
+       inner_two=$(make_tree \
+               100644 inner $blob_one \
+               100644 inner $blob_two \
+               100644 inner $blob_two \
+               100644 inner $blob_two
+       ) &&
+       outer_two=$(make_tree \
+               040000 outer $inner_two
+       ) &&
+       git tag one $outer_one &&
+       git tag two $outer_two
+'
+
+test_expect_success 'diff-tree between trees' '
+       {
+               printf ":000000 100644 $_z40 $blob_two A\touter/inner\n" &&
+               printf ":000000 100644 $_z40 $blob_two A\touter/inner\n" &&
+               printf ":000000 100644 $_z40 $blob_two A\touter/inner\n" &&
+               printf ":100644 000000 $blob_two $_z40 D\touter/inner\n" &&
+               printf ":100644 000000 $blob_two $_z40 D\touter/inner\n" &&
+               printf ":100644 000000 $blob_two $_z40 D\touter/inner\n"
+       } >expect &&
+       git diff-tree -r --no-abbrev one two >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'diff-tree with renames' '
+       # same expectation as above, since we disable rename detection
+       git diff-tree -M -r --no-abbrev one two >actual &&
+       test_cmp expect actual
+'
+
+test_done
index 70b3a06e1dc7a92ac5a0806854e100af02c2346b..4acb3f336ed3fac10c7ddf68868c3ff56db94978 100755 (executable)
@@ -3,17 +3,10 @@
 test_description='apply to deeper directory without getting fooled with symlink'
 . ./test-lib.sh
 
-lecho () {
-       for l_
-       do
-               echo "$l_"
-       done
-}
-
 test_expect_success setup '
 
        mkdir -p arch/i386/boot arch/x86_64 &&
-       lecho 1 2 3 4 5 >arch/i386/boot/Makefile &&
+       test_write_lines 1 2 3 4 5 >arch/i386/boot/Makefile &&
        test_ln_s_add ../i386/boot arch/x86_64/boot &&
        git add . &&
        test_tick &&
@@ -22,7 +15,7 @@ test_expect_success setup '
 
        rm arch/x86_64/boot &&
        mkdir arch/x86_64/boot &&
-       lecho 2 3 4 5 6 >arch/x86_64/boot/Makefile &&
+       test_write_lines 2 3 4 5 6 >arch/x86_64/boot/Makefile &&
        git add . &&
        test_tick &&
        git commit -a -m second &&
@@ -52,4 +45,110 @@ test_expect_success 'check result' '
 
 '
 
+test_expect_success SYMLINKS 'do not read from beyond symbolic link' '
+       git reset --hard &&
+       mkdir -p arch/x86_64/dir &&
+       >arch/x86_64/dir/file &&
+       git add arch/x86_64/dir/file &&
+       echo line >arch/x86_64/dir/file &&
+       git diff >patch &&
+       git reset --hard &&
+
+       mkdir arch/i386/dir &&
+       >arch/i386/dir/file &&
+       ln -s ../i386/dir arch/x86_64/dir &&
+
+       test_must_fail git apply patch &&
+       test_must_fail git apply --cached patch &&
+       test_must_fail git apply --index patch
+
+'
+
+test_expect_success SYMLINKS 'do not follow symbolic link (setup)' '
+
+       rm -rf arch/i386/dir arch/x86_64/dir &&
+       git reset --hard &&
+       ln -s ../i386/dir arch/x86_64/dir &&
+       git add arch/x86_64/dir &&
+       git diff HEAD >add_symlink.patch &&
+       git reset --hard &&
+
+       mkdir arch/x86_64/dir &&
+       >arch/x86_64/dir/file &&
+       git add arch/x86_64/dir/file &&
+       git diff HEAD >add_file.patch &&
+       git diff -R HEAD >del_file.patch &&
+       git reset --hard &&
+       rm -fr arch/x86_64/dir &&
+
+       cat add_symlink.patch add_file.patch >patch &&
+       cat add_symlink.patch del_file.patch >tricky_del &&
+
+       mkdir arch/i386/dir
+'
+
+test_expect_success SYMLINKS 'do not follow symbolic link (same input)' '
+
+       # same input creates a confusing symbolic link
+       test_must_fail git apply patch 2>error-wt &&
+       test_i18ngrep "beyond a symbolic link" error-wt &&
+       test_path_is_missing arch/x86_64/dir &&
+       test_path_is_missing arch/i386/dir/file &&
+
+       test_must_fail git apply --index patch 2>error-ix &&
+       test_i18ngrep "beyond a symbolic link" error-ix &&
+       test_path_is_missing arch/x86_64/dir &&
+       test_path_is_missing arch/i386/dir/file &&
+       test_must_fail git ls-files --error-unmatch arch/x86_64/dir &&
+       test_must_fail git ls-files --error-unmatch arch/i386/dir &&
+
+       test_must_fail git apply --cached patch 2>error-ct &&
+       test_i18ngrep "beyond a symbolic link" error-ct &&
+       test_must_fail git ls-files --error-unmatch arch/x86_64/dir &&
+       test_must_fail git ls-files --error-unmatch arch/i386/dir &&
+
+       >arch/i386/dir/file &&
+       git add arch/i386/dir/file &&
+
+       test_must_fail git apply tricky_del &&
+       test_path_is_file arch/i386/dir/file &&
+
+       test_must_fail git apply --index tricky_del &&
+       test_path_is_file arch/i386/dir/file &&
+       test_must_fail git ls-files --error-unmatch arch/x86_64/dir &&
+       git ls-files --error-unmatch arch/i386/dir &&
+
+       test_must_fail git apply --cached tricky_del &&
+       test_must_fail git ls-files --error-unmatch arch/x86_64/dir &&
+       git ls-files --error-unmatch arch/i386/dir
+'
+
+test_expect_success SYMLINKS 'do not follow symbolic link (existing)' '
+
+       # existing symbolic link
+       git reset --hard &&
+       ln -s ../i386/dir arch/x86_64/dir &&
+       git add arch/x86_64/dir &&
+
+       test_must_fail git apply add_file.patch 2>error-wt-add &&
+       test_i18ngrep "beyond a symbolic link" error-wt-add &&
+       test_path_is_missing arch/i386/dir/file &&
+
+       mkdir arch/i386/dir &&
+       >arch/i386/dir/file &&
+       test_must_fail git apply del_file.patch 2>error-wt-del &&
+       test_i18ngrep "beyond a symbolic link" error-wt-del &&
+       test_path_is_file arch/i386/dir/file &&
+       rm arch/i386/dir/file &&
+
+       test_must_fail git apply --index add_file.patch 2>error-ix-add &&
+       test_i18ngrep "beyond a symbolic link" error-ix-add &&
+       test_path_is_missing arch/i386/dir/file &&
+       test_must_fail git ls-files --error-unmatch arch/i386/dir &&
+
+       test_must_fail git apply --cached add_file.patch 2>error-ct-file &&
+       test_i18ngrep "beyond a symbolic link" error-ct-file &&
+       test_must_fail git ls-files --error-unmatch arch/i386/dir
+'
+
 test_done
diff --git a/t/t4138-apply-ws-expansion.sh b/t/t4138-apply-ws-expansion.sh
new file mode 100755 (executable)
index 0000000..0ffe33f
--- /dev/null
@@ -0,0 +1,121 @@
+#!/bin/sh
+#
+# Copyright (C) 2015 Kyle J. McKay
+#
+
+test_description='git apply test patches with whitespace expansion.'
+
+. ./test-lib.sh
+
+test_expect_success setup '
+       #
+       ## create test-N, patchN.patch, expect-N files
+       #
+
+       # test 1
+       printf "\t%s\n" 1 2 3 4 5 6 >before &&
+       printf "\t%s\n" 1 2 3 >after &&
+       printf "%64s\n" a b c >>after &&
+       printf "\t%s\n" 4 5 6 >>after &&
+       git diff --no-index before after |
+               sed -e "s/before/test-1/" -e "s/after/test-1/" >patch1.patch &&
+       printf "%64s\n" 1 2 3 4 5 6 >test-1 &&
+       printf "%64s\n" 1 2 3 a b c 4 5 6 >expect-1 &&
+
+       # test 2
+       printf "\t%s\n" a b c d e f >before &&
+       printf "\t%s\n" a b c >after &&
+       n=10 &&
+       x=1 &&
+       while test $x -lt $n
+       do
+               printf "%63s%d\n" "" $x >>after
+               x=$(( $x + 1 ))
+       done &&
+       printf "\t%s\n" d e f >>after &&
+       git diff --no-index before after |
+               sed -e "s/before/test-2/" -e "s/after/test-2/" >patch2.patch &&
+       printf "%64s\n" a b c d e f >test-2 &&
+       printf "%64s\n" a b c >expect-2 &&
+       x=1 &&
+       while test $x -lt $n
+       do
+               printf "%63s%d\n" "" $x >>expect-2
+               x=$(( $x + 1 ))
+       done &&
+       printf "%64s\n" d e f >>expect-2 &&
+
+       # test 3
+       printf "\t%s\n" a b c d e f >before &&
+       printf "\t%s\n" a b c >after &&
+       n=100 &&
+       x=0 &&
+       while test $x -lt $n
+       do
+               printf "%63s%02d\n" "" $x >>after
+               x=$(( $x + 1 ))
+       done &&
+       printf "\t%s\n" d e f >>after &&
+       git diff --no-index before after |
+       sed -e "s/before/test-3/" -e "s/after/test-3/" >patch3.patch &&
+       printf "%64s\n" a b c d e f >test-3 &&
+       printf "%64s\n" a b c >expect-3 &&
+       x=0 &&
+       while test $x -lt $n
+       do
+               printf "%63s%02d\n" "" $x >>expect-3
+               x=$(( $x + 1 ))
+       done &&
+       printf "%64s\n" d e f >>expect-3 &&
+
+       # test 4
+       >before &&
+       x=0 &&
+       while test $x -lt 50
+       do
+               printf "\t%02d\n" $x >>before
+               x=$(( $x + 1 ))
+       done &&
+       cat before >after &&
+       printf "%64s\n" a b c >>after &&
+       while test $x -lt 100
+       do
+               printf "\t%02d\n" $x >>before
+               printf "\t%02d\n" $x >>after
+               x=$(( $x + 1 ))
+       done &&
+       git diff --no-index before after |
+       sed -e "s/before/test-4/" -e "s/after/test-4/" >patch4.patch &&
+       >test-4 &&
+       x=0 &&
+       while test $x -lt 50
+       do
+               printf "%63s%02d\n" "" $x >>test-4
+               x=$(( $x + 1 ))
+       done &&
+       cat test-4 >expect-4 &&
+       printf "%64s\n" a b c >>expect-4 &&
+       while test $x -lt 100
+       do
+               printf "%63s%02d\n" "" $x >>test-4
+               printf "%63s%02d\n" "" $x >>expect-4
+               x=$(( $x + 1 ))
+       done &&
+
+       git config core.whitespace tab-in-indent,tabwidth=63 &&
+       git config apply.whitespace fix
+
+'
+
+# Note that `patch` can successfully apply all patches when run
+# with the --ignore-whitespace option.
+
+for t in 1 2 3 4
+do
+       test_expect_success 'apply with ws expansion (t=$t)' '
+               git apply patch$t.patch &&
+               test_cmp test-$t expect-$t
+       '
+done
+
+test_done
diff --git a/t/t4139-apply-escape.sh b/t/t4139-apply-escape.sh
new file mode 100755 (executable)
index 0000000..45b5660
--- /dev/null
@@ -0,0 +1,141 @@
+#!/bin/sh
+
+test_description='paths written by git-apply cannot escape the working tree'
+. ./test-lib.sh
+
+# tests will try to write to ../foo, and we do not
+# want them to escape the trash directory when they
+# fail
+test_expect_success 'bump git repo one level down' '
+       mkdir inside &&
+       mv .git inside/ &&
+       cd inside
+'
+
+# $1 = name of file
+# $2 = current path to file (if different)
+mkpatch_add () {
+       rm -f "${2:-$1}" &&
+       cat <<-EOF
+       diff --git a/$1 b/$1
+       new file mode 100644
+       index 0000000..53c74cd
+       --- /dev/null
+       +++ b/$1
+       @@ -0,0 +1 @@
+       +evil
+       EOF
+}
+
+mkpatch_del () {
+       echo evil >"${2:-$1}" &&
+       cat <<-EOF
+       diff --git a/$1 b/$1
+       deleted file mode 100644
+       index 53c74cd..0000000
+       --- a/$1
+       +++ /dev/null
+       @@ -1 +0,0 @@
+       -evil
+       EOF
+}
+
+# $1 = name of file
+# $2 = content of symlink
+mkpatch_symlink () {
+       rm -f "$1" &&
+       cat <<-EOF
+       diff --git a/$1 b/$1
+       new file mode 120000
+       index 0000000..$(printf "%s" "$2" | git hash-object --stdin)
+       --- /dev/null
+       +++ b/$1
+       @@ -0,0 +1 @@
+       +$2
+       \ No newline at end of file
+       EOF
+}
+
+test_expect_success 'cannot create file containing ..' '
+       mkpatch_add ../foo >patch &&
+       test_must_fail git apply patch &&
+       test_path_is_missing ../foo
+'
+
+test_expect_success 'can create file containing .. with --unsafe-paths' '
+       mkpatch_add ../foo >patch &&
+       git apply --unsafe-paths patch &&
+       test_path_is_file ../foo
+'
+
+test_expect_success  'cannot create file containing .. (index)' '
+       mkpatch_add ../foo >patch &&
+       test_must_fail git apply --index patch &&
+       test_path_is_missing ../foo
+'
+
+test_expect_success  'cannot create file containing .. with --unsafe-paths (index)' '
+       mkpatch_add ../foo >patch &&
+       test_must_fail git apply --index --unsafe-paths patch &&
+       test_path_is_missing ../foo
+'
+
+test_expect_success 'cannot delete file containing ..' '
+       mkpatch_del ../foo >patch &&
+       test_must_fail git apply patch &&
+       test_path_is_file ../foo
+'
+
+test_expect_success 'can delete file containing .. with --unsafe-paths' '
+       mkpatch_del ../foo >patch &&
+       git apply --unsafe-paths patch &&
+       test_path_is_missing ../foo
+'
+
+test_expect_success 'cannot delete file containing .. (index)' '
+       mkpatch_del ../foo >patch &&
+       test_must_fail git apply --index patch &&
+       test_path_is_file ../foo
+'
+
+test_expect_success SYMLINKS 'symlink escape via ..' '
+       {
+               mkpatch_symlink tmp .. &&
+               mkpatch_add tmp/foo ../foo
+       } >patch &&
+       test_must_fail git apply patch &&
+       test_path_is_missing tmp &&
+       test_path_is_missing ../foo
+'
+
+test_expect_success SYMLINKS 'symlink escape via .. (index)' '
+       {
+               mkpatch_symlink tmp .. &&
+               mkpatch_add tmp/foo ../foo
+       } >patch &&
+       test_must_fail git apply --index patch &&
+       test_path_is_missing tmp &&
+       test_path_is_missing ../foo
+'
+
+test_expect_success SYMLINKS 'symlink escape via absolute path' '
+       {
+               mkpatch_symlink tmp "$(pwd)" &&
+               mkpatch_add tmp/foo ../foo
+       } >patch &&
+       test_must_fail git apply patch &&
+       test_path_is_missing tmp &&
+       test_path_is_missing ../foo
+'
+
+test_expect_success SYMLINKS 'symlink escape via absolute path (index)' '
+       {
+               mkpatch_symlink tmp "$(pwd)" &&
+               mkpatch_add tmp/foo ../foo
+       } >patch &&
+       test_must_fail git apply --index patch &&
+       test_path_is_missing tmp &&
+       test_path_is_missing ../foo
+'
+
+test_done
index 99ab7ca21f2673e646232d9c07f77c8ed2f5f998..5f2b290d2b803a4af971a1c03021e97a16951847 100755 (executable)
@@ -212,6 +212,21 @@ test_expect_success 'log --grep' '
        test_cmp expect actual
 '
 
+cat > expect << EOF
+second
+initial
+EOF
+test_expect_success 'log --invert-grep --grep' '
+       git log --pretty="tformat:%s" --invert-grep --grep=th --grep=Sec >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'log --invert-grep --grep -i' '
+       echo initial >expect &&
+       git log --pretty="tformat:%s" --invert-grep -i --grep=th --grep=Sec >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success 'log --grep option parsing' '
        echo second >expect &&
        git log -1 --pretty="tformat:%s" --grep sec >actual &&
index 8bde7dbb6dba8f65797204fee38951e213e80cdd..0ba8194403f6740807cbd63d1bda8a69091e3d6b 100755 (executable)
@@ -18,4 +18,76 @@ am_3way () {
 KNOWN_FAILURE_NOFF_MERGE_ATTEMPTS_TO_MERGE_REMOVED_SUBMODULE_FILES=1
 test_submodule_switch "am_3way"
 
+test_expect_success 'setup diff.submodule' '
+       test_commit one &&
+       INITIAL=$(git rev-parse HEAD) &&
+
+       git init submodule &&
+       (
+               cd submodule &&
+               test_commit two &&
+               git rev-parse HEAD >../initial-submodule
+       ) &&
+       git submodule add ./submodule &&
+       git commit -m first &&
+
+       (
+               cd submodule &&
+               test_commit three &&
+               git rev-parse HEAD >../first-submodule
+       ) &&
+       git add submodule &&
+       git commit -m second &&
+       SECOND=$(git rev-parse HEAD) &&
+
+       (
+               cd submodule &&
+               git mv two.t four.t &&
+               git commit -m "second submodule" &&
+               git rev-parse HEAD >../second-submodule
+       ) &&
+       test_commit four &&
+       git add submodule &&
+       git commit --amend --no-edit &&
+       THIRD=$(git rev-parse HEAD) &&
+       git submodule update --init
+'
+
+run_test() {
+       START_COMMIT=$1 &&
+       EXPECT=$2 &&
+       # Abort any merges in progress: the previous
+       # test may have failed, and we should clean up.
+       test_might_fail git am --abort &&
+       git reset --hard $START_COMMIT &&
+       rm -f *.patch &&
+       git format-patch -1 &&
+       git reset --hard $START_COMMIT^ &&
+       git submodule update &&
+       git am *.patch &&
+       git submodule update &&
+       git -C submodule rev-parse HEAD >actual &&
+       test_cmp $EXPECT actual
+}
+
+test_expect_success 'diff.submodule unset' '
+       test_unconfig diff.submodule &&
+       run_test $SECOND first-submodule
+'
+
+test_expect_success 'diff.submodule unset with extra file' '
+       test_unconfig diff.submodule &&
+       run_test $THIRD second-submodule
+'
+
+test_expect_success 'diff.submodule=log' '
+       test_config diff.submodule log &&
+       run_test $SECOND first-submodule
+'
+
+test_expect_success 'diff.submodule=log with extra file' '
+       test_config diff.submodule log &&
+       run_test $THIRD second-submodule
+'
+
 test_done
index e32e46dee10e96a0b0e51df0eeefd343373f662e..0794d33dad6cddcb6be58663c16cbe67be600e47 100755 (executable)
@@ -253,4 +253,12 @@ test_expect_success 'prune .git/shallow' '
        test_path_is_missing .git/shallow
 '
 
+test_expect_success 'prune: handle alternate object database' '
+       test_create_repo A &&
+       git -C A commit --allow-empty -m "initial commit" &&
+       git clone --shared A B &&
+       git -C B commit --allow-empty -m "next commit" &&
+       git -C B prune
+'
+
 test_done
index 5b2b1c2c130387332778f6e49043b739dd2d7d21..bd37f040b6ce13406ef009944d46d2f1cc6c8d7b 100755 (executable)
@@ -541,13 +541,30 @@ check_prot_path () {
        test_cmp expected actual
 }
 
-check_prot_host_path () {
-       cat >expected <<-EOF &&
+check_prot_host_port_path () {
+       local diagport
+       case "$2" in
+               *ssh*)
+               pp=ssh
+               uah=userandhost
+               ehost=$(echo $3 | tr -d "[]")
+               diagport="Diag: port=$4"
+               ;;
+               *)
+               pp=$p
+               uah=hostandport
+               ehost=$(echo $3$4 | sed -e "s/22$/:22/" -e "s/NONE//")
+               diagport=""
+               ;;
+       esac
+       cat >exp <<-EOF &&
        Diag: url=$1
-       Diag: protocol=$2
-       Diag: hostandport=$3
-       Diag: path=$4
+       Diag: protocol=$pp
+       Diag: $uah=$ehost
+       $diagport
+       Diag: path=$5
        EOF
+       grep -v "^$" exp >expected
        git fetch-pack --diag-url "$1" >actual &&
        test_cmp expected actual
 }
@@ -557,22 +574,20 @@ do
        # git or ssh with scheme
        for p in "ssh+git" "git+ssh" git ssh
        do
-               for h in host host:12 [::1] [::1]:23
+               for h in host user@host user@[::1] user@::1
                do
-                       case "$p" in
-                       *ssh*)
-                               pp=ssh
-                               ;;
-                       *)
-                               pp=$p
-                       ;;
-                       esac
                        test_expect_success "fetch-pack --diag-url $p://$h/$r" '
-                               check_prot_host_path $p://$h/$r $pp "$h" "/$r"
+                               check_prot_host_port_path $p://$h/$r $p "$h" NONE "/$r"
                        '
                        # "/~" -> "~" conversion
                        test_expect_success "fetch-pack --diag-url $p://$h/~$r" '
-                               check_prot_host_path $p://$h/~$r $pp "$h" "~$r"
+                               check_prot_host_port_path $p://$h/~$r $p "$h" NONE "~$r"
+                       '
+               done
+               for h in host User@host User@[::1]
+               do
+                       test_expect_success "fetch-pack --diag-url $p://$h:22/$r" '
+                               check_prot_host_port_path $p://$h:22/$r $p "$h" 22 "/$r"
                        '
                done
        done
@@ -603,11 +618,11 @@ do
        for h in host [::1]
        do
                test_expect_success "fetch-pack --diag-url $h:$r" '
-                       check_prot_path $h:$r $p "$r"
+                       check_prot_host_port_path $h:$r $p "$h" NONE "$r"
                '
                # Do "/~" -> "~" conversion
                test_expect_success "fetch-pack --diag-url $h:/~$r" '
-                       check_prot_host_path $h:/~$r $p "$h" "~$r"
+                       check_prot_host_port_path $h:/~$r $p "$h" NONE "~$r"
                '
        done
 done
index 85c7fecd22a37d06001398883954180a2b1a9868..630885d6df2fed0b8ba35005f150ccd3838dfcca 100755 (executable)
@@ -238,7 +238,7 @@ test_expect_success 'push with pushInsteadOf' '
 test_expect_success 'push with pushInsteadOf and explicit pushurl (pushInsteadOf should not rewrite)' '
        mk_empty testrepo &&
        test_config "url.trash2/.pushInsteadOf" testrepo/ &&
-       test_config "url.trash3/.pusnInsteadOf" trash/wrong &&
+       test_config "url.trash3/.pushInsteadOf" trash/wrong &&
        test_config remote.r.url trash/wrong &&
        test_config remote.r.pushurl "testrepo/" &&
        git push r refs/heads/master:refs/remotes/origin/master &&
@@ -1434,4 +1434,67 @@ test_expect_success 'receive.denyCurrentBranch = updateInstead' '
 
 '
 
+test_expect_success 'updateInstead with push-to-checkout hook' '
+       rm -fr testrepo &&
+       git init testrepo &&
+       (
+               cd testrepo &&
+               git pull .. master &&
+               git reset --hard HEAD^^ &&
+               git tag initial &&
+               git config receive.denyCurrentBranch updateInstead &&
+               write_script .git/hooks/push-to-checkout <<-\EOF
+               echo >&2 updating from $(git rev-parse HEAD)
+               echo >&2 updating to "$1"
+
+               git update-index -q --refresh &&
+               git read-tree -u -m HEAD "$1" || {
+                       status=$?
+                       echo >&2 read-tree failed
+                       exit $status
+               }
+               EOF
+       ) &&
+
+       # Try pushing into a pristine
+       git push testrepo master &&
+       (
+               cd testrepo &&
+               git diff --quiet &&
+               git diff HEAD --quiet &&
+               test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
+       ) &&
+
+       # Try pushing into a repository with conflicting change
+       (
+               cd testrepo &&
+               git reset --hard initial &&
+               echo conflicting >path2
+       ) &&
+       test_must_fail git push testrepo master &&
+       (
+               cd testrepo &&
+               test $(git rev-parse initial) = $(git rev-parse HEAD) &&
+               test conflicting = "$(cat path2)" &&
+               git diff-index --quiet --cached HEAD
+       ) &&
+
+       # Try pushing into a repository with unrelated change
+       (
+               cd testrepo &&
+               git reset --hard initial &&
+               echo unrelated >path1 &&
+               echo irrelevant >path5 &&
+               git add path5
+       ) &&
+       git push testrepo master &&
+       (
+               cd testrepo &&
+               test "$(cat path1)" = unrelated &&
+               test "$(cat path5)" = irrelevant &&
+               test "$(git diff --name-only --cached HEAD)" = path5 &&
+               test $(git -C .. rev-parse HEAD) = $(git rev-parse HEAD)
+       )
+'
+
 test_done
index ac71418a1b26bc17a1252d6831869b96a8d8c176..2731ad4cea951744ea82b94a038a71ef01a228a2 100755 (executable)
@@ -165,6 +165,24 @@ test_expect_success 'fetch notices corrupt idx' '
        )
 '
 
+test_expect_success 'fetch can handle previously-fetched .idx files' '
+       git checkout --orphan branch1 &&
+       echo base >file &&
+       git add file &&
+       git commit -m base &&
+       git --bare init "$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git &&
+       git push "$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git branch1 &&
+       git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git repack -d &&
+       git checkout -b branch2 branch1 &&
+       echo b2 >>file &&
+       git commit -a -m b2 &&
+       git push "$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git branch2 &&
+       git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH"/repo_packed_branches.git repack -d &&
+       git --bare init clone_packed_branches.git &&
+       git --git-dir=clone_packed_branches.git fetch "$HTTPD_URL"/dumb/repo_packed_branches.git branch1:branch1 &&
+       git --git-dir=clone_packed_branches.git fetch "$HTTPD_URL"/dumb/repo_packed_branches.git branch2:branch2
+'
+
 test_expect_success 'did not use upload-pack service' '
        grep '/git-upload-pack' <"$HTTPD_ROOT_PATH"/access.log >act
        : >exp
@@ -196,5 +214,47 @@ test_expect_success 'reencoding is robust to whitespace oddities' '
        grep "this is the error message" stderr
 '
 
+check_language () {
+       case "$2" in
+       '')
+               >expect
+               ;;
+       ?*)
+               echo "Accept-Language: $1" >expect
+               ;;
+       esac &&
+       GIT_CURL_VERBOSE=1 \
+       LANGUAGE=$2 \
+       git ls-remote "$HTTPD_URL/dumb/repo.git" >output 2>&1 &&
+       tr -d '\015' <output |
+       sort -u |
+       sed -ne '/^Accept-Language:/ p' >actual &&
+       test_cmp expect actual
+}
+
+test_expect_success 'git client sends Accept-Language based on LANGUAGE' '
+       check_language "ko-KR, *;q=0.9" ko_KR.UTF-8'
+
+test_expect_success 'git client sends Accept-Language correctly with unordinary LANGUAGE' '
+       check_language "ko-KR, *;q=0.9" "ko_KR:" &&
+       check_language "ko-KR, en-US;q=0.9, *;q=0.8" "ko_KR::en_US" &&
+       check_language "ko-KR, *;q=0.9" ":::ko_KR" &&
+       check_language "ko-KR, en-US;q=0.9, *;q=0.8" "ko_KR!!:en_US" &&
+       check_language "ko-KR, ja-JP;q=0.9, *;q=0.8" "ko_KR en_US:ja_JP"'
+
+test_expect_success 'git client sends Accept-Language with many preferred languages' '
+       check_language "ko-KR, en-US;q=0.9, fr-CA;q=0.8, de;q=0.7, sr;q=0.6, \
+ja;q=0.5, zh;q=0.4, sv;q=0.3, pt;q=0.2, *;q=0.1" \
+               ko_KR.EUC-KR:en_US.UTF-8:fr_CA:de.UTF-8@euro:sr@latin:ja:zh:sv:pt &&
+       check_language "ko-KR, en-US;q=0.99, fr-CA;q=0.98, de;q=0.97, sr;q=0.96, \
+ja;q=0.95, zh;q=0.94, sv;q=0.93, pt;q=0.92, nb;q=0.91, *;q=0.90" \
+               ko_KR.EUC-KR:en_US.UTF-8:fr_CA:de.UTF-8@euro:sr@latin:ja:zh:sv:pt:nb
+'
+
+test_expect_success 'git client does not send an empty Accept-Language' '
+       GIT_CURL_VERBOSE=1 LANGUAGE= git ls-remote "$HTTPD_URL/dumb/repo.git" 2>stderr &&
+       ! grep "^Accept-Language:" stderr
+'
+
 stop_httpd
 test_done
index 6b163799510fa608fc6effa146accf295d0068f5..b7e283252d7d73e937ef87096801f2d252e95961 100755 (executable)
@@ -141,5 +141,32 @@ test_expect_success 'push disabled'      "test_remote_error    'service not enab
 test_expect_success 'read access denied' "test_remote_error -x 'no such repository'      fetch repo.git       "
 test_expect_success 'not exported'       "test_remote_error -n 'repository not exported' fetch repo.git       "
 
+stop_git_daemon
+start_git_daemon --interpolated-path="$GIT_DAEMON_DOCUMENT_ROOT_PATH/%H%D"
+
+test_expect_success 'access repo via interpolated hostname' '
+       repo="$GIT_DAEMON_DOCUMENT_ROOT_PATH/localhost/interp.git" &&
+       git init --bare "$repo" &&
+       git push "$repo" HEAD &&
+       >"$repo"/git-daemon-export-ok &&
+       rm -rf tmp.git &&
+       GIT_OVERRIDE_VIRTUAL_HOST=localhost \
+               git clone --bare "$GIT_DAEMON_URL/interp.git" tmp.git &&
+       rm -rf tmp.git &&
+       GIT_OVERRIDE_VIRTUAL_HOST=LOCALHOST \
+               git clone --bare "$GIT_DAEMON_URL/interp.git" tmp.git
+'
+
+test_expect_success 'hostname cannot break out of directory' '
+       rm -rf tmp.git &&
+       repo="$GIT_DAEMON_DOCUMENT_ROOT_PATH/../escape.git" &&
+       git init --bare "$repo" &&
+       git push "$repo" HEAD &&
+       >"$repo"/git-daemon-export-ok &&
+       test_must_fail \
+               env GIT_OVERRIDE_VIRTUAL_HOST=.. \
+               git clone --bare "$GIT_DAEMON_URL/escape.git" tmp.git
+'
+
 stop_git_daemon
 test_done
index e4f10c0f68b94bfa719c3d208f622541506c86b3..02b40b117faa1c6de816001018d1c7deda15ad7d 100755 (executable)
@@ -301,11 +301,17 @@ expect_ssh () {
                (cd "$TRASH_DIRECTORY" && rm -f ssh-expect && >ssh-output)
        ' &&
        {
-               case "$1" in
-               none)
+               case "$#" in
+               1)
                        ;;
-               *)
+               2)
                        echo "ssh: $1 git-upload-pack '$2'"
+                       ;;
+               3)
+                       echo "ssh: $1 $2 git-upload-pack '$3'"
+                       ;;
+               *)
+                       echo "ssh: $1 $2 git-upload-pack '$3' $4"
                esac
        } >"$TRASH_DIRECTORY/ssh-expect" &&
        (cd "$TRASH_DIRECTORY" && test_cmp ssh-expect ssh-output)
@@ -326,7 +332,7 @@ test_expect_success !MINGW,!CYGWIN 'clone local path foo:bar' '
 
 test_expect_success 'bracketed hostnames are still ssh' '
        git clone "[myhost:123]:src" ssh-bracket-clone &&
-       expect_ssh myhost:123 src
+       expect_ssh myhost '-p 123' src
 '
 
 counter=0
@@ -336,7 +342,8 @@ counter=0
 test_clone_url () {
        counter=$(($counter + 1))
        test_might_fail git clone "$1" tmp$counter &&
-       expect_ssh "$2" "$3"
+       shift &&
+       expect_ssh "$@"
 }
 
 test_expect_success !MINGW 'clone c:temp is ssl' '
@@ -359,7 +366,7 @@ done
 for repo in rep rep/home/project 123
 do
        test_expect_success "clone [::1]:$repo" '
-               test_clone_url [::1]:$repo ::1 $repo
+               test_clone_url [::1]:$repo ::1 "$repo"
        '
 done
 #home directory
@@ -400,24 +407,40 @@ test_expect_success 'clone ssh://host.xz:22/~repo' '
 '
 
 #IPv6
-test_expect_success 'clone ssh://[::1]/home/user/repo' '
-       test_clone_url "ssh://[::1]/home/user/repo" "::1" "/home/user/repo"
-'
+for tuah in ::1 [::1] user@::1 user@[::1] [user@::1]
+do
+       ehost=$(echo $tuah | tr -d "[]")
+       test_expect_success "clone ssh://$tuah/home/user/repo" "
+         test_clone_url ssh://$tuah/home/user/repo $ehost /home/user/repo
+       "
+done
 
 #IPv6 from home directory
-test_expect_success 'clone ssh://[::1]/~repo' '
-       test_clone_url "ssh://[::1]/~repo" "::1" "~repo"
-'
+for tuah in ::1 [::1] user@::1 user@[::1] [user@::1]
+do
+       euah=$(echo $tuah | tr -d "[]")
+       test_expect_success "clone ssh://$tuah/~repo" "
+         test_clone_url ssh://$tuah/~repo $euah '~repo'
+       "
+done
 
 #IPv6 with port number
-test_expect_success 'clone ssh://[::1]:22/home/user/repo' '
-       test_clone_url "ssh://[::1]:22/home/user/repo" "-p 22 ::1" "/home/user/repo"
-'
+for tuah in [::1] user@[::1] [user@::1]
+do
+       euah=$(echo $tuah | tr -d "[]")
+       test_expect_success "clone ssh://$tuah:22/home/user/repo" "
+         test_clone_url ssh://$tuah:22/home/user/repo '-p 22' $euah /home/user/repo
+       "
+done
 
 #IPv6 from home directory with port number
-test_expect_success 'clone ssh://[::1]:22/~repo' '
-       test_clone_url "ssh://[::1]:22/~repo" "-p 22 ::1" "~repo"
-'
+for tuah in [::1] user@[::1] [user@::1]
+do
+       euah=$(echo $tuah | tr -d "[]")
+       test_expect_success "clone ssh://$tuah:22/~repo" "
+         test_clone_url ssh://$tuah:22/~repo '-p 22' $euah '~repo'
+       "
+done
 
 test_expect_success 'clone from a repository with two identical branches' '
 
index 24194075468819881826c24c08b1aa97bacb9897..c9d3ed14c3a3238208b44ce815e37123298dea77 100755 (executable)
@@ -281,4 +281,28 @@ test_expect_success 'push messages' '
        )
 '
 
+test_expect_success 'fetch HEAD' '
+       (cd server &&
+       git checkout master &&
+       echo more >>file &&
+       git commit -a -m more
+       ) &&
+       (cd local &&
+       git fetch origin HEAD
+       ) &&
+       compare_refs server HEAD local FETCH_HEAD
+'
+
+test_expect_success 'fetch url' '
+       (cd server &&
+       git checkout master &&
+       echo more >>file &&
+       git commit -a -m more
+       ) &&
+       (cd local &&
+       git fetch "testgit::${PWD}/../server"
+       ) &&
+       compare_refs server HEAD local FETCH_HEAD
+'
+
 test_done
index 3758961765635c4ce504eec1540605f65efd386a..190ee903cf6269071809e82d61d6065f1de679c6 100755 (executable)
@@ -69,7 +69,8 @@ test_expect_success 'works in subdirectory' '
        cp new1.txt dir/a.txt &&
        cp orig.txt dir/o.txt &&
        cp new2.txt dir/b.txt &&
-       ( cd dir && git merge-file a.txt o.txt b.txt )
+       ( cd dir && git merge-file a.txt o.txt b.txt ) &&
+       test_path_is_missing a.txt
 '
 
 cp new1.txt test.txt
index 7c882450317b85ffdeabc105ee62a18ce3b04ca9..5811a982f472e3b79f31cc50dcdef92dcdb4a58c 100755 (executable)
@@ -171,6 +171,23 @@ test_expect_success 'submodule add with ./ in path' '
        test_cmp empty untracked
 '
 
+test_expect_success 'submodule add with /././ in path' '
+       echo "refs/heads/master" >expect &&
+       >empty &&
+
+       (
+               cd addtest &&
+               git submodule add "$submodurl" dotslashdotsubmod/././frotz/./ &&
+               git submodule init
+       ) &&
+
+       rm -f heads head untracked &&
+       inspect addtest/dotslashdotsubmod/frotz ../../.. &&
+       test_cmp expect heads &&
+       test_cmp expect head &&
+       test_cmp empty untracked
+'
+
 test_expect_success 'submodule add with // in path' '
        echo "refs/heads/master" >expect &&
        >empty &&
diff --git a/t/t7516-commit-races.sh b/t/t7516-commit-races.sh
new file mode 100755 (executable)
index 0000000..f2ce14e
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+test_description='git commit races'
+. ./test-lib.sh
+
+test_expect_success 'race to create orphan commit' '
+       write_script hare-editor <<-\EOF &&
+       git commit --allow-empty -m hare
+       EOF
+       test_must_fail env EDITOR=./hare-editor git commit --allow-empty -m tortoise -e &&
+       git show -s --pretty=format:%s >subject &&
+       grep hare subject &&
+       test -z "$(git show -s --pretty=format:%P)"
+'
+
+test_expect_success 'race to create non-orphan commit' '
+       write_script airplane-editor <<-\EOF &&
+       git commit --allow-empty -m airplane
+       EOF
+       git checkout --orphan branch &&
+       git commit --allow-empty -m base &&
+       git rev-parse HEAD >base &&
+       test_must_fail env EDITOR=./airplane-editor git commit --allow-empty -m ship -e &&
+       git show -s --pretty=format:%s >subject &&
+       grep airplane subject &&
+       git rev-parse HEAD^ >parent &&
+       test_cmp base parent
+'
+
+test_done
index af6a3e8904ab1d953b359707de1e0c9a09b3ce1f..051305545c414481b6883fa619ffb39134187de0 100755 (executable)
@@ -392,7 +392,7 @@ test_expect_success $PREREQ 'allow long lines with --no-validate' '
                --from="Example <nobody@example.com>" \
                --to=nobody@example.com \
                --smtp-server="$(pwd)/fake.sendmail" \
-               --novalidate \
+               --no-validate \
                $patches longline.patch \
                2>errors
 '
@@ -426,7 +426,7 @@ test_expect_success $PREREQ 'In-Reply-To without --chain-reply-to' '
        git send-email \
                --from="Example <nobody@example.com>" \
                --to=nobody@example.com \
-               --nochain-reply-to \
+               --no-chain-reply-to \
                --in-reply-to="$(cat expect)" \
                --smtp-server="$(pwd)/fake.sendmail" \
                $patches $patches $patches \
@@ -1067,7 +1067,7 @@ test_expect_success $PREREQ 'in-reply-to but no threading' '
                --from="Example <nobody@example.com>" \
                --to=nobody@example.com \
                --in-reply-to="<in-reply-id@example.com>" \
-               --nothread \
+               --no-thread \
                $patches |
        grep "In-Reply-To: <in-reply-id@example.com>"
 '
@@ -1077,7 +1077,7 @@ test_expect_success $PREREQ 'no in-reply-to and no threading' '
                --dry-run \
                --from="Example <nobody@example.com>" \
                --to=nobody@example.com \
-               --nothread \
+               --no-thread \
                $patches $patches >stdout &&
        ! grep "In-Reply-To: " stdout
 '
@@ -1088,7 +1088,7 @@ test_expect_success $PREREQ 'threading but no chain-reply-to' '
                --from="Example <nobody@example.com>" \
                --to=nobody@example.com \
                --thread \
-               --nochain-reply-to \
+               --no-chain-reply-to \
                $patches $patches >stdout &&
        grep "In-Reply-To: " stdout
 '
index 37c2d633f0d2fefdb530266b8b250ef59e8704d3..c538e0a4e97c942dcb64b3e5bdd9afa10591f33e 100755 (executable)
@@ -552,8 +552,8 @@ test_expect_success 'D: verify pack' '
 '
 
 cat >expect <<EOF
-:000000 100755 0000000000000000000000000000000000000000 35a59026a33beac1569b1c7f66f3090ce9c09afc A     newdir/exec.sh
-:000000 100644 0000000000000000000000000000000000000000 046d0371e9220107917db0d0e030628de8a1de9b A     newdir/interesting
+:000000 100755 0000000000000000000000000000000000000000 e74b7d465e52746be2b4bae983670711e6e66657 A     newdir/exec.sh
+:000000 100644 0000000000000000000000000000000000000000 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 A     newdir/interesting
 EOF
 git diff-tree -M -r branch^ branch >actual
 test_expect_success \
diff --git a/t/t9817-git-p4-exclude.sh b/t/t9817-git-p4-exclude.sh
new file mode 100755 (executable)
index 0000000..aac568e
--- /dev/null
@@ -0,0 +1,71 @@
+#!/bin/sh
+
+test_description='git p4 tests for excluded paths during clone and sync'
+
+. ./lib-git-p4.sh
+
+test_expect_success 'start p4d' '
+       start_p4d
+'
+
+# Create a repo with the structure:
+#
+#    //depot/wanted/foo
+#    //depot/discard/foo
+#
+# Check that we can exclude a subdirectory with both
+# clone and sync operations.
+
+test_expect_success 'create exclude repo' '
+       (
+               cd "$cli" &&
+               mkdir -p wanted discard &&
+               echo wanted >wanted/foo &&
+               echo discard >discard/foo &&
+               p4 add wanted/foo discard/foo &&
+               p4 submit -d "initial revision"
+       )
+'
+
+test_expect_success 'check the repo was created correctly' '
+       test_when_finished cleanup_git &&
+       git p4 clone --dest="$git" //depot/...@all &&
+       (
+               cd "$git" &&
+               test_path_is_file wanted/foo &&
+               test_path_is_file discard/foo
+       )
+'
+
+test_expect_success 'clone, excluding part of repo' '
+       test_when_finished cleanup_git &&
+       git p4 clone -//depot/discard/... --dest="$git" //depot/...@all &&
+       (
+               cd "$git" &&
+               test_path_is_file wanted/foo &&
+               test_path_is_missing discard/foo
+       )
+'
+
+test_expect_success 'clone, then sync with exclude' '
+       test_when_finished cleanup_git &&
+       git p4 clone -//depot/discard/... --dest="$git" //depot/...@all &&
+       (
+               cd "$cli" &&
+               p4 edit wanted/foo discard/foo &&
+               date >>wanted/foo &&
+               date >>discard/foo &&
+               p4 submit -d "updating" &&
+
+               cd "$git" &&
+               git p4 sync -//depot/discard/... &&
+               test_path_is_file wanted/foo &&
+               test_path_is_missing discard/foo
+       )
+'
+
+test_expect_success 'kill p4d' '
+       kill_p4d
+'
+
+test_done
index 0d93e33de4759bff71739c19be803cac981f0770..0698ce7908cb958c6e94a8cfa11c1019de692710 100644 (file)
@@ -745,7 +745,9 @@ test_ln_s_add () {
        else
                printf '%s' "$1" >"$2" &&
                ln_s_obj=$(git hash-object -w "$2") &&
-               git update-index --add --cacheinfo 120000 $ln_s_obj "$2"
+               git update-index --add --cacheinfo 120000 $ln_s_obj "$2" &&
+               # pick up stat info from the file
+               git update-index "$2"
        fi
 }
 
index bb1402de944de11ee54a73dab7c33441ae1450c5..c09677802cce067a946a2550cdd2d8ef33434e81 100644 (file)
@@ -1031,9 +1031,33 @@ test_lazy_prereq USR_BIN_TIME '
        test -x /usr/bin/time
 '
 
-# When the tests are run as root, permission tests will report that
-# things are writable when they shouldn't be.
-test -w / || test_set_prereq SANITY
+test_lazy_prereq NOT_ROOT '
+       uid=$(id -u) &&
+       test "$uid" != 0
+'
+
+# On a filesystem that lacks SANITY, a file can be deleted even if
+# the containing directory doesn't have write permissions, or a file
+# can be accessed even if the containing directory doesn't have read
+# or execute permissions, causing our tests that validate that Git
+# works sensibly in such situations.
+test_lazy_prereq SANITY '
+       mkdir SANETESTD.1 SANETESTD.2 &&
+
+       chmod +w SANETESTD.1 SANETESTD.2 &&
+       >SANETESTD.1/x 2>SANETESTD.2/x &&
+       chmod -w SANETESTD.1 &&
+       chmod -rx SANETESTD.2 ||
+       error "bug in test sript: cannot prepare SANETESTD"
+
+       ! rm SANETESTD.1/x && ! test -f SANETESTD.2/x
+       status=$?
+
+       chmod +rwx SANETESTD.1 SANETESTD.2 &&
+       rm -rf SANETESTD.1 SANETESTD.2 ||
+       error "bug in test sript: cannot clean SANETESTD"
+       return $status
+'
 
 GIT_UNZIP=${GIT_UNZIP:-unzip}
 test_lazy_prereq UNZIP '
index 623adeb02d0e06a83d7b17a9b605ff8c6475a0bd..05b3859b476dc19f37d8715ac012c29373e8f91e 100644 (file)
--- a/trailer.c
+++ b/trailer.c
@@ -1,7 +1,6 @@
 #include "cache.h"
 #include "string-list.h"
 #include "run-command.h"
-#include "string-list.h"
 #include "commit.h"
 #include "trailer.h"
 /*
index 0224687a2316798c57315093315eafae0da0b1aa..5d99a6bc2e7a10d40f6d8213e2f3cad254dbdb04 100644 (file)
@@ -5,7 +5,6 @@
 #include "commit.h"
 #include "diff.h"
 #include "revision.h"
-#include "quote.h"
 #include "remote.h"
 #include "string-list.h"
 #include "thread-utils.h"
@@ -98,6 +97,8 @@ static void do_take_over(struct transport *transport)
        free(data);
 }
 
+static void standard_options(struct transport *t);
+
 static struct child_process *get_helper(struct transport *transport)
 {
        struct helper_data *data = transport->data;
@@ -212,6 +213,7 @@ static struct child_process *get_helper(struct transport *transport)
        strbuf_release(&buf);
        if (debug)
                fprintf(stderr, "Debug: Capabilities complete.\n");
+       standard_options(transport);
        return data->helper;
 }
 
@@ -339,24 +341,14 @@ static int fetch_with_fetch(struct transport *transport,
        int i;
        struct strbuf buf = STRBUF_INIT;
 
-       standard_options(transport);
-       if (data->check_connectivity &&
-           data->transport_options.check_self_contained_and_connected)
-               set_helper_option(transport, "check-connectivity", "true");
-
-       if (transport->cloning)
-               set_helper_option(transport, "cloning", "true");
-
-       if (data->transport_options.update_shallow)
-               set_helper_option(transport, "update-shallow", "true");
-
        for (i = 0; i < nr_heads; i++) {
                const struct ref *posn = to_fetch[i];
                if (posn->status & REF_STATUS_UPTODATE)
                        continue;
 
                strbuf_addf(&buf, "fetch %s %s\n",
-                           sha1_to_hex(posn->old_sha1), posn->name);
+                           sha1_to_hex(posn->old_sha1),
+                           posn->symref ? posn->symref : posn->name);
        }
 
        strbuf_addch(&buf, '\n');
@@ -454,7 +446,8 @@ static int fetch_with_import(struct transport *transport,
                if (posn->status & REF_STATUS_UPTODATE)
                        continue;
 
-               strbuf_addf(&buf, "import %s\n", posn->name);
+               strbuf_addf(&buf, "import %s\n",
+                           posn->symref ? posn->symref : posn->name);
                sendline(data, &buf);
                strbuf_reset(&buf);
        }
@@ -487,14 +480,15 @@ static int fetch_with_import(struct transport *transport,
         * fast-forward or this is a forced update.
         */
        for (i = 0; i < nr_heads; i++) {
-               char *private;
+               char *private, *name;
                posn = to_fetch[i];
                if (posn->status & REF_STATUS_UPTODATE)
                        continue;
+               name = posn->symref ? posn->symref : posn->name;
                if (data->refspecs)
-                       private = apply_refspecs(data->refspecs, data->refspec_nr, posn->name);
+                       private = apply_refspecs(data->refspecs, data->refspec_nr, name);
                else
-                       private = xstrdup(posn->name);
+                       private = xstrdup(name);
                if (private) {
                        read_ref(private, posn->old_sha1);
                        free(private);
@@ -620,6 +614,16 @@ static int fetch(struct transport *transport,
        if (!count)
                return 0;
 
+       if (data->check_connectivity &&
+           data->transport_options.check_self_contained_and_connected)
+               set_helper_option(transport, "check-connectivity", "true");
+
+       if (transport->cloning)
+               set_helper_option(transport, "cloning", "true");
+
+       if (data->transport_options.update_shallow)
+               set_helper_option(transport, "update-shallow", "true");
+
        if (data->fetch)
                return fetch_with_fetch(transport, nr_heads, to_fetch);
 
@@ -824,7 +828,6 @@ static int push_refs_with_push(struct transport *transport,
                return 0;
        }
 
-       standard_options(transport);
        for_each_string_list_item(cas_option, &cas_options)
                set_helper_option(transport, "cas", cas_option->string);
 
@@ -860,7 +863,7 @@ static int push_refs_with_export(struct transport *transport,
                        die("helper %s does not support dry-run", data->name);
        } else if (flags & TRANSPORT_PUSH_CERT) {
                if (set_helper_option(transport, TRANS_OPT_PUSH_CERT, "true") != 0)
-                       die("helper %s does not support dry-run", data->name);
+                       die("helper %s does not support --signed", data->name);
        }
 
        if (flags & TRANSPORT_PUSH_FORCE) {
index 618d2164919758b141aa9d6408c57a4fb99c922c..132d342bc12bf790f9964f179385aa4f08e6ae00 100644 (file)
@@ -412,9 +412,9 @@ static size_t url_match_prefix(const char *url,
        return 0;
 }
 
-int match_urls(const struct url_info *url,
-              const struct url_info *url_prefix,
-              int *exactusermatch)
+static int match_urls(const struct url_info *url,
+                     const struct url_info *url_prefix,
+                     int *exactusermatch)
 {
        /*
         * url_prefix matches url if the scheme, host and port of url_prefix
index b461dfd3dfee2c37eb65e5abb28f6f128f40096b..528862adc55c43ed26763b3c05e1d27d558a1b74 100644 (file)
@@ -31,7 +31,6 @@ struct url_info {
 };
 
 extern char *url_normalize(const char *, struct url_info *);
-extern int match_urls(const struct url_info *url, const struct url_info *url_prefix, int *exactusermatch);
 
 struct urlmatch_item {
        size_t matched_len;
index fad52d6392fab8aadc8f6555db5aafcde224a120..2ccbee50cb69171062e84c9a1b36baf7e31be2f8 100644 (file)
@@ -1,6 +1,5 @@
 #include "cache.h"
 #include "userdiff.h"
-#include "cache.h"
 #include "attr.h"
 
 static struct userdiff_driver *drivers;
index f149371e71ebdcdbd12336aace15b0fc20f74569..58ffeca264b765326a234b21356a02a3152e1c38 100644 (file)
--- a/walker.c
+++ b/walker.c
@@ -232,7 +232,7 @@ int walker_targets_stdin(char ***target, const char ***write_ref)
                        REALLOC_ARRAY(*write_ref, targets_alloc);
                }
                (*target)[targets] = xstrdup(tg_one);
-               (*write_ref)[targets] = rf_one ? xstrdup(rf_one) : NULL;
+               (*write_ref)[targets] = xstrdup_or_null(rf_one);
                targets++;
        }
        strbuf_release(&buf);
@@ -299,7 +299,7 @@ int walker_fetch(struct walker *walker, int targets, char **target,
                strbuf_reset(&refname);
                strbuf_addf(&refname, "refs/%s", write_ref[i]);
                if (ref_transaction_update(transaction, refname.buf,
-                                          &sha1[20 * i], NULL, 0, 0,
+                                          &sha1[20 * i], NULL, 0,
                                           msg ? msg : "fetch (unknown)",
                                           &err)) {
                        error("%s", err.buf);
index 007ec0d8eac529579cc00b14f9baaddb7ac68487..d5a6cef2be0fb13b262bed2e0b58bd58fbb5454d 100644 (file)
--- a/wrapper.c
+++ b/wrapper.c
@@ -172,8 +172,22 @@ void *xcalloc(size_t nmemb, size_t size)
  * 64-bit is buggy, returning EINVAL if len >= INT_MAX; and even in
  * the absence of bugs, large chunks can result in bad latencies when
  * you decide to kill the process.
+ *
+ * We pick 8 MiB as our default, but if the platform defines SSIZE_MAX
+ * that is smaller than that, clip it to SSIZE_MAX, as a call to
+ * read(2) or write(2) larger than that is allowed to fail.  As the last
+ * resort, we allow a port to pass via CFLAGS e.g. "-DMAX_IO_SIZE=value"
+ * to override this, if the definition of SSIZE_MAX given by the platform
+ * is broken.
  */
-#define MAX_IO_SIZE (8*1024*1024)
+#ifndef MAX_IO_SIZE
+# define MAX_IO_SIZE_DEFAULT (8*1024*1024)
+# if defined(SSIZE_MAX) && (SSIZE_MAX < MAX_IO_SIZE_DEFAULT)
+#  define MAX_IO_SIZE SSIZE_MAX
+# else
+#  define MAX_IO_SIZE MAX_IO_SIZE_DEFAULT
+# endif
+#endif
 
 /*
  * xread() is the same a read(), but it automatically restarts read()
index b54eac5af6233de183144230259bd317cf24513a..29666d0dbaa5af768aca86f3ca0b644ac9720648 100644 (file)
@@ -1140,7 +1140,7 @@ static char *read_and_strip_branch(const char *path)
        if (strbuf_read_file(&sb, git_path("%s", path), 0) <= 0)
                goto got_nothing;
 
-       while (&sb.len && sb.buf[sb.len - 1] == '\n')
+       while (sb.len && sb.buf[sb.len - 1] == '\n')
                strbuf_setlen(&sb, sb.len - 1);
        if (!sb.len)
                goto got_nothing;