Merge branch 'en/t7406-fixes'
authorJunio C Hamano <gitster@pobox.com>
Mon, 20 Aug 2018 18:33:48 +0000 (11:33 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 20 Aug 2018 18:33:49 +0000 (11:33 -0700)
Test fixes.

* en/t7406-fixes:
  t7406: avoid using test_must_fail for commands other than git
  t7406: prefer test_* helper functions to test -[feds]
  t7406: avoid having git commands upstream of a pipe
  t7406: simplify by using diff --name-only instead of diff --raw
  t7406: fix call that was failing for the wrong reason

215 files changed:
.gitignore
Documentation/.gitignore
Documentation/RelNotes/2.19.0.txt
Documentation/config.txt
Documentation/diff-options.txt
Documentation/doc-diff [new file with mode: 0755]
Documentation/fetch-options.txt
Documentation/git-for-each-ref.txt
Documentation/git-interpret-trailers.txt
Documentation/git-p4.txt
Documentation/git-tag.txt
Documentation/githooks.txt
Documentation/technical/hash-function-transition.txt
Documentation/technical/http-protocol.txt
Documentation/technical/pack-protocol.txt
Makefile
apply.h
archive-tar.c
archive-zip.c
attr.h
banned.h [new file with mode: 0644]
blame.h
builtin/add.c
builtin/blame.c
builtin/checkout.c
builtin/clone.c
builtin/commit.c
builtin/config.c
builtin/difftool.c
builtin/fast-export.c
builtin/fetch.c
builtin/fmt-merge-msg.c
builtin/fsck.c
builtin/grep.c
builtin/index-pack.c
builtin/init-db.c
builtin/log.c
builtin/merge.c
builtin/pack-objects.c
builtin/prune.c
builtin/pull.c
builtin/push.c
builtin/read-tree.c
builtin/remote.c
builtin/replace.c
builtin/rm.c
builtin/send-pack.c
builtin/shortlog.c
builtin/show-branch.c
builtin/unpack-objects.c
builtin/update-index.c
builtin/upload-pack.c
builtin/write-tree.c
cache-tree.h
cache.h
ci/lib-travisci.sh
ci/print-test-failures.sh
ci/run-static-analysis.sh
ci/util/extract-trash-dirs.sh [new file with mode: 0755]
color.c
commit-graph.c
config.c
config.h
config.mak.dev
config.mak.uname
connect.c
contrib/mw-to-git/t/t9360-mw-to-git-clone.sh
contrib/subtree/t/t7900-subtree.sh
contrib/vscode/.gitattributes [new file with mode: 0644]
contrib/vscode/README.md [new file with mode: 0644]
contrib/vscode/init.sh [new file with mode: 0755]
convert.c
convert.h
diff.c
diff.h
diffcore.h
dir.c
environment.c
exec-cmd.c
fetch-negotiator.c
fetch-object.c
fetch-pack.c
git-compat-util.h
git-p4.py
git.c
gpg-interface.c
help.c
http-backend.c
json-writer.c [new file with mode: 0644]
json-writer.h [new file with mode: 0644]
line-range.h
log-tree.c
match-trees.c
merge-recursive.c
object.c
packfile.h
parse-options.c
pkt-line.c
pretty.c
read-cache.c
ref-filter.c
reflog-walk.c
refs.c
refs/files-backend.c
refspec.c
remote.c
replace-object.c
replace-object.h
repository.h
rerere.h
revision.h
sequencer.c
sha1-file.c
sha1collisiondetection
sha1dc/sha1.c
strbuf.c
submodule.h
t/helper/test-json-writer.c [new file with mode: 0644]
t/helper/test-tool.c
t/helper/test-tool.h
t/lib-gpg.sh
t/lib-gpg/gpgsm-gen-key.in [new file with mode: 0644]
t/lib-gpg/gpgsm_cert.p12 [new file with mode: 0644]
t/t0008-ignores.sh
t/t0019-json-writer.sh [new file with mode: 0755]
t/t0019/parse_json.perl [new file with mode: 0644]
t/t0021-conversion.sh
t/t0030-stripspace.sh
t/t0300-credentials.sh
t/t1011-read-tree-sparse-checkout.sh
t/t1015-read-index-unmerged.sh [new file with mode: 0755]
t/t1305-config-include.sh
t/t1306-xdg-files.sh
t/t1308-config-set.sh
t/t1400-update-ref.sh
t/t1403-show-ref.sh
t/t1404-update-ref-errors.sh
t/t1450-fsck.sh
t/t1507-rev-parse-upstream.sh
t/t2024-checkout-dwim.sh
t/t2025-worktree-add.sh
t/t2202-add-addremove.sh
t/t3001-ls-files-others-exclude.sh
t/t3005-ls-files-relative.sh
t/t3031-merge-criscross.sh
t/t3070-wildmatch.sh
t/t3201-branch-contains.sh
t/t3210-pack-refs.sh
t/t3310-notes-merge-manual-resolve.sh
t/t3404-rebase-interactive.sh
t/t3430-rebase-merges.sh
t/t3507-cherry-pick-conflict.sh
t/t3700-add.sh
t/t3910-mac-os-precompose.sh
t/t4010-diff-pathspec.sh
t/t4015-diff-whitespace.sh
t/t4039-diff-assume-unchanged.sh
t/t4150-am.sh
t/t4200-rerere.sh
t/t4202-log.sh
t/t4210-log-i18n.sh
t/t5310-pack-bitmaps.sh
t/t5313-pack-bounds-checks.sh
t/t5500-fetch-pack.sh
t/t5504-fetch-receive-strict.sh
t/t5505-remote.sh
t/t5510-fetch.sh
t/t5512-ls-remote.sh
t/t5514-fetch-multiple.sh
t/t5520-pull.sh
t/t5533-push-cas.sh
t/t5534-push-signed.sh
t/t5551-http-fetch-smart.sh
t/t5552-skipping-fetch-negotiator.sh
t/t5562-http-backend-content-length.sh [new file with mode: 0755]
t/t5562/invoke-with-content-length.pl [new file with mode: 0755]
t/t5570-git-daemon.sh
t/t5612-clone-refspec.sh
t/t5702-protocol-v2.sh
t/t5801-remote-helpers.sh
t/t6000-rev-list-misc.sh
t/t6009-rev-list-parent.sh
t/t6018-rev-list-glob.sh
t/t6019-rev-list-ancestry-path.sh
t/t6020-merge-df.sh
t/t6022-merge-rename.sh
t/t6029-merge-subtree.sh
t/t6042-merge-rename-corner-cases.sh
t/t6050-replace.sh
t/t6060-merge-index.sh
t/t6300-for-each-ref.sh
t/t7004-tag.sh
t/t7006-pager.sh
t/t7030-verify-tag.sh
t/t7063-status-untracked-cache.sh
t/t7102-reset.sh
t/t7106-reset-unborn-branch.sh
t/t7400-submodule-basic.sh
t/t7401-submodule-summary.sh
t/t7406-submodule-update.sh
t/t7502-commit.sh
t/t7510-signed-commit.sh
t/t7610-mergetool.sh
t/t7810-grep.sh
t/t9001-send-email.sh
t/t9300-fast-import.sh
t/t9800-git-p4-basic.sh
transport-helper.c
transport-internal.h
transport.c
transport.h
utf8.c
utf8.h
xdiff/xdiffi.c
xdiff/xhistogram.c

index 3284a1e..3524803 100644 (file)
 /config.mak.autogen
 /config.mak.append
 /configure
+/.vscode/
 /tags
 /TAGS
 /cscope*
index c7096f1..3ef54e0 100644 (file)
@@ -12,3 +12,4 @@ cmds-*.txt
 mergetools-*.txt
 manpage-base-url.xsl
 SubmittingPatches.txt
+tmp-doc-diff/
index 8a03613..8f8da9f 100644 (file)
@@ -50,6 +50,29 @@ UI, Workflows & Features
    ancestor discovery during the "git fetch" transaction.
    (merge 42cc7485a2 jt/fetch-negotiator-skipping later to maint).
 
+ * A new configuration variable core.usereplacerefs has been added,
+   primarily to help server installations that want to ignore the
+   replace mechanism altogether.
+
+ * Teach "git tag -s" etc. a few configuration variables (gpg.format
+   that can be set to "openpgp" or "x509", and gpg.<format>.program
+   that is used to specify what program to use to deal with the format)
+   to allow x.509 certs with CMS via "gpgsm" to be used instead of
+   openpgp via "gnupg".
+
+ * Many more strings are prepared for l10n.
+
+ * "git p4 submit" learns to ask its own pre-submit hook if it should
+   continue with submitting.
+
+ * The test performed at the receiving end of "git push" to prevent
+   bad objects from entering repository can be customized via
+   receive.fsck.* configuration variables; we now have gained a
+   counterpart to do the same on the "git fetch" side, with
+   fetch.fsck.* configuration variables.
+
+ * "git pull --rebase=interactive" learned "i" as a short-hand for
+   "interactive".
 
 Performance, Internal Implementation, Development Support etc.
 
@@ -157,6 +180,46 @@ Performance, Internal Implementation, Development Support etc.
  * The singleton commit-graph in-core instance is made per in-core
    repository instance.
 
+ * "make DEVELOPER=1 DEVOPTS=pedantic" allows developers to compile
+   with -pedantic option, which may catch more problematic program
+   constructs and potential bugs.
+
+ * Preparatory code to later add json output for telemetry data has
+   been added.
+
+ * Update the way we use Coccinelle to find out-of-style code that
+   need to be modernised.
+
+ * It is too easy to misuse system API functions such as strcat();
+   these selected functions are now forbidden in this codebase and
+   will cause a compilation failure.
+
+ * Add a script (in contrib/) to help users of VSCode work better with
+   our codebase.
+
+ * The Travis CI scripts were taught to ship back the test data from
+   failed tests.
+   (merge aea8879a6a sg/travis-retrieve-trash-upon-failure later to maint).
+
+ * The parse-options machinery learned to refrain from enclosing
+   placeholder string inside a "<bra" and "ket>" pair automatically
+   without PARSE_OPT_LITERAL_ARGHELP.  Existing help text for option
+   arguments that are not formatted correctly have been identified and
+   fixed.
+   (merge 5f0df44cd7 rs/parse-opt-lithelp later to maint).
+
+ * Noiseword "extern" has been removed from function decls in the
+   header files.
+
+ * A few atoms like %(objecttype) and %(objectsize) in the format
+   specifier of "for-each-ref --format=<format>" can be filled without
+   getting the full contents of the object, but just with the object
+   header.  These cases have been optimized by calling
+   oid_object_info() API (instead of reading and inspecting the data).
+
+ * The end result of documentation update has been made to be
+   inspected more easily to help developers.
+
 
 Fixes since v2.18
 -----------------
@@ -329,6 +392,73 @@ Fixes since v2.18
  * The lazy clone support had a few places where missing but promised
    objects were not correctly tolerated, which have been fixed.
 
+ * One of the "diff --color-moved" mode "dimmed_zebra" that was named
+   in an unusual way has been deprecated and replaced by
+   "dimmed-zebra".
+   (merge e3f2f5f9cd es/diff-color-moved-fix later to maint).
+
+ * The wire-protocol v2 relies on the client to send "ref prefixes" to
+   limit the bandwidth spent on the initial ref advertisement.  "git
+   clone" when learned to speak v2 forgot to do so, which has been
+   corrected.
+   (merge 402c47d939 bw/clone-ref-prefixes later to maint).
+
+ * "git diff --histogram" had a bad memory usage pattern, which has
+   been rearranged to reduce the peak usage.
+   (merge 79cb2ebb92 sb/histogram-less-memory later to maint).
+
+ * Code clean-up to use size_t/ssize_t when they are the right type.
+   (merge 7726d360b5 jk/size-t later to maint).
+
+ * The wire-protocol v2 relies on the client to send "ref prefixes" to
+   limit the bandwidth spent on the initial ref advertisement.  "git
+   fetch $remote branch:branch" that asks tags that point into the
+   history leading to the "branch" automatically followed sent to
+   narrow prefix and broke the tag following, which has been fixed.
+   (merge 2b554353a5 jt/tag-following-with-proto-v2-fix later to maint).
+
+ * When the sparse checkout feature is in use, "git cherry-pick" and
+   other mergy operations lost the skip_worktree bit when a path that
+   is excluded from checkout requires content level merge, which is
+   resolved as the same as the HEAD version, without materializing the
+   merge result in the working tree, which made the path appear as
+   deleted.  This has been corrected by preserving the skip_worktree
+   bit (and not materializing the file in the working tree).
+   (merge 2b75fb601c en/merge-recursive-skip-fix later to maint).
+
+ * The "author-script" file "git rebase -i" creates got broken when
+   we started to move the command away from shell script, which is
+   getting fixed now.
+   (merge 5522bbac20 es/rebase-i-author-script-fix later to maint).
+
+ * The automatic tree-matching in "git merge -s subtree" was broken 5
+   years ago and nobody has noticed since then, which is now fixed.
+   (merge 2ec4150713 jk/merge-subtree-heuristics later to maint).
+
+ * "git fetch $there refs/heads/s" ought to fetch the tip of the
+   branch 's', but when "refs/heads/refs/heads/s", i.e. a branch whose
+   name is "refs/heads/s" exists at the same time, fetched that one
+   instead by mistake.  This has been corrected to honor the usual
+   disambiguation rules for abbreviated refnames.
+   (merge 60650a48c0 jt/refspec-dwim-precedence-fix later to maint).
+
+ * Futureproofing a helper function that can easily be misused.
+   (merge 65bb21e77e es/want-color-fd-defensive later to maint).
+
+ * The http-backend (used for smart-http transport) used to slurp the
+   whole input until EOF, without paying attention to CONTENT_LENGTH
+   that is supplied in the environment and instead expecting the Web
+   server to close the input stream.  This has been fixed.
+   (merge eebfe40962 mk/http-backend-content-length later to maint).
+
+ * "git merge --abort" etc. did not clean things up properly when
+   there were conflicted entries in the index in certain order that
+   are involved in D/F conflicts.  This has been corrected.
+   (merge ad3762042a en/abort-df-conflict-fixes later to maint).
+
+ * "git diff --indent-heuristic" had a bad corner case performance.
+   (merge 301ef85401 sb/indent-heuristic-optim later to maint).
+
  * Code cleanup, docfix, build fix, etc.
    (merge aee9be2ebe sg/update-ref-stdin-cleanup later to maint).
    (merge 037714252f jc/clean-after-sanity-tests later to maint).
@@ -344,3 +474,14 @@ Fixes since v2.18
    (merge 6aaded5509 tb/config-default later to maint).
    (merge 022d2ac1f3 sb/blame-color later to maint).
    (merge 5a06a20e0c bp/test-drop-caches-for-windows later to maint).
+   (merge dd61cc1c2e jk/ui-color-always-to-auto later to maint).
+   (merge 1e83b9bfdd sb/trailers-docfix later to maint).
+   (merge ab29f1b329 sg/fast-import-dump-refs-on-checkpoint-fix later to maint).
+   (merge 6a8ad880f0 jn/subtree-test-fixes later to maint).
+   (merge ffbd51cc60 nd/pack-objects-threading-doc later to maint).
+   (merge e9dac7be60 es/mw-to-git-chain-fix later to maint).
+   (merge fe583c6c7a rs/remote-mv-leakfix later to maint).
+   (merge 69885ab015 en/t3031-title-fix later to maint).
+   (merge 8578037bed nd/config-blame-sort later to maint).
+   (merge 8ad169c4ba hn/config-in-code-comment later to maint).
+   (merge b7446fcfdf ar/t4150-am-scissors-test-fix later to maint).
index 63365dc..95ad715 100644 (file)
@@ -924,6 +924,11 @@ gc.commitGraph::
        required. Default is false. See linkgit:git-commit-graph[1]
        for details.
 
+core.useReplaceRefs::
+       If set to `false`, behave as if the `--no-replace-objects`
+       option was given on the command line. See linkgit:git[1] and
+       linkgit:git-replace[1] for more information.
+
 core.sparseCheckout::
        Enable "sparse checkout" feature. See section "Sparse checkout" in
        linkgit:git-read-tree[1] for more information.
@@ -990,23 +995,28 @@ apply.whitespace::
        Tells 'git apply' how to handle whitespaces, in the same way
        as the `--whitespace` option. See linkgit:git-apply[1].
 
-blame.showRoot::
-       Do not treat root commits as boundaries in linkgit:git-blame[1].
-       This option defaults to false.
-
 blame.blankBoundary::
        Show blank commit object name for boundary commits in
        linkgit:git-blame[1]. This option defaults to false.
 
-blame.showEmail::
-       Show the author email instead of author name in linkgit:git-blame[1].
-       This option defaults to false.
+blame.coloring::
+       This determines the coloring scheme to be applied to blame
+       output. It can be 'repeatedLines', 'highlightRecent',
+       or 'none' which is the default.
 
 blame.date::
        Specifies the format used to output dates in linkgit:git-blame[1].
        If unset the iso format is used. For supported values,
        see the discussion of the `--date` option at linkgit:git-log[1].
 
+blame.showEmail::
+       Show the author email instead of author name in linkgit:git-blame[1].
+       This option defaults to false.
+
+blame.showRoot::
+       Do not treat root commits as boundaries in linkgit:git-blame[1].
+       This option defaults to false.
+
 branch.autoSetupMerge::
        Tells 'git branch' and 'git checkout' to set up new branches
        so that linkgit:git-pull[1] will appropriately merge from the
@@ -1144,6 +1154,28 @@ color.advice::
 color.advice.hint::
        Use customized color for hints.
 
+color.blame.highlightRecent::
+       This can be used to color the metadata of a blame line depending
+       on age of the line.
++
+This setting should be set to a comma-separated list of color and date settings,
+starting and ending with a color, the dates should be set from oldest to newest.
+The metadata will be colored given the colors if the the line was introduced
+before the given timestamp, overwriting older timestamped colors.
++
+Instead of an absolute timestamp relative timestamps work as well, e.g.
+2.weeks.ago is valid to address anything older than 2 weeks.
++
+It defaults to 'blue,12 month ago,white,1 month ago,red', which colors
+everything older than one year blue, recent changes between one month and
+one year old are kept white, and lines introduced within the last month are
+colored red.
+
+color.blame.repeatedLines::
+       Use the customized color for the part of git-blame output that
+       is repeated meta information per line (such as commit id,
+       author name, date and timezone). Defaults to cyan.
+
 color.branch::
        A boolean to enable/disable color in the output of
        linkgit:git-branch[1]. May be set to `always`,
@@ -1291,33 +1323,6 @@ color.status.<slot>::
        status short-format), or
        `unmerged` (files which have unmerged changes).
 
-color.blame.repeatedLines::
-       Use the customized color for the part of git-blame output that
-       is repeated meta information per line (such as commit id,
-       author name, date and timezone). Defaults to cyan.
-
-color.blame.highlightRecent::
-       This can be used to color the metadata of a blame line depending
-       on age of the line.
-+
-This setting should be set to a comma-separated list of color and date settings,
-starting and ending with a color, the dates should be set from oldest to newest.
-The metadata will be colored given the colors if the the line was introduced
-before the given timestamp, overwriting older timestamped colors.
-+
-Instead of an absolute timestamp relative timestamps work as well, e.g.
-2.weeks.ago is valid to address anything older than 2 weeks.
-+
-It defaults to 'blue,12 month ago,white,1 month ago,red', which colors
-everything older than one year blue, recent changes between one month and
-one year old are kept white, and lines introduced within the last month are
-colored red.
-
-blame.coloring::
-       This determines the coloring scheme to be applied to blame
-       output. It can be 'repeatedLines', 'highlightRecent',
-       or 'none' which is the default.
-
 color.transport::
        A boolean to enable/disable color when pushes are rejected. May be
        set to `always`, `false` (or `never`) or `auto` (or `true`), in which
@@ -1497,10 +1502,19 @@ fetch.recurseSubmodules::
 
 fetch.fsckObjects::
        If it is set to true, git-fetch-pack will check all fetched
-       objects. It will abort in the case of a malformed object or a
-       broken link. The result of an abort are only dangling objects.
-       Defaults to false. If not set, the value of `transfer.fsckObjects`
-       is used instead.
+       objects. See `transfer.fsckObjects` for what's
+       checked. Defaults to false. If not set, the value of
+       `transfer.fsckObjects` is used instead.
+
+fetch.fsck.<msg-id>::
+       Acts like `fsck.<msg-id>`, but is used by
+       linkgit:git-fetch-pack[1] instead of linkgit:git-fsck[1]. See
+       the `fsck.<msg-id>` documentation for details.
+
+fetch.fsck.skipList::
+       Acts like `fsck.skipList`, but is used by
+       linkgit:git-fetch-pack[1] instead of linkgit:git-fsck[1]. See
+       the `fsck.skipList` documentation for details.
 
 fetch.unpackLimit::
        If the number of objects fetched over the Git native
@@ -1536,9 +1550,12 @@ fetch.negotiationAlgorithm::
        sent when negotiating the contents of the packfile to be sent by the
        server. Set to "skipping" to use an algorithm that skips commits in an
        effort to converge faster, but may result in a larger-than-necessary
-       packfile; any other value instructs Git to use the default algorithm
+       packfile; The default is "default" which instructs Git to use the default algorithm
        that never skips commits (unless the server has acknowledged it or one
        of its descendants).
+       Unknown values will cause 'git fetch' to error out.
++
+See also the `--negotiation-tip` option for linkgit:git-fetch[1].
 
 format.attach::
        Enable multipart/mixed attachments as the default for
@@ -1639,15 +1656,42 @@ filter.<driver>.smudge::
        linkgit:gitattributes[5] for details.
 
 fsck.<msg-id>::
-       Allows overriding the message type (error, warn or ignore) of a
-       specific message ID such as `missingEmail`.
-+
-For convenience, fsck prefixes the error/warning with the message ID,
-e.g.  "missingEmail: invalid author/committer line - missing email" means
-that setting `fsck.missingEmail = ignore` will hide that issue.
-+
-This feature is intended to support working with legacy repositories
-which cannot be repaired without disruptive changes.
+       During fsck git may find issues with legacy data which
+       wouldn't be generated by current versions of git, and which
+       wouldn't be sent over the wire if `transfer.fsckObjects` was
+       set. This feature is intended to support working with legacy
+       repositories containing such data.
++
+Setting `fsck.<msg-id>` will be picked up by linkgit:git-fsck[1], but
+to accept pushes of such data set `receive.fsck.<msg-id>` instead, or
+to clone or fetch it set `fetch.fsck.<msg-id>`.
++
+The rest of the documentation discusses `fsck.*` for brevity, but the
+same applies for the corresponding `receive.fsck.*` and
+`fetch.<msg-id>.*`. variables.
++
+Unlike variables like `color.ui` and `core.editor` the
+`receive.fsck.<msg-id>` and `fetch.fsck.<msg-id>` variables will not
+fall back on the `fsck.<msg-id>` configuration if they aren't set. To
+uniformly configure the same fsck settings in different circumstances
+all three of them they must all set to the same values.
++
+When `fsck.<msg-id>` is set, errors can be switched to warnings and
+vice versa by configuring the `fsck.<msg-id>` setting where the
+`<msg-id>` is the fsck message ID and the value is one of `error`,
+`warn` or `ignore`. For convenience, fsck prefixes the error/warning
+with the message ID, e.g. "missingEmail: invalid author/committer line
+- missing email" means that setting `fsck.missingEmail = ignore` will
+hide that issue.
++
+In general, it is better to enumerate existing objects with problems
+with `fsck.skipList`, instead of listing the kind of breakages these
+problematic objects share to be ignored, as doing the latter will
+allow new instances of the same breakages go unnoticed.
++
+Setting an unknown `fsck.<msg-id>` value will cause fsck to die, but
+doing the same for `receive.fsck.<msg-id>` and `fetch.fsck.<msg-id>`
+will only cause git to warn.
 
 fsck.skipList::
        The path to a sorted list of object names (i.e. one SHA-1 per
@@ -1656,6 +1700,15 @@ fsck.skipList::
        should be accepted despite early commits containing errors that
        can be safely ignored such as invalid committer email addresses.
        Note: corrupt objects cannot be skipped with this setting.
++
+Like `fsck.<msg-id>` this variable has corresponding
+`receive.fsck.skipList` and `fetch.fsck.skipList` variants.
++
+Unlike variables like `color.ui` and `core.editor` the
+`receive.fsck.skipList` and `fetch.fsck.skipList` variables will not
+fall back on the `fsck.skipList` configuration if they aren't set. To
+uniformly configure the same fsck settings in different circumstances
+all three of them they must all set to the same values.
 
 gc.aggressiveDepth::
        The depth parameter used in the delta compression
@@ -1879,6 +1932,16 @@ gpg.program::
        signed, and the program is expected to send the result to its
        standard output.
 
+gpg.format::
+       Specifies which key format to use when signing with `--gpg-sign`.
+       Default is "openpgp" and another possible value is "x509".
+
+gpg.<format>.program::
+       Use this to customize the program used for the signing format you
+       chose. (see `gpg.program` and `gpg.format`) `gpg.program` can still
+       be used as a legacy synonym for `gpg.openpgp.program`. The default
+       value for `gpg.x509.program` is "gpgsm".
+
 gui.commitMsgWidth::
        Defines how wide the commit message window is in the
        linkgit:git-gui[1]. "75" is the default.
@@ -2932,32 +2995,21 @@ receive.certNonceSlop::
 
 receive.fsckObjects::
        If it is set to true, git-receive-pack will check all received
-       objects. It will abort in the case of a malformed object or a
-       broken link. The result of an abort are only dangling objects.
-       Defaults to false. If not set, the value of `transfer.fsckObjects`
-       is used instead.
+       objects. See `transfer.fsckObjects` for what's checked.
+       Defaults to false. If not set, the value of
+       `transfer.fsckObjects` is used instead.
 
 receive.fsck.<msg-id>::
-       When `receive.fsckObjects` is set to true, errors can be switched
-       to warnings and vice versa by configuring the `receive.fsck.<msg-id>`
-       setting where the `<msg-id>` is the fsck message ID and the value
-       is one of `error`, `warn` or `ignore`. For convenience, fsck prefixes
-       the error/warning with the message ID, e.g. "missingEmail: invalid
-       author/committer line - missing email" means that setting
-       `receive.fsck.missingEmail = ignore` will hide that issue.
-+
-This feature is intended to support working with legacy repositories
-which would not pass pushing when `receive.fsckObjects = true`, allowing
-the host to accept repositories with certain known issues but still catch
-other issues.
+       Acts like `fsck.<msg-id>`, but is used by
+       linkgit:git-receive-pack[1] instead of
+       linkgit:git-fsck[1]. See the `fsck.<msg-id>` documentation for
+       details.
 
 receive.fsck.skipList::
-       The path to a sorted list of object names (i.e. one SHA-1 per
-       line) that are known to be broken in a non-fatal way and should
-       be ignored. This feature is useful when an established project
-       should be accepted despite early commits containing errors that
-       can be safely ignored such as invalid committer email addresses.
-       Note: corrupt objects cannot be skipped with this setting.
+       Acts like `fsck.skipList`, but is used by
+       linkgit:git-receive-pack[1] instead of
+       linkgit:git-fsck[1]. See the `fsck.skipList` documentation for
+       details.
 
 receive.keepAlive::
        After receiving the pack from the client, `receive-pack` may
@@ -3432,6 +3484,40 @@ transfer.fsckObjects::
        When `fetch.fsckObjects` or `receive.fsckObjects` are
        not set, the value of this variable is used instead.
        Defaults to false.
++
+When set, the fetch or receive will abort in the case of a malformed
+object or a link to a nonexistent object. In addition, various other
+issues are checked for, including legacy issues (see `fsck.<msg-id>`),
+and potential security issues like the existence of a `.GIT` directory
+or a malicious `.gitmodules` file (see the release notes for v2.2.1
+and v2.17.1 for details). Other sanity and security checks may be
+added in future releases.
++
+On the receiving side, failing fsckObjects will make those objects
+unreachable, see "QUARANTINE ENVIRONMENT" in
+linkgit:git-receive-pack[1]. On the fetch side, malformed objects will
+instead be left unreferenced in the repository.
++
+Due to the non-quarantine nature of the `fetch.fsckObjects`
+implementation it can not be relied upon to leave the object store
+clean like `receive.fsckObjects` can.
++
+As objects are unpacked they're written to the object store, so there
+can be cases where malicious objects get introduced even though the
+"fetch" failed, only to have a subsequent "fetch" succeed because only
+new incoming objects are checked, not those that have already been
+written to the object store. That difference in behavior should not be
+relied upon. In the future, such objects may be quarantined for
+"fetch" as well.
++
+For now, the paranoid need to find some way to emulate the quarantine
+environment if they'd like the same protection as "push". E.g. in the
+case of an internal mirror do the mirroring in two steps, one to fetch
+the untrusted objects, and then do a second "push" (which will use the
+quarantine) to another internal repo, and have internal clients
+consume this pushed-to repository, or embargo internal fetches and
+only allow them once a full "fsck" has run (and no new fetches have
+happened in the meantime).
 
 transfer.hideRefs::
        String(s) `receive-pack` and `upload-pack` use to decide which
index f394608..0378cd5 100644 (file)
@@ -286,10 +286,11 @@ zebra::
        are painted using either the 'color.diff.{old,new}Moved' color or
        'color.diff.{old,new}MovedAlternative'. The change between
        the two colors indicates that a new block was detected.
-dimmed_zebra::
+dimmed-zebra::
        Similar to 'zebra', but additional dimming of uninteresting parts
        of moved code is performed. The bordering lines of two adjacent
        blocks are considered interesting, the rest is uninteresting.
+       `dimmed_zebra` is a deprecated synonym.
 --
 
 --color-moved-ws=<modes>::
diff --git a/Documentation/doc-diff b/Documentation/doc-diff
new file mode 100755 (executable)
index 0000000..f483fe4
--- /dev/null
@@ -0,0 +1,109 @@
+#!/bin/sh
+
+OPTIONS_SPEC="\
+doc-diff [options] <from> <to> [-- <diff-options>]
+--
+j=n    parallel argument to pass to make
+f      force rebuild; do not rely on cached results
+"
+SUBDIRECTORY_OK=1
+. "$(git --exec-path)/git-sh-setup"
+
+parallel=
+force=
+while test $# -gt 0
+do
+       case "$1" in
+       -j)
+               parallel=$2; shift ;;
+       -f)
+               force=t ;;
+       --)
+               shift; break ;;
+       *)
+               usage ;;
+       esac
+       shift
+done
+
+if test -z "$parallel"
+then
+       parallel=$(getconf _NPROCESSORS_ONLN 2>/dev/null)
+       if test $? != 0 || test -z "$parallel"
+       then
+               parallel=1
+       fi
+fi
+
+test $# -gt 1 || usage
+from=$1; shift
+to=$1; shift
+
+from_oid=$(git rev-parse --verify "$from") || exit 1
+to_oid=$(git rev-parse --verify "$to") || exit 1
+
+cd_to_toplevel
+tmp=Documentation/tmp-doc-diff
+
+if test -n "$force"
+then
+       rm -rf "$tmp"
+fi
+
+# We'll do both builds in a single worktree, which lets "make" reuse
+# results that don't differ between the two trees.
+if ! test -d "$tmp/worktree"
+then
+       git worktree add --detach "$tmp/worktree" "$from" &&
+       dots=$(echo "$tmp/worktree" | sed 's#[^/]*#..#g') &&
+       ln -s "$dots/config.mak" "$tmp/worktree/config.mak"
+fi
+
+# generate_render_makefile <srcdir> <dstdir>
+generate_render_makefile () {
+       find "$1" -type f |
+       while read src
+       do
+               dst=$2/${src#$1/}
+               printf 'all:: %s\n' "$dst"
+               printf '%s: %s\n' "$dst" "$src"
+               printf '\t@echo >&2 "  RENDER $(notdir $@)" && \\\n'
+               printf '\tmkdir -p $(dir $@) && \\\n'
+               printf '\tMANWIDTH=80 man -l $< >$@+ && \\\n'
+               printf '\tmv $@+ $@\n'
+       done
+}
+
+# render_tree <dirname> <committish>
+render_tree () {
+       # Skip install-man entirely if we already have an installed directory.
+       # We can't rely on make here, since "install-man" unconditionally
+       # copies the files (spending effort, but also updating timestamps that
+       # we then can't rely on during the render step). We use "mv" to make
+       # sure we don't get confused by a previous run that failed partway
+       # through.
+       if ! test -d "$tmp/installed/$1"
+       then
+               git -C "$tmp/worktree" checkout "$2" &&
+               make -j$parallel -C "$tmp/worktree" \
+                       GIT_VERSION=omitted \
+                       SOURCE_DATE_EPOCH=0 \
+                       DESTDIR="$PWD/$tmp/installed/$1+" \
+                       install-man &&
+               mv "$tmp/installed/$1+" "$tmp/installed/$1"
+       fi &&
+
+       # As with "installed" above, we skip the render if it's already been
+       # done.  So using make here is primarily just about running in
+       # parallel.
+       if ! test -d "$tmp/rendered/$1"
+       then
+               generate_render_makefile "$tmp/installed/$1" "$tmp/rendered/$1+" |
+               make -j$parallel -f - &&
+               mv "$tmp/rendered/$1+" "$tmp/rendered/$1"
+       fi
+}
+
+render_tree $from_oid "$from" &&
+render_tree $to_oid "$to" &&
+git -C $tmp/rendered diff --no-index "$@" $from_oid $to_oid
index 2d09f87..8bc36af 100644 (file)
@@ -57,6 +57,9 @@ commits reachable from any of the given commits.
 The argument to this option may be a glob on ref names, a ref, or the (possibly
 abbreviated) SHA-1 of a commit. Specifying a glob is equivalent to specifying
 this option multiple times, one for each matching ref name.
++
+See also the `fetch.negotiationAlgorithm` configuration variable
+documented in linkgit:git-config[1].
 
 ifndef::git-pull[]
 --dry-run::
index 085d177..901faef 100644 (file)
@@ -57,7 +57,7 @@ OPTIONS
        `xx`; for example `%00` interpolates to `\0` (NUL),
        `%09` to `\t` (TAB) and `%0a` to `\n` (LF).
 
---color[=<when>]:
+--color[=<when>]::
        Respect any colors specified in the `--format` option. The
        `<when>` field must be one of `always`, `never`, or `auto` (if
        `<when>` is absent, behave as if `always` was given).
index 9111c47..b8fafb1 100644 (file)
@@ -88,7 +88,8 @@ OPTIONS
        Specify where all new trailers will be added.  A setting
        provided with '--where' overrides all configuration variables
        and applies to all '--trailer' options until the next occurrence of
-       '--where' or '--no-where'.
+       '--where' or '--no-where'. Possible values are `after`, `before`,
+       `end` or `start`.
 
 --if-exists <action>::
 --no-if-exists::
@@ -96,7 +97,8 @@ OPTIONS
        least one trailer with the same <token> in the message.  A setting
        provided with '--if-exists' overrides all configuration variables
        and applies to all '--trailer' options until the next occurrence of
-       '--if-exists' or '--no-if-exists'.
+       '--if-exists' or '--no-if-exists'. Possible actions are `addIfDifferent`,
+       `addIfDifferentNeighbor`, `add`, `replace` and `doNothing`.
 
 --if-missing <action>::
 --no-if-missing::
@@ -104,7 +106,8 @@ OPTIONS
        trailer with the same <token> in the message.  A setting
        provided with '--if-missing' overrides all configuration variables
        and applies to all '--trailer' options until the next occurrence of
-       '--if-missing' or '--no-if-missing'.
+       '--if-missing' or '--no-if-missing'. Possible actions are `doNothing`
+       or `add`.
 
 --only-trailers::
        Output only the trailers, not any other parts of the input.
index f0de3b8..41780a5 100644 (file)
@@ -374,6 +374,14 @@ These options can be used to modify 'git p4 submit' behavior.
     been submitted. Implies --disable-rebase. Can also be set with
     git-p4.disableP4Sync. Sync with origin/master still goes ahead if possible.
 
+Hook for submit
+~~~~~~~~~~~~~~~
+The `p4-pre-submit` hook is executed if it exists and is executable.
+The hook takes no parameters and nothing from standard input. Exiting with
+non-zero status from this script prevents `git-p4 submit` from launching.
+
+One usage scenario is to run unit tests in the hook.
+
 Rebase options
 ~~~~~~~~~~~~~~
 These options can be used to modify 'git p4 rebase' behavior.
index 87c4288..92f9c12 100644 (file)
@@ -115,7 +115,7 @@ options for details.
        variable if it exists, or lexicographic order otherwise. See
        linkgit:git-config[1].
 
---color[=<when>]:
+--color[=<when>]::
        Respect any colors specified in the `--format` option. The
        `<when>` field must be one of `always`, `never`, or `auto` (if
        `<when>` is absent, behave as if `always` was given).
index e3c283a..9590443 100644 (file)
@@ -485,6 +485,13 @@ The exit status determines whether git will use the data from the
 hook to limit its search.  On error, it will fall back to verifying
 all files and folders.
 
+p4-pre-submit
+~~~~~~~~~~~~~
+
+This hook is invoked by `git-p4 submit`. It takes no parameters and nothing
+from standard input. Exiting with non-zero status from this script prevent
+`git-p4 submit` from launching. Run `git-p4 submit --help` for details.
+
 GIT
 ---
 Part of the linkgit:git[1] suite
index 4ab6cd1..bc2ace2 100644 (file)
@@ -59,14 +59,11 @@ that are believed to be cryptographically secure.
 
 Goals
 -----
-Where NewHash is a strong 256-bit hash function to replace SHA-1 (see
-"Selection of a New Hash", below):
-
-1. The transition to NewHash can be done one local repository at a time.
+1. The transition to SHA-256 can be done one local repository at a time.
    a. Requiring no action by any other party.
-   b. A NewHash repository can communicate with SHA-1 Git servers
+   b. A SHA-256 repository can communicate with SHA-1 Git servers
       (push/fetch).
-   c. Users can use SHA-1 and NewHash identifiers for objects
+   c. Users can use SHA-1 and SHA-256 identifiers for objects
       interchangeably (see "Object names on the command line", below).
    d. New signed objects make use of a stronger hash function than
       SHA-1 for their security guarantees.
@@ -79,7 +76,7 @@ Where NewHash is a strong 256-bit hash function to replace SHA-1 (see
 
 Non-Goals
 ---------
-1. Add NewHash support to Git protocol. This is valuable and the
+1. Add SHA-256 support to Git protocol. This is valuable and the
    logical next step but it is out of scope for this initial design.
 2. Transparently improving the security of existing SHA-1 signed
    objects.
@@ -87,26 +84,26 @@ Non-Goals
    repository.
 4. Taking the opportunity to fix other bugs in Git's formats and
    protocols.
-5. Shallow clones and fetches into a NewHash repository. (This will
-   change when we add NewHash support to Git protocol.)
-6. Skip fetching some submodules of a project into a NewHash
-   repository. (This also depends on NewHash support in Git
+5. Shallow clones and fetches into a SHA-256 repository. (This will
+   change when we add SHA-256 support to Git protocol.)
+6. Skip fetching some submodules of a project into a SHA-256
+   repository. (This also depends on SHA-256 support in Git
    protocol.)
 
 Overview
 --------
 We introduce a new repository format extension. Repositories with this
-extension enabled use NewHash instead of SHA-1 to name their objects.
+extension enabled use SHA-256 instead of SHA-1 to name their objects.
 This affects both object names and object content --- both the names
 of objects and all references to other objects within an object are
 switched to the new hash function.
 
-NewHash repositories cannot be read by older versions of Git.
+SHA-256 repositories cannot be read by older versions of Git.
 
-Alongside the packfile, a NewHash repository stores a bidirectional
-mapping between NewHash and SHA-1 object names. The mapping is generated
+Alongside the packfile, a SHA-256 repository stores a bidirectional
+mapping between SHA-256 and SHA-1 object names. The mapping is generated
 locally and can be verified using "git fsck". Object lookups use this
-mapping to allow naming objects using either their SHA-1 and NewHash names
+mapping to allow naming objects using either their SHA-1 and SHA-256 names
 interchangeably.
 
 "git cat-file" and "git hash-object" gain options to display an object
@@ -116,7 +113,7 @@ object database so that they can be named using the appropriate name
 (using the bidirectional hash mapping).
 
 Fetches from a SHA-1 based server convert the fetched objects into
-NewHash form and record the mapping in the bidirectional mapping table
+SHA-256 form and record the mapping in the bidirectional mapping table
 (see below for details). Pushes to a SHA-1 based server convert the
 objects being pushed into sha1 form so the server does not have to be
 aware of the hash function the client is using.
@@ -125,19 +122,19 @@ Detailed Design
 ---------------
 Repository format extension
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
-A NewHash repository uses repository format version `1` (see
+A SHA-256 repository uses repository format version `1` (see
 Documentation/technical/repository-version.txt) with extensions
 `objectFormat` and `compatObjectFormat`:
 
        [core]
                repositoryFormatVersion = 1
        [extensions]
-               objectFormat = newhash
+               objectFormat = sha256
                compatObjectFormat = sha1
 
 The combination of setting `core.repositoryFormatVersion=1` and
 populating `extensions.*` ensures that all versions of Git later than
-`v0.99.9l` will die instead of trying to operate on the NewHash
+`v0.99.9l` will die instead of trying to operate on the SHA-256
 repository, instead producing an error message.
 
        # Between v0.99.9l and v2.7.0
@@ -155,36 +152,36 @@ repository extensions.
 Object names
 ~~~~~~~~~~~~
 Objects can be named by their 40 hexadecimal digit sha1-name or 64
-hexadecimal digit newhash-name, plus names derived from those (see
+hexadecimal digit sha256-name, plus names derived from those (see
 gitrevisions(7)).
 
 The sha1-name of an object is the SHA-1 of the concatenation of its
 type, length, a nul byte, and the object's sha1-content. This is the
 traditional <sha1> used in Git to name objects.
 
-The newhash-name of an object is the NewHash of the concatenation of its
-type, length, a nul byte, and the object's newhash-content.
+The sha256-name of an object is the SHA-256 of the concatenation of its
+type, length, a nul byte, and the object's sha256-content.
 
 Object format
 ~~~~~~~~~~~~~
 The content as a byte sequence of a tag, commit, or tree object named
-by sha1 and newhash differ because an object named by newhash-name refers to
-other objects by their newhash-names and an object named by sha1-name
+by sha1 and sha256 differ because an object named by sha256-name refers to
+other objects by their sha256-names and an object named by sha1-name
 refers to other objects by their sha1-names.
 
-The newhash-content of an object is the same as its sha1-content, except
-that objects referenced by the object are named using their newhash-names
+The sha256-content of an object is the same as its sha1-content, except
+that objects referenced by the object are named using their sha256-names
 instead of sha1-names. Because a blob object does not refer to any
-other object, its sha1-content and newhash-content are the same.
+other object, its sha1-content and sha256-content are the same.
 
-The format allows round-trip conversion between newhash-content and
+The format allows round-trip conversion between sha256-content and
 sha1-content.
 
 Object storage
 ~~~~~~~~~~~~~~
 Loose objects use zlib compression and packed objects use the packed
 format described in Documentation/technical/pack-format.txt, just like
-today. The content that is compressed and stored uses newhash-content
+today. The content that is compressed and stored uses sha256-content
 instead of sha1-content.
 
 Pack index
@@ -255,10 +252,10 @@ network byte order):
   up to and not including the table of CRC32 values.
 - Zero or more NUL bytes.
 - The trailer consists of the following:
-  - A copy of the 20-byte NewHash checksum at the end of the
+  - A copy of the 20-byte SHA-256 checksum at the end of the
     corresponding packfile.
 
-  - 20-byte NewHash checksum of all of the above.
+  - 20-byte SHA-256 checksum of all of the above.
 
 Loose object index
 ~~~~~~~~~~~~~~~~~~
@@ -266,7 +263,7 @@ A new file $GIT_OBJECT_DIR/loose-object-idx contains information about
 all loose objects. Its format is
 
   # loose-object-idx
-  (newhash-name SP sha1-name LF)*
+  (sha256-name SP sha1-name LF)*
 
 where the object names are in hexadecimal format. The file is not
 sorted.
@@ -292,8 +289,8 @@ To remove entries (e.g. in "git pack-refs" or "git-prune"):
 Translation table
 ~~~~~~~~~~~~~~~~~
 The index files support a bidirectional mapping between sha1-names
-and newhash-names. The lookup proceeds similarly to ordinary object
-lookups. For example, to convert a sha1-name to a newhash-name:
+and sha256-names. The lookup proceeds similarly to ordinary object
+lookups. For example, to convert a sha1-name to a sha256-name:
 
  1. Look for the object in idx files. If a match is present in the
     idx's sorted list of truncated sha1-names, then:
@@ -301,8 +298,8 @@ lookups. For example, to convert a sha1-name to a newhash-name:
        name order mapping.
     b. Read the corresponding entry in the full sha1-name table to
        verify we found the right object. If it is, then
-    c. Read the corresponding entry in the full newhash-name table.
-       That is the object's newhash-name.
+    c. Read the corresponding entry in the full sha256-name table.
+       That is the object's sha256-name.
  2. Check for a loose object. Read lines from loose-object-idx until
     we find a match.
 
@@ -318,25 +315,25 @@ for all objects in the object store.
 
 Reading an object's sha1-content
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The sha1-content of an object can be read by converting all newhash-names
-its newhash-content references to sha1-names using the translation table.
+The sha1-content of an object can be read by converting all sha256-names
+its sha256-content references to sha1-names using the translation table.
 
 Fetch
 ~~~~~
 Fetching from a SHA-1 based server requires translating between SHA-1
-and NewHash based representations on the fly.
+and SHA-256 based representations on the fly.
 
 SHA-1s named in the ref advertisement that are present on the client
-can be translated to NewHash and looked up as local objects using the
+can be translated to SHA-256 and looked up as local objects using the
 translation table.
 
 Negotiation proceeds as today. Any "have"s generated locally are
 converted to SHA-1 before being sent to the server, and SHA-1s
-mentioned by the server are converted to NewHash when looking them up
+mentioned by the server are converted to SHA-256 when looking them up
 locally.
 
 After negotiation, the server sends a packfile containing the
-requested objects. We convert the packfile to NewHash format using
+requested objects. We convert the packfile to SHA-256 format using
 the following steps:
 
 1. index-pack: inflate each object in the packfile and compute its
@@ -351,12 +348,12 @@ the following steps:
    (This list only contains objects reachable from the "wants". If the
    pack from the server contained additional extraneous objects, then
    they will be discarded.)
-3. convert to newhash: open a new (newhash) packfile. Read the topologically
+3. convert to sha256: open a new (sha256) packfile. Read the topologically
    sorted list just generated. For each object, inflate its
-   sha1-content, convert to newhash-content, and write it to the newhash
-   pack. Record the new sha1<->newhash mapping entry for use in the idx.
+   sha1-content, convert to sha256-content, and write it to the sha256
+   pack. Record the new sha1<->sha256 mapping entry for use in the idx.
 4. sort: reorder entries in the new pack to match the order of objects
-   in the pack the server generated and include blobs. Write a newhash idx
+   in the pack the server generated and include blobs. Write a sha256 idx
    file
 5. clean up: remove the SHA-1 based pack file, index, and
    topologically sorted list obtained from the server in steps 1
@@ -388,16 +385,16 @@ send-pack.
 
 Signed Commits
 ~~~~~~~~~~~~~~
-We add a new field "gpgsig-newhash" to the commit object format to allow
+We add a new field "gpgsig-sha256" to the commit object format to allow
 signing commits without relying on SHA-1. It is similar to the
-existing "gpgsig" field. Its signed payload is the newhash-content of the
-commit object with any "gpgsig" and "gpgsig-newhash" fields removed.
+existing "gpgsig" field. Its signed payload is the sha256-content of the
+commit object with any "gpgsig" and "gpgsig-sha256" fields removed.
 
 This means commits can be signed
 1. using SHA-1 only, as in existing signed commit objects
-2. using both SHA-1 and NewHash, by using both gpgsig-newhash and gpgsig
+2. using both SHA-1 and SHA-256, by using both gpgsig-sha256 and gpgsig
    fields.
-3. using only NewHash, by only using the gpgsig-newhash field.
+3. using only SHA-256, by only using the gpgsig-sha256 field.
 
 Old versions of "git verify-commit" can verify the gpgsig signature in
 cases (1) and (2) without modifications and view case (3) as an
@@ -405,24 +402,24 @@ ordinary unsigned commit.
 
 Signed Tags
 ~~~~~~~~~~~
-We add a new field "gpgsig-newhash" to the tag object format to allow
+We add a new field "gpgsig-sha256" to the tag object format to allow
 signing tags without relying on SHA-1. Its signed payload is the
-newhash-content of the tag with its gpgsig-newhash field and "-----BEGIN PGP
+sha256-content of the tag with its gpgsig-sha256 field and "-----BEGIN PGP
 SIGNATURE-----" delimited in-body signature removed.
 
 This means tags can be signed
 1. using SHA-1 only, as in existing signed tag objects
-2. using both SHA-1 and NewHash, by using gpgsig-newhash and an in-body
+2. using both SHA-1 and SHA-256, by using gpgsig-sha256 and an in-body
    signature.
-3. using only NewHash, by only using the gpgsig-newhash field.
+3. using only SHA-256, by only using the gpgsig-sha256 field.
 
 Mergetag embedding
 ~~~~~~~~~~~~~~~~~~
 The mergetag field in the sha1-content of a commit contains the
 sha1-content of a tag that was merged by that commit.
 
-The mergetag field in the newhash-content of the same commit contains the
-newhash-content of the same tag.
+The mergetag field in the sha256-content of the same commit contains the
+sha256-content of the same tag.
 
 Submodules
 ~~~~~~~~~~
@@ -497,7 +494,7 @@ Caveats
 -------
 Invalid objects
 ~~~~~~~~~~~~~~~
-The conversion from sha1-content to newhash-content retains any
+The conversion from sha1-content to sha256-content retains any
 brokenness in the original object (e.g., tree entry modes encoded with
 leading 0, tree objects whose paths are not sorted correctly, and
 commit objects without an author or committer). This is a deliberate
@@ -516,7 +513,7 @@ allow lifting this restriction.
 
 Alternates
 ~~~~~~~~~~
-For the same reason, a newhash repository cannot borrow objects from a
+For the same reason, a sha256 repository cannot borrow objects from a
 sha1 repository using objects/info/alternates or
 $GIT_ALTERNATE_OBJECT_REPOSITORIES.
 
@@ -524,20 +521,20 @@ git notes
 ~~~~~~~~~
 The "git notes" tool annotates objects using their sha1-name as key.
 This design does not describe a way to migrate notes trees to use
-newhash-names. That migration is expected to happen separately (for
+sha256-names. That migration is expected to happen separately (for
 example using a file at the root of the notes tree to describe which
 hash it uses).
 
 Server-side cost
 ~~~~~~~~~~~~~~~~
-Until Git protocol gains NewHash support, using NewHash based storage
+Until Git protocol gains SHA-256 support, using SHA-256 based storage
 on public-facing Git servers is strongly discouraged. Once Git
-protocol gains NewHash support, NewHash based servers are likely not
+protocol gains SHA-256 support, SHA-256 based servers are likely not
 to support SHA-1 compatibility, to avoid what may be a very expensive
 hash reencode during clone and to encourage peers to modernize.
 
 The design described here allows fetches by SHA-1 clients of a
-personal NewHash repository because it's not much more difficult than
+personal SHA-256 repository because it's not much more difficult than
 allowing pushes from that repository. This support needs to be guarded
 by a configuration option --- servers like git.kernel.org that serve a
 large number of clients would not be expected to bear that cost.
@@ -547,7 +544,7 @@ Meaning of signatures
 The signed payload for signed commits and tags does not explicitly
 name the hash used to identify objects. If some day Git adopts a new
 hash function with the same length as the current SHA-1 (40
-hexadecimal digit) or NewHash (64 hexadecimal digit) objects then the
+hexadecimal digit) or SHA-256 (64 hexadecimal digit) objects then the
 intent behind the PGP signed payload in an object signature is
 unclear:
 
@@ -562,7 +559,7 @@ Does this mean Git v2.12.0 is the commit with sha1-name
 e7e07d5a4fcc2a203d9873968ad3e6bd4d7419d7 or the commit with
 new-40-digit-hash-name e7e07d5a4fcc2a203d9873968ad3e6bd4d7419d7?
 
-Fortunately NewHash and SHA-1 have different lengths. If Git starts
+Fortunately SHA-256 and SHA-1 have different lengths. If Git starts
 using another hash with the same length to name objects, then it will
 need to change the format of signed payloads using that hash to
 address this issue.
@@ -574,24 +571,24 @@ supports four different modes of operation:
 
  1. ("dark launch") Treat object names input by the user as SHA-1 and
     convert any object names written to output to SHA-1, but store
-    objects using NewHash.  This allows users to test the code with no
+    objects using SHA-256.  This allows users to test the code with no
     visible behavior change except for performance.  This allows
     allows running even tests that assume the SHA-1 hash function, to
     sanity-check the behavior of the new mode.
 
- 2. ("early transition") Allow both SHA-1 and NewHash object names in
+ 2. ("early transition") Allow both SHA-1 and SHA-256 object names in
     input. Any object names written to output use SHA-1. This allows
     users to continue to make use of SHA-1 to communicate with peers
     (e.g. by email) that have not migrated yet and prepares for mode 3.
 
- 3. ("late transition") Allow both SHA-1 and NewHash object names in
-    input. Any object names written to output use NewHash. In this
+ 3. ("late transition") Allow both SHA-1 and SHA-256 object names in
+    input. Any object names written to output use SHA-256. In this
     mode, users are using a more secure object naming method by
     default.  The disruption is minimal as long as most of their peers
     are in mode 2 or mode 3.
 
  4. ("post-transition") Treat object names input by the user as
-    NewHash and write output using NewHash. This is safer than mode 3
+    SHA-256 and write output using SHA-256. This is safer than mode 3
     because there is less risk that input is incorrectly interpreted
     using the wrong hash function.
 
@@ -601,27 +598,31 @@ The user can also explicitly specify which format to use for a
 particular revision specifier and for output, overriding the mode. For
 example:
 
-git --output-format=sha1 log abac87a^{sha1}..f787cac^{newhash}
+git --output-format=sha1 log abac87a^{sha1}..f787cac^{sha256}
 
-Selection of a New Hash
------------------------
+Choice of Hash
+--------------
 In early 2005, around the time that Git was written,  Xiaoyun Wang,
 Yiqun Lisa Yin, and Hongbo Yu announced an attack finding SHA-1
 collisions in 2^69 operations. In August they published details.
 Luckily, no practical demonstrations of a collision in full SHA-1 were
 published until 10 years later, in 2017.
 
-The hash function NewHash to replace SHA-1 should be stronger than
-SHA-1 was: we would like it to be trustworthy and useful in practice
-for at least 10 years.
+Git v2.13.0 and later subsequently moved to a hardened SHA-1
+implementation by default that mitigates the SHAttered attack, but
+SHA-1 is still believed to be weak.
+
+The hash to replace this hardened SHA-1 should be stronger than SHA-1
+was: we would like it to be trustworthy and useful in practice for at
+least 10 years.
 
 Some other relevant properties:
 
 1. A 256-bit hash (long enough to match common security practice; not
    excessively long to hurt performance and disk usage).
 
-2. High quality implementations should be widely available (e.g. in
-   OpenSSL).
+2. High quality implementations should be widely available (e.g., in
+   OpenSSL and Apple CommonCrypto).
 
 3. The hash function's properties should match Git's needs (e.g. Git
    requires collision and 2nd preimage resistance and does not require
@@ -630,14 +631,13 @@ Some other relevant properties:
 4. As a tiebreaker, the hash should be fast to compute (fortunately
    many contenders are faster than SHA-1).
 
-Some hashes under consideration are SHA-256, SHA-512/256, SHA-256x16,
-K12, and BLAKE2bp-256.
+We choose SHA-256.
 
 Transition plan
 ---------------
 Some initial steps can be implemented independently of one another:
 - adding a hash function API (vtable)
-- teaching fsck to tolerate the gpgsig-newhash field
+- teaching fsck to tolerate the gpgsig-sha256 field
 - excluding gpgsig-* from the fields copied by "git commit --amend"
 - annotating tests that depend on SHA-1 values with a SHA1 test
   prerequisite
@@ -664,7 +664,7 @@ Next comes introduction of compatObjectFormat:
 - adding appropriate index entries when adding a new object to the
   object store
 - --output-format option
-- ^{sha1} and ^{newhash} revision notation
+- ^{sha1} and ^{sha256} revision notation
 - configuration to specify default input and output format (see
   "Object names on the command line" above)
 
@@ -672,7 +672,7 @@ The next step is supporting fetches and pushes to SHA-1 repositories:
 - allow pushes to a repository using the compat format
 - generate a topologically sorted list of the SHA-1 names of fetched
   objects
-- convert the fetched packfile to newhash format and generate an idx
+- convert the fetched packfile to sha256 format and generate an idx
   file
 - re-sort to match the order of objects in the fetched packfile
 
@@ -680,30 +680,30 @@ The infrastructure supporting fetch also allows converting an existing
 repository. In converted repositories and new clones, end users can
 gain support for the new hash function without any visible change in
 behavior (see "dark launch" in the "Object names on the command line"
-section). In particular this allows users to verify NewHash signatures
+section). In particular this allows users to verify SHA-256 signatures
 on objects in the repository, and it should ensure the transition code
 is stable in production in preparation for using it more widely.
 
 Over time projects would encourage their users to adopt the "early
 transition" and then "late transition" modes to take advantage of the
-new, more futureproof NewHash object names.
+new, more futureproof SHA-256 object names.
 
 When objectFormat and compatObjectFormat are both set, commands
-generating signatures would generate both SHA-1 and NewHash signatures
+generating signatures would generate both SHA-1 and SHA-256 signatures
 by default to support both new and old users.
 
-In projects using NewHash heavily, users could be encouraged to adopt
+In projects using SHA-256 heavily, users could be encouraged to adopt
 the "post-transition" mode to avoid accidentally making implicit use
 of SHA-1 object names.
 
 Once a critical mass of users have upgraded to a version of Git that
-can verify NewHash signatures and have converted their existing
+can verify SHA-256 signatures and have converted their existing
 repositories to support verifying them, we can add support for a
-setting to generate only NewHash signatures. This is expected to be at
+setting to generate only SHA-256 signatures. This is expected to be at
 least a year later.
 
 That is also a good moment to advertise the ability to convert
-repositories to use NewHash only, stripping out all SHA-1 related
+repositories to use SHA-256 only, stripping out all SHA-1 related
 metadata. This improves performance by eliminating translation
 overhead and security by avoiding the possibility of accidentally
 relying on the safety of SHA-1.
@@ -742,16 +742,16 @@ using the old hash function.
 
 Signed objects with multiple hashes
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Instead of introducing the gpgsig-newhash field in commit and tag objects
-for newhash-content based signatures, an earlier version of this design
-added "hash newhash <newhash-name>" fields to strengthen the existing
+Instead of introducing the gpgsig-sha256 field in commit and tag objects
+for sha256-content based signatures, an earlier version of this design
+added "hash sha256 <sha256-name>" fields to strengthen the existing
 sha1-content based signatures.
 
 In other words, a single signature was used to attest to the object
 content using both hash functions. This had some advantages:
 * Using one signature instead of two speeds up the signing process.
 * Having one signed payload with both hashes allows the signer to
-  attest to the sha1-name and newhash-name referring to the same object.
+  attest to the sha1-name and sha256-name referring to the same object.
 * All users consume the same signature. Broken signatures are likely
   to be detected quickly using current versions of git.
 
@@ -760,11 +760,11 @@ However, it also came with disadvantages:
   objects it references, even after the transition is complete and
   translation table is no longer needed for anything else. To support
   this, the design added fields such as "hash sha1 tree <sha1-name>"
-  and "hash sha1 parent <sha1-name>" to the newhash-content of a signed
+  and "hash sha1 parent <sha1-name>" to the sha256-content of a signed
   commit, complicating the conversion process.
 * Allowing signed objects without a sha1 (for after the transition is
   complete) complicated the design further, requiring a "nohash sha1"
-  field to suppress including "hash sha1" fields in the newhash-content
+  field to suppress including "hash sha1" fields in the sha256-content
   and signed payload.
 
 Lazily populated translation table
@@ -772,7 +772,7 @@ Lazily populated translation table
 Some of the work of building the translation table could be deferred to
 push time, but that would significantly complicate and slow down pushes.
 Calculating the sha1-name at object creation time at the same time it is
-being streamed to disk and having its newhash-name calculated should be
+being streamed to disk and having its sha256-name calculated should be
 an acceptable cost.
 
 Document History
@@ -814,6 +814,12 @@ Incorporated suggestions from jonathantanmy and sbeller:
 * avoid loose object overhead by packing more aggressively in
   "git gc --auto"
 
+Later history:
+
+ See the history of this file in git.git for the history of subsequent
+ edits. This document history is no longer being maintained as it
+ would now be superfluous to the commit log
+
 [1] http://public-inbox.org/git/CA+55aFzJtejiCjV0e43+9oR3QuJK2PiFiLQemytoLpyJWe6P9w@mail.gmail.com/
 [2] http://public-inbox.org/git/CA+55aFz+gkAsDZ24zmePQuEs1XPS9BP_s8O7Q4wQ7LV7X5-oDA@mail.gmail.com/
 [3] http://public-inbox.org/git/20170306084353.nrns455dvkdsfgo5@sigill.intra.peff.net/
index 64f49d0..9c5b6f0 100644 (file)
@@ -338,11 +338,11 @@ server advertises capability `allow-tip-sha1-in-want` or
                       request_end
   request_end       =  "0000" / "done"
 
-  want_list         =  PKT-LINE(want NUL cap_list LF)
+  want_list         =  PKT-LINE(want SP cap_list LF)
                       *(want_pkt)
   want_pkt          =  PKT-LINE(want LF)
   want              =  "want" SP id
-  cap_list          =  *(SP capability) SP
+  cap_list          =  capability *(SP capability)
 
   have_list         =  *PKT-LINE("have" SP id LF)
 
index 508a344..6ac774d 100644 (file)
@@ -50,7 +50,8 @@ Each Extra Parameter takes the form of `<key>=<value>` or `<key>`.
 
 Servers that receive any such Extra Parameters MUST ignore all
 unrecognized keys. Currently, the only Extra Parameter recognized is
-"version=1".
+"version" with a value of '1' or '2'.  See protocol-v2.txt for more
+information on protocol version 2.
 
 Git Transport
 -------------
index bc4fc8e..73aa943 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -484,6 +484,11 @@ all::
 #        The DEVELOPER mode enables -Wextra with a few exceptions. By
 #        setting this flag the exceptions are removed, and all of
 #        -Wextra is used.
+#
+#    pedantic:
+#
+#        Enable -pedantic compilation. This also disables
+#        USE_PARENS_AROUND_GETTEXT_N to produce only relevant warnings.
 
 GIT-VERSION-FILE: FORCE
        @$(SHELL_PATH) ./GIT-VERSION-GEN
@@ -564,7 +569,7 @@ SPATCH = spatch
 export TCL_PATH TCLTK_PATH
 
 SPARSE_FLAGS =
-SPATCH_FLAGS = --all-includes
+SPATCH_FLAGS = --all-includes --patch .
 
 
 
@@ -709,6 +714,7 @@ TEST_BUILTINS_OBJS += test-example-decorate.o
 TEST_BUILTINS_OBJS += test-genrandom.o
 TEST_BUILTINS_OBJS += test-hashmap.o
 TEST_BUILTINS_OBJS += test-index-version.o
+TEST_BUILTINS_OBJS += test-json-writer.o
 TEST_BUILTINS_OBJS += test-lazy-init-name-hash.o
 TEST_BUILTINS_OBJS += test-match-trees.o
 TEST_BUILTINS_OBJS += test-mergesort.o
@@ -873,6 +879,7 @@ LIB_OBJS += hashmap.o
 LIB_OBJS += help.o
 LIB_OBJS += hex.o
 LIB_OBJS += ident.o
+LIB_OBJS += json-writer.o
 LIB_OBJS += kwset.o
 LIB_OBJS += levenshtein.o
 LIB_OBJS += line-log.o
@@ -2037,7 +2044,7 @@ $(BUILT_INS): git$X
 
 command-list.h: generate-cmdlist.sh command-list.txt
 
-command-list.h: $(wildcard Documentation/git*.txt)
+command-list.h: $(wildcard Documentation/git*.txt) Documentation/config.txt
        $(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh command-list.txt >$@+ && mv $@+ $@
 
 SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):$(GIT_VERSION):\
@@ -2673,10 +2680,16 @@ check: command-list.h
        fi
 
 C_SOURCES = $(patsubst %.o,%.c,$(C_OBJ))
-%.cocci.patch: %.cocci $(C_SOURCES)
+ifdef DC_SHA1_SUBMODULE
+COCCI_SOURCES = $(filter-out sha1collisiondetection/%,$(C_SOURCES))
+else
+COCCI_SOURCES = $(filter-out sha1dc/%,$(C_SOURCES))
+endif
+
+%.cocci.patch: %.cocci $(COCCI_SOURCES)
        @echo '    ' SPATCH $<; \
        ret=0; \
-       for f in $(C_SOURCES); do \
+       for f in $(COCCI_SOURCES); do \
                $(SPATCH) --sp-file $< $$f $(SPATCH_FLAGS) || \
                        { ret=$$?; break; }; \
        done >$@+ 2>$@.log; \
@@ -2690,7 +2703,9 @@ C_SOURCES = $(patsubst %.o,%.c,$(C_OBJ))
        then \
                echo '    ' SPATCH result: $@; \
        fi
-coccicheck: $(patsubst %.cocci,%.cocci.patch,$(wildcard contrib/coccinelle/*.cocci))
+coccicheck: $(addsuffix .patch,$(wildcard contrib/coccinelle/*.cocci))
+
+.PHONY: coccicheck
 
 ### Installation rules
 
@@ -2902,7 +2917,10 @@ profile-clean:
        $(RM) $(addsuffix *.gcda,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
        $(RM) $(addsuffix *.gcno,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
 
-clean: profile-clean coverage-clean
+cocciclean:
+       $(RM) contrib/coccinelle/*.cocci.patch*
+
+clean: profile-clean coverage-clean cocciclean
        $(RM) *.res
        $(RM) $(OBJECTS)
        $(RM) $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB)
@@ -2914,7 +2932,6 @@ clean: profile-clean coverage-clean
        $(RM) -r $(GIT_TARNAME) .doc-tmp-dir
        $(RM) $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
        $(RM) $(htmldocs).tar.gz $(manpages).tar.gz
-       $(RM) contrib/coccinelle/*.cocci.patch*
        $(MAKE) -C Documentation/ clean
 ifndef NO_PERL
        $(MAKE) -C gitweb clean
@@ -2930,7 +2947,7 @@ endif
        $(RM) GIT-USER-AGENT GIT-PREFIX
        $(RM) GIT-SCRIPT-DEFINES GIT-PERL-DEFINES GIT-PERL-HEADER GIT-PYTHON-VARS
 
-.PHONY: all install profile-clean clean strip
+.PHONY: all install profile-clean cocciclean clean strip
 .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
 .PHONY: FORCE cscope
 
diff --git a/apply.h b/apply.h
index b80d8ba..01963b5 100644 (file)
--- a/apply.h
+++ b/apply.h
@@ -111,14 +111,14 @@ struct apply_state {
        int applied_after_fixing_ws;
 };
 
-extern int apply_parse_options(int argc, const char **argv,
-                              struct apply_state *state,
-                              int *force_apply, int *options,
-                              const char * const *apply_usage);
-extern int init_apply_state(struct apply_state *state,
-                           const char *prefix);
-extern void clear_apply_state(struct apply_state *state);
-extern int check_apply_state(struct apply_state *state, int force_apply);
+int apply_parse_options(int argc, const char **argv,
+                       struct apply_state *state,
+                       int *force_apply, int *options,
+                       const char * const *apply_usage);
+int init_apply_state(struct apply_state *state,
+                    const char *prefix);
+void clear_apply_state(struct apply_state *state);
+int check_apply_state(struct apply_state *state, int force_apply);
 
 /*
  * Some aspects of the apply behavior are controlled by the following
@@ -127,9 +127,8 @@ extern int check_apply_state(struct apply_state *state, int force_apply);
 #define APPLY_OPT_INACCURATE_EOF       (1<<0) /* accept inaccurate eof */
 #define APPLY_OPT_RECOUNT              (1<<1) /* accept inaccurate line count */
 
-extern int apply_all_patches(struct apply_state *state,
-                            int argc,
-                            const char **argv,
-                            int options);
+int apply_all_patches(struct apply_state *state,
+                     int argc, const char **argv,
+                     int options);
 
 #endif
index 7df8565..0bc50f6 100644 (file)
@@ -122,7 +122,7 @@ static int stream_blocked(const struct object_id *oid)
 
        st = open_istream(oid, &type, &sz, NULL);
        if (!st)
-               return error("cannot stream blob %s", oid_to_hex(oid));
+               return error(_("cannot stream blob %s"), oid_to_hex(oid));
        for (;;) {
                readlen = read_istream(st, buf, sizeof(buf));
                if (readlen <= 0)
@@ -257,7 +257,7 @@ static int write_tar_entry(struct archiver_args *args,
                *header.typeflag = TYPEFLAG_REG;
                mode = (mode | ((mode & 0100) ? 0777 : 0666)) & ~tar_umask;
        } else {
-               return error("unsupported file mode: 0%o (SHA1: %s)",
+               return error(_("unsupported file mode: 0%o (SHA1: %s)"),
                             mode, oid_to_hex(oid));
        }
        if (pathlen > sizeof(header.name)) {
@@ -284,7 +284,7 @@ static int write_tar_entry(struct archiver_args *args,
                enum object_type type;
                buffer = object_file_to_archive(args, path, oid, old_mode, &type, &size);
                if (!buffer)
-                       return error("cannot read %s", oid_to_hex(oid));
+                       return error(_("cannot read %s"), oid_to_hex(oid));
        } else {
                buffer = NULL;
                size = 0;
@@ -455,17 +455,17 @@ static int write_tar_filter_archive(const struct archiver *ar,
        filter.in = -1;
 
        if (start_command(&filter) < 0)
-               die_errno("unable to start '%s' filter", argv[0]);
+               die_errno(_("unable to start '%s' filter"), argv[0]);
        close(1);
        if (dup2(filter.in, 1) < 0)
-               die_errno("unable to redirect descriptor");
+               die_errno(_("unable to redirect descriptor"));
        close(filter.in);
 
        r = write_tar_archive(ar, args);
 
        close(1);
        if (finish_command(&filter) != 0)
-               die("'%s' filter reported error", argv[0]);
+               die(_("'%s' filter reported error"), argv[0]);
 
        strbuf_release(&cmd);
        return r;
index abc556e..024267f 100644 (file)
@@ -310,11 +310,11 @@ static int write_zip_entry(struct archiver_args *args,
                if (is_utf8(path))
                        flags |= ZIP_UTF8;
                else
-                       warning("Path is not valid UTF-8: %s", path);
+                       warning(_("path is not valid UTF-8: %s"), path);
        }
 
        if (pathlen > 0xffff) {
-               return error("path too long (%d chars, SHA1: %s): %s",
+               return error(_("path too long (%d chars, SHA1: %s): %s"),
                                (int)pathlen, oid_to_hex(oid), path);
        }
 
@@ -341,7 +341,7 @@ static int write_zip_entry(struct archiver_args *args,
                    size > big_file_threshold) {
                        stream = open_istream(oid, &type, &size, NULL);
                        if (!stream)
-                               return error("cannot stream blob %s",
+                               return error(_("cannot stream blob %s"),
                                             oid_to_hex(oid));
                        flags |= ZIP_STREAM;
                        out = buffer = NULL;
@@ -349,7 +349,7 @@ static int write_zip_entry(struct archiver_args *args,
                        buffer = object_file_to_archive(args, path, oid, mode,
                                                        &type, &size);
                        if (!buffer)
-                               return error("cannot read %s",
+                               return error(_("cannot read %s"),
                                             oid_to_hex(oid));
                        crc = crc32(crc, buffer, size);
                        is_binary = entry_is_binary(path_without_prefix,
@@ -358,7 +358,7 @@ static int write_zip_entry(struct archiver_args *args,
                }
                compressed_size = (method == 0) ? size : 0;
        } else {
-               return error("unsupported file mode: 0%o (SHA1: %s)", mode,
+               return error(_("unsupported file mode: 0%o (SHA1: %s)"), mode,
                                oid_to_hex(oid));
        }
 
@@ -467,7 +467,7 @@ static int write_zip_entry(struct archiver_args *args,
                        zstream.avail_in = readlen;
                        result = git_deflate(&zstream, 0);
                        if (result != Z_OK)
-                               die("deflate error (%d)", result);
+                               die(_("deflate error (%d)"), result);
                        out_len = zstream.next_out - compressed;
 
                        if (out_len > 0) {
@@ -602,7 +602,7 @@ static void dos_time(timestamp_t *timestamp, int *dos_date, int *dos_time)
        struct tm *t;
 
        if (date_overflows(*timestamp))
-               die("timestamp too large for this system: %"PRItime,
+               die(_("timestamp too large for this system: %"PRItime),
                    *timestamp);
        time = (time_t)*timestamp;
        t = localtime(&time);
diff --git a/attr.h b/attr.h
index 442d464..4634001 100644 (file)
--- a/attr.h
+++ b/attr.h
@@ -42,31 +42,31 @@ struct attr_check {
        struct attr_stack *stack;
 };
 
-extern struct attr_check *attr_check_alloc(void);
-extern struct attr_check *attr_check_initl(const char *, ...);
-extern struct attr_check *attr_check_dup(const struct attr_check *check);
+struct attr_check *attr_check_alloc(void);
+struct attr_check *attr_check_initl(const char *, ...);
+struct attr_check *attr_check_dup(const struct attr_check *check);
 
-extern struct attr_check_item *attr_check_append(struct attr_check *check,
-                                                const struct git_attr *attr);
+struct attr_check_item *attr_check_append(struct attr_check *check,
+                                         const struct git_attr *attr);
 
-extern void attr_check_reset(struct attr_check *check);
-extern void attr_check_clear(struct attr_check *check);
-extern void attr_check_free(struct attr_check *check);
+void attr_check_reset(struct attr_check *check);
+void attr_check_clear(struct attr_check *check);
+void attr_check_free(struct attr_check *check);
 
 /*
  * Return the name of the attribute represented by the argument.  The
  * return value is a pointer to a null-delimited string that is part
  * of the internal data structure; it should not be modified or freed.
  */
-extern const char *git_attr_name(const struct git_attr *);
+const char *git_attr_name(const struct git_attr *);
 
-extern int git_check_attr(const char *path, struct attr_check *check);
+int git_check_attr(const char *path, struct attr_check *check);
 
 /*
  * Retrieve all attributes that apply to the specified path.
  * check holds the attributes and their values.
  */
-extern void git_all_attrs(const char *path, struct attr_check *check);
+void git_all_attrs(const char *path, struct attr_check *check);
 
 enum git_attr_direction {
        GIT_ATTR_CHECKIN,
@@ -76,6 +76,6 @@ enum git_attr_direction {
 void git_attr_set_direction(enum git_attr_direction new_direction,
                            struct index_state *istate);
 
-extern void attr_start(void);
+void attr_start(void);
 
 #endif /* ATTR_H */
diff --git a/banned.h b/banned.h
new file mode 100644 (file)
index 0000000..28f5937
--- /dev/null
+++ b/banned.h
@@ -0,0 +1,30 @@
+#ifndef BANNED_H
+#define BANNED_H
+
+/*
+ * This header lists functions that have been banned from our code base,
+ * because they're too easy to misuse (and even if used correctly,
+ * complicate audits). Including this header turns them into compile-time
+ * errors.
+ */
+
+#define BANNED(func) sorry_##func##_is_a_banned_function
+
+#undef strcpy
+#define strcpy(x,y) BANNED(strcpy)
+#undef strcat
+#define strcat(x,y) BANNED(strcat)
+#undef strncpy
+#define strncpy(x,y,n) BANNED(strncpy)
+
+#undef sprintf
+#undef vsprintf
+#ifdef HAVE_VARIADIC_MACROS
+#define sprintf(...) BANNED(sprintf)
+#define vsprintf(...) BANNED(vsprintf)
+#else
+#define sprintf(buf,fmt,arg) BANNED(sprintf)
+#define vsprintf(buf,fmt,arg) BANNED(sprintf)
+#endif
+
+#endif /* BANNED_H */
diff --git a/blame.h b/blame.h
index 2092f95..9b5240f 100644 (file)
--- a/blame.h
+++ b/blame.h
@@ -159,18 +159,22 @@ static inline struct blame_origin *blame_origin_incref(struct blame_origin *o)
                o->refcnt++;
        return o;
 }
-extern void blame_origin_decref(struct blame_origin *o);
-
-extern void blame_coalesce(struct blame_scoreboard *sb);
-extern void blame_sort_final(struct blame_scoreboard *sb);
-extern unsigned blame_entry_score(struct blame_scoreboard *sb, struct blame_entry *e);
-extern void assign_blame(struct blame_scoreboard *sb, int opt);
-extern const char *blame_nth_line(struct blame_scoreboard *sb, long lno);
-
-extern void init_scoreboard(struct blame_scoreboard *sb);
-extern void setup_scoreboard(struct blame_scoreboard *sb, const char *path, struct blame_origin **orig);
-
-extern struct blame_entry *blame_entry_prepend(struct blame_entry *head, long start, long end, struct blame_origin *o);
+void blame_origin_decref(struct blame_origin *o);
+
+void blame_coalesce(struct blame_scoreboard *sb);
+void blame_sort_final(struct blame_scoreboard *sb);
+unsigned blame_entry_score(struct blame_scoreboard *sb, struct blame_entry *e);
+void assign_blame(struct blame_scoreboard *sb, int opt);
+const char *blame_nth_line(struct blame_scoreboard *sb, long lno);
+
+void init_scoreboard(struct blame_scoreboard *sb);
+void setup_scoreboard(struct blame_scoreboard *sb,
+                     const char *path,
+                     struct blame_origin **orig);
+
+struct blame_entry *blame_entry_prepend(struct blame_entry *head,
+                                       long start, long end,
+                                       struct blame_origin *o);
 
 extern struct blame_origin *get_blame_suspects(struct commit *commit);
 
index 8a155dd..ba1ff56 100644 (file)
@@ -304,7 +304,8 @@ static struct option builtin_add_options[] = {
        OPT_BOOL( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
        OPT_BOOL( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
        OPT_BOOL( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
-       OPT_STRING( 0 , "chmod", &chmod_arg, N_("(+/-)x"), N_("override the executable bit of the listed files")),
+       OPT_STRING(0, "chmod", &chmod_arg, "(+|-)x",
+                  N_("override the executable bit of the listed files")),
        OPT_HIDDEN_BOOL(0, "warn-embedded-repo", &warn_on_embedded_repo,
                        N_("warn when adding an embedded repository")),
        OPT_END(),
index 5c93d16..97f6eca 100644 (file)
@@ -410,7 +410,7 @@ static void parse_color_fields(const char *s)
        }
 
        if (next == EXPECT_COLOR)
-               die (_("must end with a color"));
+               die(_("must end with a color"));
 
        colorfield[colorfield_nr].hop = TIME_MAX;
        string_list_clear(&l, 0);
index 516136a..cb6bb76 100644 (file)
@@ -1198,12 +1198,12 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
        if (opts.track != BRANCH_TRACK_UNSPECIFIED && !opts.new_branch) {
                const char *argv0 = argv[0];
                if (!argc || !strcmp(argv0, "--"))
-                       die (_("--track needs a branch name"));
+                       die(_("--track needs a branch name"));
                skip_prefix(argv0, "refs/", &argv0);
                skip_prefix(argv0, "remotes/", &argv0);
                argv0 = strchr(argv0, '/');
                if (!argv0 || !argv0[1])
-                       die (_("Missing branch name; try -b"));
+                       die(_("missing branch name; try -b"));
                opts.new_branch = argv0 + 1;
        }
 
index 9ebb5ac..fd2c3ef 100644 (file)
@@ -897,7 +897,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        int err = 0, complete_refs_before_fetch = 1;
        int submodule_progress;
 
-       struct refspec_item refspec;
+       struct refspec rs = REFSPEC_INIT_FETCH;
+       struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
 
        fetch_if_missing = 0;
 
@@ -1079,7 +1080,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        if (option_required_reference.nr || option_optional_reference.nr)
                setup_reference();
 
-       refspec_item_init_or_die(&refspec, value.buf, REFSPEC_FETCH);
+       refspec_append(&rs, value.buf);
 
        strbuf_reset(&value);
 
@@ -1136,10 +1137,18 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        if (transport->smart_options && !deepen && !filter_options.choice)
                transport->smart_options->check_self_contained_and_connected = 1;
 
-       refs = transport_get_remote_refs(transport, NULL);
+
+       argv_array_push(&ref_prefixes, "HEAD");
+       refspec_ref_prefixes(&rs, &ref_prefixes);
+       if (option_branch)
+               expand_ref_prefix(&ref_prefixes, option_branch);
+       if (!option_no_tags)
+               argv_array_push(&ref_prefixes, "refs/tags/");
+
+       refs = transport_get_remote_refs(transport, &ref_prefixes);
 
        if (refs) {
-               mapped_refs = wanted_peer_refs(refs, &refspec);
+               mapped_refs = wanted_peer_refs(refs, &rs.items[0]);
                /*
                 * transport_get_remote_refs() may return refs with null sha-1
                 * in mapped_refs (see struct transport->get_refs_list
@@ -1157,7 +1166,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                        }
 
                if (!is_local && !complete_refs_before_fetch)
-                       transport_fetch_refs(transport, mapped_refs, NULL);
+                       transport_fetch_refs(transport, mapped_refs);
 
                remote_head = find_ref_by_name(refs, "HEAD");
                remote_head_points_at =
@@ -1199,7 +1208,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        if (is_local)
                clone_local(path, git_dir);
        else if (refs && complete_refs_before_fetch)
-               transport_fetch_refs(transport, mapped_refs, NULL);
+               transport_fetch_refs(transport, mapped_refs);
 
        update_remote_refs(refs, mapped_refs, remote_head_points_at,
                           branch_top.buf, reflog_msg.buf, transport,
@@ -1233,6 +1242,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        strbuf_release(&value);
        junk_mode = JUNK_LEAVE_ALL;
 
-       refspec_item_clear(&refspec);
+       refspec_clear(&rs);
+       argv_array_clear(&ref_prefixes);
        return err;
 }
index 158e3f8..213fca2 100644 (file)
@@ -1647,9 +1647,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
        unlink(git_path_squash_msg(the_repository));
 
        if (commit_index_files())
-               die (_("Repository has been updated, but unable to write\n"
-                    "new_index file. Check that disk is not full and quota is\n"
-                    "not exceeded, and then \"git reset HEAD\" to recover."));
+               die(_("repository has been updated, but unable to write\n"
+                     "new_index file. Check that disk is not full and quota is\n"
+                     "not exceeded, and then \"git reset HEAD\" to recover."));
 
        rerere(0);
        run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
index 2c93a28..97b58c4 100644 (file)
@@ -110,7 +110,7 @@ static int option_parse_type(const struct option *opt, const char *arg,
                 * --int' and '--type=bool
                 * --type=int'.
                 */
-               error("only one type at a time.");
+               error(_("only one type at a time"));
                usage_builtin_config();
        }
        *to_type = new_type;
@@ -164,7 +164,11 @@ static NORETURN void usage_builtin_config(void)
 static void check_argc(int argc, int min, int max) {
        if (argc >= min && argc <= max)
                return;
-       error("wrong number of arguments");
+       if (min == max)
+               error(_("wrong number of arguments, should be %d"), min);
+       else
+               error(_("wrong number of arguments, should be from %d to %d"),
+                     min, max);
        usage_builtin_config();
 }
 
@@ -297,7 +301,7 @@ static int get_value(const char *key_, const char *regex_)
 
                key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
                if (regcomp(key_regexp, key, REG_EXTENDED)) {
-                       error("invalid key pattern: %s", key_);
+                       error(_("invalid key pattern: %s"), key_);
                        FREE_AND_NULL(key_regexp);
                        ret = CONFIG_INVALID_PATTERN;
                        goto free_strings;
@@ -317,7 +321,7 @@ static int get_value(const char *key_, const char *regex_)
 
                regexp = (regex_t*)xmalloc(sizeof(regex_t));
                if (regcomp(regexp, regex_, REG_EXTENDED)) {
-                       error("invalid pattern: %s", regex_);
+                       error(_("invalid pattern: %s"), regex_);
                        FREE_AND_NULL(regexp);
                        ret = CONFIG_INVALID_PATTERN;
                        goto free_strings;
@@ -390,7 +394,7 @@ static char *normalize_value(const char *key, const char *value)
        if (type == TYPE_COLOR) {
                char v[COLOR_MAXLEN];
                if (git_config_color(v, key, value))
-                       die("cannot parse color '%s'", value);
+                       die(_("cannot parse color '%s'"), value);
 
                /*
                 * The contents of `v` now contain an ANSI escape
@@ -485,13 +489,13 @@ static int get_colorbool(const char *var, int print)
 static void check_write(void)
 {
        if (!given_config_source.file && !startup_info->have_repository)
-               die("not in a git directory");
+               die(_("not in a git directory"));
 
        if (given_config_source.use_stdin)
-               die("writing to stdin is not supported");
+               die(_("writing to stdin is not supported"));
 
        if (given_config_source.blob)
-               die("writing config blobs is not supported");
+               die(_("writing config blobs is not supported"));
 }
 
 struct urlmatch_current_candidate_value {
@@ -599,7 +603,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 
        if (use_global_config + use_system_config + use_local_config +
            !!given_config_source.file + !!given_config_source.blob > 1) {
-               error("only one config file at a time.");
+               error(_("only one config file at a time"));
                usage_builtin_config();
        }
 
@@ -626,7 +630,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                         * location; error out even if XDG_CONFIG_HOME
                         * is set and points at a sane location.
                         */
-                       die("$HOME not set");
+                       die(_("$HOME not set"));
 
                if (access_or_warn(user_config, R_OK, 0) &&
                    xdg_config && !access_or_warn(xdg_config, R_OK, 0)) {
@@ -663,12 +667,12 @@ int cmd_config(int argc, const char **argv, const char *prefix)
        }
 
        if ((actions & (ACTION_GET_COLOR|ACTION_GET_COLORBOOL)) && type) {
-               error("--get-color and variable type are incoherent");
+               error(_("--get-color and variable type are incoherent"));
                usage_builtin_config();
        }
 
        if (HAS_MULTI_BITS(actions)) {
-               error("only one action at a time.");
+               error(_("only one action at a time"));
                usage_builtin_config();
        }
        if (actions == 0)
@@ -681,19 +685,19 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                }
        if (omit_values &&
            !(actions == ACTION_LIST || actions == ACTION_GET_REGEXP)) {
-               error("--name-only is only applicable to --list or --get-regexp");
+               error(_("--name-only is only applicable to --list or --get-regexp"));
                usage_builtin_config();
        }
 
        if (show_origin && !(actions &
                (ACTION_GET|ACTION_GET_ALL|ACTION_GET_REGEXP|ACTION_LIST))) {
-               error("--show-origin is only applicable to --get, --get-all, "
-                         "--get-regexp, and --list.");
+               error(_("--show-origin is only applicable to --get, --get-all, "
+                       "--get-regexp, and --list"));
                usage_builtin_config();
        }
 
        if (default_value && !(actions & ACTION_GET)) {
-               error("--default is only applicable to --get");
+               error(_("--default is only applicable to --get"));
                usage_builtin_config();
        }
 
@@ -706,10 +710,10 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                                        &given_config_source,
                                        &config_options) < 0) {
                        if (given_config_source.file)
-                               die_errno("unable to read config file '%s'",
+                               die_errno(_("unable to read config file '%s'"),
                                          given_config_source.file);
                        else
-                               die("error processing config file(s)");
+                               die(_("error processing config file(s)"));
                }
        }
        else if (actions == ACTION_EDIT) {
@@ -717,11 +721,11 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 
                check_argc(argc, 0, 0);
                if (!given_config_source.file && nongit)
-                       die("not in a git directory");
+                       die(_("not in a git directory"));
                if (given_config_source.use_stdin)
-                       die("editing stdin is not supported");
+                       die(_("editing stdin is not supported"));
                if (given_config_source.blob)
-                       die("editing blobs is not supported");
+                       die(_("editing blobs is not supported"));
                git_config(git_default_config, NULL);
                config_file = given_config_source.file ?
                                xstrdup(given_config_source.file) :
@@ -822,7 +826,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                if (ret < 0)
                        return ret;
                if (ret == 0)
-                       die("No such section!");
+                       die(_("no such section: %s"), argv[0]);
        }
        else if (actions == ACTION_REMOVE_SECTION) {
                int ret;
@@ -833,7 +837,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
                if (ret < 0)
                        return ret;
                if (ret == 0)
-                       die("No such section!");
+                       die(_("no such section: %s"), argv[0]);
        }
        else if (actions == ACTION_GET_COLOR) {
                check_argc(argc, 1, 2);
index 3018e61..cdd585c 100644 (file)
@@ -703,7 +703,7 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
                        1, PARSE_OPT_NONEG | PARSE_OPT_HIDDEN),
                OPT_BOOL(0, "symlinks", &symlinks,
                         N_("use symlinks in dir-diff mode")),
-               OPT_STRING('t', "tool", &difftool_cmd, N_("<tool>"),
+               OPT_STRING('t', "tool", &difftool_cmd, N_("tool"),
                           N_("use the specified diff tool")),
                OPT_BOOL(0, "tool-help", &tool_help,
                         N_("print a list of diff tools that may be used with "
@@ -711,7 +711,7 @@ int cmd_difftool(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "trust-exit-code", &trust_exit_code,
                         N_("make 'git-difftool' exit when an invoked diff "
                            "tool returns a non - zero exit code")),
-               OPT_STRING('x', "extcmd", &extcmd, N_("<command>"),
+               OPT_STRING('x', "extcmd", &extcmd, N_("command"),
                           N_("specify a custom command for viewing diffs")),
                OPT_END()
        };
index 223499d..9bd8a14 100644 (file)
@@ -241,7 +241,7 @@ static void export_blob(const struct object_id *oid)
        } else {
                buf = read_object_file(oid, &type, &size);
                if (!buf)
-                       die ("Could not read blob %s", oid_to_hex(oid));
+                       die("could not read blob %s", oid_to_hex(oid));
                if (check_object_signature(oid, buf, size, type_name(type)) < 0)
                        die("sha1 mismatch in blob %s", oid_to_hex(oid));
                object = parse_object_buffer(the_repository, oid, type,
@@ -255,7 +255,7 @@ static void export_blob(const struct object_id *oid)
 
        printf("blob\nmark :%"PRIu32"\ndata %lu\n", last_idnum, size);
        if (size && fwrite(buf, size, 1, stdout) != 1)
-               die_errno ("Could not write blob '%s'", oid_to_hex(oid));
+               die_errno("could not write blob '%s'", oid_to_hex(oid));
        printf("\n");
 
        show_progress();
@@ -563,14 +563,14 @@ static void handle_commit(struct commit *commit, struct rev_info *rev,
        commit_buffer = get_commit_buffer(commit, NULL);
        author = strstr(commit_buffer, "\nauthor ");
        if (!author)
-               die ("Could not find author in commit %s",
-                    oid_to_hex(&commit->object.oid));
+               die("could not find author in commit %s",
+                   oid_to_hex(&commit->object.oid));
        author++;
        author_end = strchrnul(author, '\n');
        committer = strstr(author_end, "\ncommitter ");
        if (!committer)
-               die ("Could not find committer in commit %s",
-                    oid_to_hex(&commit->object.oid));
+               die("could not find committer in commit %s",
+                   oid_to_hex(&commit->object.oid));
        committer++;
        committer_end = strchrnul(committer, '\n');
        message = strstr(committer_end, "\n\n");
@@ -691,7 +691,7 @@ static void handle_tag(const char *name, struct tag *tag)
 
        buf = read_object_file(&tag->object.oid, &type, &size);
        if (!buf)
-               die ("Could not read tag %s", oid_to_hex(&tag->object.oid));
+               die("could not read tag %s", oid_to_hex(&tag->object.oid));
        message = memmem(buf, size, "\n\n", 2);
        if (message) {
                message += 2;
@@ -728,18 +728,18 @@ static void handle_tag(const char *name, struct tag *tag)
                if (signature)
                        switch(signed_tag_mode) {
                        case ABORT:
-                               die ("Encountered signed tag %s; use "
-                                    "--signed-tags=<mode> to handle it.",
-                                    oid_to_hex(&tag->object.oid));
+                               die("encountered signed tag %s; use "
+                                   "--signed-tags=<mode> to handle it",
+                                   oid_to_hex(&tag->object.oid));
                        case WARN:
-                               warning ("Exporting signed tag %s",
-                                        oid_to_hex(&tag->object.oid));
+                               warning("exporting signed tag %s",
+                                       oid_to_hex(&tag->object.oid));
                                /* fallthru */
                        case VERBATIM:
                                break;
                        case WARN_STRIP:
-                               warning ("Stripping signature from tag %s",
-                                        oid_to_hex(&tag->object.oid));
+                               warning("stripping signature from tag %s",
+                                       oid_to_hex(&tag->object.oid));
                                /* fallthru */
                        case STRIP:
                                message_size = signature + 1 - message;
@@ -753,18 +753,18 @@ static void handle_tag(const char *name, struct tag *tag)
        if (!tagged_mark) {
                switch(tag_of_filtered_mode) {
                case ABORT:
-                       die ("Tag %s tags unexported object; use "
-                            "--tag-of-filtered-object=<mode> to handle it.",
-                            oid_to_hex(&tag->object.oid));
+                       die("tag %s tags unexported object; use "
+                           "--tag-of-filtered-object=<mode> to handle it",
+                           oid_to_hex(&tag->object.oid));
                case DROP:
                        /* Ignore this tag altogether */
                        free(buf);
                        return;
                case REWRITE:
                        if (tagged->type != OBJ_COMMIT) {
-                               die ("Tag %s tags unexported %s!",
-                                    oid_to_hex(&tag->object.oid),
-                                    type_name(tagged->type));
+                               die("tag %s tags unexported %s!",
+                                   oid_to_hex(&tag->object.oid),
+                                   type_name(tagged->type));
                        }
                        p = (struct commit *)tagged;
                        for (;;) {
@@ -775,7 +775,7 @@ static void handle_tag(const char *name, struct tag *tag)
                                if (!(p->object.flags & TREESAME))
                                        break;
                                if (!p->parents)
-                                       die ("Can't find replacement commit for tag %s\n",
+                                       die("can't find replacement commit for tag %s",
                                             oid_to_hex(&tag->object.oid));
                                p = p->parents->item;
                        }
index 34d2bd1..61bec5d 100644 (file)
@@ -942,13 +942,11 @@ static int quickfetch(struct ref *ref_map)
        return check_connected(iterate_ref_map, &rm, &opt);
 }
 
-static int fetch_refs(struct transport *transport, struct ref *ref_map,
-                     struct ref **updated_remote_refs)
+static int fetch_refs(struct transport *transport, struct ref *ref_map)
 {
        int ret = quickfetch(ref_map);
        if (ret)
-               ret = transport_fetch_refs(transport, ref_map,
-                                          updated_remote_refs);
+               ret = transport_fetch_refs(transport, ref_map);
        if (!ret)
                /*
                 * Keep the new pack's ".keep" file around to allow the caller
@@ -1153,7 +1151,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)
        transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
        transport_set_option(transport, TRANS_OPT_DEPTH, "0");
        transport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL);
-       if (!fetch_refs(transport, ref_map, NULL))
+       if (!fetch_refs(transport, ref_map))
                consume_refs(transport, ref_map);
 
        if (gsecondary) {
@@ -1169,7 +1167,6 @@ static int do_fetch(struct transport *transport,
        int autotags = (transport->remote->fetch_tags == 1);
        int retcode = 0;
        const struct ref *remote_refs;
-       struct ref *updated_remote_refs = NULL;
        struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
 
        if (tags == TAGS_DEFAULT) {
@@ -1192,7 +1189,7 @@ static int do_fetch(struct transport *transport,
                refspec_ref_prefixes(&transport->remote->fetch, &ref_prefixes);
 
        if (ref_prefixes.argc &&
-           (tags == TAGS_SET || (tags == TAGS_DEFAULT && !rs->nr))) {
+           (tags == TAGS_SET || (tags == TAGS_DEFAULT))) {
                argv_array_push(&ref_prefixes, "refs/tags/");
        }
 
@@ -1220,24 +1217,7 @@ static int do_fetch(struct transport *transport,
                                   transport->url);
                }
        }
-
-       if (fetch_refs(transport, ref_map, &updated_remote_refs)) {
-               free_refs(ref_map);
-               retcode = 1;
-               goto cleanup;
-       }
-       if (updated_remote_refs) {
-               /*
-                * Regenerate ref_map using the updated remote refs.  This is
-                * to account for additional information which may be provided
-                * by the transport (e.g. shallow info).
-                */
-               free_refs(ref_map);
-               ref_map = get_ref_map(transport->remote, updated_remote_refs, rs,
-                                     tags, &autotags);
-               free_refs(updated_remote_refs);
-       }
-       if (consume_refs(transport, ref_map)) {
+       if (fetch_refs(transport, ref_map) || consume_refs(transport, ref_map)) {
                free_refs(ref_map);
                retcode = 1;
                goto cleanup;
index ca9206f..f35ff16 100644 (file)
@@ -628,7 +628,7 @@ int fmt_merge_msg(struct strbuf *in, struct strbuf *out,
                i++;
                p[len] = 0;
                if (handle_line(p, &merge_parents))
-                       die ("Error in line %d: %.*s", i, len, p);
+                       die("error in line %d: %.*s", i, len, p);
        }
 
        if (opts->add_title && srcs.nr)
index c96f3f4..250f5af 100644 (file)
@@ -694,7 +694,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
        fetch_if_missing = 0;
 
        errors_found = 0;
-       check_replace_refs = 0;
+       read_replace_refs = 0;
 
        argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);
 
index 056161f..ee5a1bd 100644 (file)
@@ -489,7 +489,7 @@ static int grep_cache(struct grep_opt *opt, struct repository *repo,
        }
 
        if (repo_read_index(repo) < 0)
-               die("index file corrupt");
+               die(_("index file corrupt"));
 
        for (nr = 0; nr < repo->index->cache_nr; nr++) {
                const struct cache_entry *ce = repo->index->cache[nr];
@@ -963,7 +963,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        }
 
        if (!opt.pattern_list)
-               die(_("no pattern given."));
+               die(_("no pattern given"));
 
        /* --only-matching has no effect with --invert. */
        if (opt.invert)
@@ -1093,19 +1093,19 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
        }
 
        if (recurse_submodules && (!use_index || untracked))
-               die(_("option not supported with --recurse-submodules."));
+               die(_("option not supported with --recurse-submodules"));
 
        if (!show_in_pager && !opt.status_only)
                setup_pager();
 
        if (!use_index && (untracked || cached))
-               die(_("--cached or --untracked cannot be used with --no-index."));
+               die(_("--cached or --untracked cannot be used with --no-index"));
 
        if (!use_index || untracked) {
                int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude;
                hit = grep_directory(&opt, &pathspec, use_exclude, use_index);
        } else if (0 <= opt_exclude) {
-               die(_("--[no-]exclude-standard cannot be used for tracked contents."));
+               die(_("--[no-]exclude-standard cannot be used for tracked contents"));
        } else if (!list.nr) {
                if (!cached)
                        setup_work_tree();
@@ -1113,7 +1113,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
                hit = grep_cache(&opt, the_repository, &pathspec, cached);
        } else {
                if (cached)
-                       die(_("both --cached and trees are given."));
+                       die(_("both --cached and trees are given"));
 
                hit = grep_objects(&opt, &pathspec, &list);
        }
index de311fe..9582ead 100644 (file)
@@ -1680,7 +1680,7 @@ int cmd_index_pack(int argc, const char **argv, const char *prefix)
        if (argc == 2 && !strcmp(argv[1], "-h"))
                usage(index_pack_usage);
 
-       check_replace_refs = 0;
+       read_replace_refs = 0;
        fsck_options.walk = mark_link;
 
        reset_pack_idx_option(&opts);
index 4ecf909..12ddda7 100644 (file)
@@ -73,7 +73,8 @@ static void copy_templates_1(struct strbuf *path, struct strbuf *template_path,
                        continue;
                else if (S_ISLNK(st_template.st_mode)) {
                        struct strbuf lnk = STRBUF_INIT;
-                       if (strbuf_readlink(&lnk, template_path->buf, 0) < 0)
+                       if (strbuf_readlink(&lnk, template_path->buf,
+                                           st_template.st_size) < 0)
                                die_errno(_("cannot readlink '%s'"), template_path->buf);
                        if (symlink(lnk.buf, path->buf))
                                die_errno(_("cannot symlink '%s' '%s'"),
index 5745951..e094560 100644 (file)
@@ -1608,14 +1608,14 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                numbered = 0;
 
        if (numbered && keep_subject)
-               die (_("-n and -k are mutually exclusive."));
+               die(_("-n and -k are mutually exclusive"));
        if (keep_subject && subject_prefix)
-               die (_("--subject-prefix/--rfc and -k are mutually exclusive."));
+               die(_("--subject-prefix/--rfc and -k are mutually exclusive"));
        rev.preserve_subject = keep_subject;
 
        argc = setup_revisions(argc, argv, &rev, &s_r_opt);
        if (argc > 1)
-               die (_("unrecognized argument: %s"), argv[1]);
+               die(_("unrecognized argument: %s"), argv[1]);
 
        if (rev.diffopt.output_format & DIFF_FORMAT_NAME)
                die(_("--name-only does not make sense"));
index 77e1694..8f4a506 100644 (file)
@@ -725,7 +725,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
                        exit(128);
                if (write_locked_index(&the_index, &lock,
                                       COMMIT_LOCK | SKIP_IF_UNCHANGED))
-                       die (_("unable to write %s"), get_index_file());
+                       die(_("unable to write %s"), get_index_file());
                return clean ? 0 : 1;
        } else {
                return try_merge_command(strategy, xopts_nr, xopts,
index 4391504..c0741ba 100644 (file)
@@ -140,7 +140,7 @@ static void *get_delta(struct object_entry *entry)
 
        buf = read_object_file(&entry->idx.oid, &type, &size);
        if (!buf)
-               die("unable to read %s", oid_to_hex(&entry->idx.oid));
+               die(_("unable to read %s"), oid_to_hex(&entry->idx.oid));
        base_buf = read_object_file(&DELTA(entry)->idx.oid, &type,
                                    &base_size);
        if (!base_buf)
@@ -148,8 +148,13 @@ static void *get_delta(struct object_entry *entry)
                    oid_to_hex(&DELTA(entry)->idx.oid));
        delta_buf = diff_delta(base_buf, base_size,
                               buf, size, &delta_size, 0);
+       /*
+        * We succesfully computed this delta once but dropped it for
+        * memory reasons. Something is very wrong if this time we
+        * recompute and create a different delta.
+        */
        if (!delta_buf || delta_size != DELTA_SIZE(entry))
-               die("delta size changed");
+               BUG("delta size changed");
        free(buf);
        free(base_buf);
        return delta_buf;
@@ -406,7 +411,7 @@ static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
        datalen = revidx[1].offset - offset;
        if (!pack_to_stdout && p->index_version > 1 &&
            check_pack_crc(p, &w_curs, offset, datalen, revidx->nr)) {
-               error("bad packed object CRC for %s",
+               error(_("bad packed object CRC for %s"),
                      oid_to_hex(&entry->idx.oid));
                unuse_pack(&w_curs);
                return write_no_reuse_object(f, entry, limit, usable_delta);
@@ -417,7 +422,7 @@ static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
 
        if (!pack_to_stdout && p->index_version == 1 &&
            check_pack_inflate(p, &w_curs, offset, datalen, entry_size)) {
-               error("corrupt packed object for %s",
+               error(_("corrupt packed object for %s"),
                      oid_to_hex(&entry->idx.oid));
                unuse_pack(&w_curs);
                return write_no_reuse_object(f, entry, limit, usable_delta);
@@ -548,7 +553,7 @@ static enum write_one_status write_one(struct hashfile *f,
         */
        recursing = (e->idx.offset == 1);
        if (recursing) {
-               warning("recursive delta detected for object %s",
+               warning(_("recursive delta detected for object %s"),
                        oid_to_hex(&e->idx.oid));
                return WRITE_ONE_RECURSIVE;
        } else if (e->idx.offset || e->preferred_base) {
@@ -582,7 +587,7 @@ static enum write_one_status write_one(struct hashfile *f,
 
        /* make sure off_t is sufficiently large not to wrap */
        if (signed_add_overflows(*offset, size))
-               die("pack too large for current definition of off_t");
+               die(_("pack too large for current definition of off_t"));
        *offset += size;
        return WRITE_ONE_WRITTEN;
 }
@@ -748,7 +753,8 @@ static struct object_entry **compute_write_order(void)
        }
 
        if (wo_end != to_pack.nr_objects)
-               die("ordered %u objects, expected %"PRIu32, wo_end, to_pack.nr_objects);
+               die(_("ordered %u objects, expected %"PRIu32),
+                   wo_end, to_pack.nr_objects);
 
        return wo;
 }
@@ -760,15 +766,15 @@ static off_t write_reused_pack(struct hashfile *f)
        int fd;
 
        if (!is_pack_valid(reuse_packfile))
-               die("packfile is invalid: %s", reuse_packfile->pack_name);
+               die(_("packfile is invalid: %s"), reuse_packfile->pack_name);
 
        fd = git_open(reuse_packfile->pack_name);
        if (fd < 0)
-               die_errno("unable to open packfile for reuse: %s",
+               die_errno(_("unable to open packfile for reuse: %s"),
                          reuse_packfile->pack_name);
 
        if (lseek(fd, sizeof(struct pack_header), SEEK_SET) == -1)
-               die_errno("unable to seek in reused packfile");
+               die_errno(_("unable to seek in reused packfile"));
 
        if (reuse_packfile_offset < 0)
                reuse_packfile_offset = reuse_packfile->pack_size - the_hash_algo->rawsz;
@@ -779,7 +785,7 @@ static off_t write_reused_pack(struct hashfile *f)
                int read_pack = xread(fd, buffer, sizeof(buffer));
 
                if (read_pack <= 0)
-                       die_errno("unable to read from reused packfile");
+                       die_errno(_("unable to read from reused packfile"));
 
                if (read_pack > to_write)
                        read_pack = to_write;
@@ -882,7 +888,7 @@ static void write_pack_file(void)
                         * to preserve this property.
                         */
                        if (stat(pack_tmp_name, &st) < 0) {
-                               warning_errno("failed to stat %s", pack_tmp_name);
+                               warning_errno(_("failed to stat %s"), pack_tmp_name);
                        } else if (!last_mtime) {
                                last_mtime = st.st_mtime;
                        } else {
@@ -890,7 +896,7 @@ static void write_pack_file(void)
                                utb.actime = st.st_atime;
                                utb.modtime = --last_mtime;
                                if (utime(pack_tmp_name, &utb) < 0)
-                                       warning_errno("failed utime() on %s", pack_tmp_name);
+                                       warning_errno(_("failed utime() on %s"), pack_tmp_name);
                        }
 
                        strbuf_addf(&tmpname, "%s-", base_name);
@@ -935,8 +941,8 @@ static void write_pack_file(void)
        free(write_order);
        stop_progress(&progress_state);
        if (written != nr_result)
-               die("wrote %"PRIu32" objects while expecting %"PRIu32,
-                       written, nr_result);
+               die(_("wrote %"PRIu32" objects while expecting %"PRIu32),
+                   written, nr_result);
 }
 
 static int no_try_delta(const char *path)
@@ -1480,7 +1486,7 @@ static void check_object(struct object_entry *entry)
                        while (c & 128) {
                                ofs += 1;
                                if (!ofs || MSB(ofs, 7)) {
-                                       error("delta base offset overflow in pack for %s",
+                                       error(_("delta base offset overflow in pack for %s"),
                                              oid_to_hex(&entry->idx.oid));
                                        goto give_up;
                                }
@@ -1489,7 +1495,7 @@ static void check_object(struct object_entry *entry)
                        }
                        ofs = entry->in_pack_offset - ofs;
                        if (ofs <= 0 || ofs >= entry->in_pack_offset) {
-                               error("delta base offset out of bound for %s",
+                               error(_("delta base offset out of bound for %s"),
                                      oid_to_hex(&entry->idx.oid));
                                goto give_up;
                        }
@@ -1852,18 +1858,30 @@ static int delta_cacheable(unsigned long src_size, unsigned long trg_size,
 
 #ifndef NO_PTHREADS
 
+/* Protect access to object database */
 static pthread_mutex_t read_mutex;
 #define read_lock()            pthread_mutex_lock(&read_mutex)
 #define read_unlock()          pthread_mutex_unlock(&read_mutex)
 
+/* Protect delta_cache_size */
 static pthread_mutex_t cache_mutex;
 #define cache_lock()           pthread_mutex_lock(&cache_mutex)
 #define cache_unlock()         pthread_mutex_unlock(&cache_mutex)
 
+/*
+ * Protect object list partitioning (e.g. struct thread_param) and
+ * progress_state
+ */
 static pthread_mutex_t progress_mutex;
 #define progress_lock()                pthread_mutex_lock(&progress_mutex)
 #define progress_unlock()      pthread_mutex_unlock(&progress_mutex)
 
+/*
+ * Access to struct object_entry is unprotected since each thread owns
+ * a portion of the main object list. Just don't access object entries
+ * ahead in the list because they can be stolen and would need
+ * progress_mutex for protection.
+ */
 #else
 
 #define read_lock()            (void)0
@@ -1974,10 +1992,10 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
                trg->data = read_object_file(&trg_entry->idx.oid, &type, &sz);
                read_unlock();
                if (!trg->data)
-                       die("object %s cannot be read",
+                       die(_("object %s cannot be read"),
                            oid_to_hex(&trg_entry->idx.oid));
                if (sz != trg_size)
-                       die("object %s inconsistent object length (%lu vs %lu)",
+                       die(_("object %s inconsistent object length (%lu vs %lu)"),
                            oid_to_hex(&trg_entry->idx.oid), sz,
                            trg_size);
                *mem_usage += sz;
@@ -1990,7 +2008,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
                        if (src_entry->preferred_base) {
                                static int warned = 0;
                                if (!warned++)
-                                       warning("object %s cannot be read",
+                                       warning(_("object %s cannot be read"),
                                                oid_to_hex(&src_entry->idx.oid));
                                /*
                                 * Those objects are not included in the
@@ -2000,11 +2018,11 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
                                 */
                                return 0;
                        }
-                       die("object %s cannot be read",
+                       die(_("object %s cannot be read"),
                            oid_to_hex(&src_entry->idx.oid));
                }
                if (sz != src_size)
-                       die("object %s inconsistent object length (%lu vs %lu)",
+                       die(_("object %s inconsistent object length (%lu vs %lu)"),
                            oid_to_hex(&src_entry->idx.oid), sz,
                            src_size);
                *mem_usage += sz;
@@ -2014,7 +2032,7 @@ static int try_delta(struct unpacked *trg, struct unpacked *src,
                if (!src->index) {
                        static int warned = 0;
                        if (!warned++)
-                               warning("suboptimal pack - out of memory");
+                               warning(_("suboptimal pack - out of memory"));
                        return 0;
                }
                *mem_usage += sizeof_delta_index(src->index);
@@ -2245,12 +2263,19 @@ static void try_to_free_from_threads(size_t size)
 static try_to_free_t old_try_to_free_routine;
 
 /*
+ * The main object list is split into smaller lists, each is handed to
+ * one worker.
+ *
  * The main thread waits on the condition that (at least) one of the workers
  * has stopped working (which is indicated in the .working member of
  * struct thread_params).
+ *
  * When a work thread has completed its work, it sets .working to 0 and
  * signals the main thread and waits on the condition that .data_ready
  * becomes 1.
+ *
+ * The main thread steals half of the work from the worker that has
+ * most work left to hand it to the idle worker.
  */
 
 struct thread_params {
@@ -2341,8 +2366,8 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
                return;
        }
        if (progress > pack_to_stdout)
-               fprintf(stderr, "Delta compression using up to %d threads.\n",
-                               delta_search_threads);
+               fprintf_ln(stderr, _("Delta compression using up to %d threads"),
+                          delta_search_threads);
        p = xcalloc(delta_search_threads, sizeof(*p));
 
        /* Partition the work amongst work threads. */
@@ -2382,7 +2407,7 @@ static void ll_find_deltas(struct object_entry **list, unsigned list_size,
                ret = pthread_create(&p[i].thread, NULL,
                                     threaded_find_deltas, &p[i]);
                if (ret)
-                       die("unable to create thread: %s", strerror(ret));
+                       die(_("unable to create thread: %s"), strerror(ret));
                active_threads++;
        }
 
@@ -2477,7 +2502,7 @@ static void add_tag_chain(const struct object_id *oid)
        tag = lookup_tag(the_repository, oid);
        while (1) {
                if (!tag || parse_tag(tag) || !tag->tagged)
-                       die("unable to pack objects reachable from tag %s",
+                       die(_("unable to pack objects reachable from tag %s"),
                            oid_to_hex(oid));
 
                add_object_entry(&tag->object.oid, OBJ_TAG, NULL, 0);
@@ -2543,7 +2568,7 @@ static void prepare_pack(int window, int depth)
                if (!entry->preferred_base) {
                        nr_deltas++;
                        if (oe_type(entry) < 0)
-                               die("unable to get type of object %s",
+                               die(_("unable to get type of object %s"),
                                    oid_to_hex(&entry->idx.oid));
                } else {
                        if (oe_type(entry) < 0) {
@@ -2567,7 +2592,7 @@ static void prepare_pack(int window, int depth)
                ll_find_deltas(delta_list, n, window+1, depth, &nr_done);
                stop_progress(&progress_state);
                if (nr_done != nr_deltas)
-                       die("inconsistency with delta count");
+                       die(_("inconsistency with delta count"));
        }
        free(delta_list);
 }
@@ -2607,11 +2632,11 @@ static int git_pack_config(const char *k, const char *v, void *cb)
        if (!strcmp(k, "pack.threads")) {
                delta_search_threads = git_config_int(k, v);
                if (delta_search_threads < 0)
-                       die("invalid number of threads specified (%d)",
+                       die(_("invalid number of threads specified (%d)"),
                            delta_search_threads);
 #ifdef NO_PTHREADS
                if (delta_search_threads != 1) {
-                       warning("no threads support, ignoring %s", k);
+                       warning(_("no threads support, ignoring %s"), k);
                        delta_search_threads = 0;
                }
 #endif
@@ -2620,7 +2645,7 @@ static int git_pack_config(const char *k, const char *v, void *cb)
        if (!strcmp(k, "pack.indexversion")) {
                pack_idx_opts.version = git_config_int(k, v);
                if (pack_idx_opts.version > 2)
-                       die("bad pack.indexversion=%"PRIu32,
+                       die(_("bad pack.indexversion=%"PRIu32),
                            pack_idx_opts.version);
                return 0;
        }
@@ -2638,7 +2663,7 @@ static void read_object_list_from_stdin(void)
                        if (feof(stdin))
                                break;
                        if (!ferror(stdin))
-                               die("fgets returned NULL, not EOF, not error!");
+                               die("BUG: fgets returned NULL, not EOF, not error!");
                        if (errno != EINTR)
                                die_errno("fgets");
                        clearerr(stdin);
@@ -2646,13 +2671,13 @@ static void read_object_list_from_stdin(void)
                }
                if (line[0] == '-') {
                        if (get_oid_hex(line+1, &oid))
-                               die("expected edge object ID, got garbage:\n %s",
+                               die(_("expected edge object ID, got garbage:\n %s"),
                                    line);
                        add_preferred_base(&oid);
                        continue;
                }
                if (parse_oid_hex(line, &oid, &p))
-                       die("expected object ID, got garbage:\n %s", line);
+                       die(_("expected object ID, got garbage:\n %s"), line);
 
                add_preferred_base_object(p + 1);
                add_object_entry(&oid, OBJ_NONE, p + 1, 0);
@@ -2791,7 +2816,7 @@ static void add_objects_in_unpacked_packs(struct rev_info *revs)
                if (!p->pack_local || p->pack_keep || p->pack_keep_in_core)
                        continue;
                if (open_pack_index(p))
-                       die("cannot open pack index");
+                       die(_("cannot open pack index"));
 
                ALLOC_GROW(in_pack.array,
                           in_pack.nr + p->num_objects,
@@ -2822,7 +2847,7 @@ static int add_loose_object(const struct object_id *oid, const char *path,
        enum object_type type = oid_object_info(the_repository, oid, NULL);
 
        if (type < 0) {
-               warning("loose object at %s could not be examined", path);
+               warning(_("loose object at %s could not be examined"), path);
                return 0;
        }
 
@@ -2899,7 +2924,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
                        continue;
 
                if (open_pack_index(p))
-                       die("cannot open pack index");
+                       die(_("cannot open pack index"));
 
                for (i = 0; i < p->num_objects; i++) {
                        nth_packed_object_oid(&oid, p, i);
@@ -2907,7 +2932,7 @@ static void loosen_unused_packed_objects(struct rev_info *revs)
                            !has_sha1_pack_kept_or_nonlocal(&oid) &&
                            !loosened_object_can_be_discarded(&oid, p->mtime))
                                if (force_object_loose(&oid, p->mtime))
-                                       die("unable to force loose object");
+                                       die(_("unable to force loose object"));
                }
        }
 }
@@ -2994,17 +3019,17 @@ static void get_object_list(int ac, const char **av)
                                use_bitmap_index = 0;
                                continue;
                        }
-                       die("not a rev '%s'", line);
+                       die(_("not a rev '%s'"), line);
                }
                if (handle_revision_arg(line, &revs, flags, REVARG_CANNOT_BE_FILENAME))
-                       die("bad revision '%s'", line);
+                       die(_("bad revision '%s'"), line);
        }
 
        if (use_bitmap_index && !get_object_list_from_bitmap(&revs))
                return;
 
        if (prepare_revision_walk(&revs))
-               die("revision walk setup failed");
+               die(_("revision walk setup failed"));
        mark_edges_uninteresting(&revs, show_edge);
 
        if (!fn_show_object)
@@ -3017,9 +3042,9 @@ static void get_object_list(int ac, const char **av)
                revs.ignore_missing_links = 1;
                if (add_unseen_recent_objects_to_traversal(&revs,
                                unpack_unreachable_expiration))
-                       die("unable to add recent objects");
+                       die(_("unable to add recent objects"));
                if (prepare_revision_walk(&revs))
-                       die("revision walk setup failed");
+                       die(_("revision walk setup failed"));
                traverse_commit_list(&revs, record_recent_commit,
                                     record_recent_object, NULL);
        }
@@ -3110,7 +3135,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "all-progress-implied",
                         &all_progress_implied,
                         N_("similar to --all-progress when progress meter is shown")),
-               { OPTION_CALLBACK, 0, "index-version", NULL, N_("version[,offset]"),
+               { OPTION_CALLBACK, 0, "index-version", NULL, N_("<version>[,<offset>]"),
                  N_("write the pack index file in the specified idx format version"),
                  0, option_parse_index_version },
                OPT_MAGNITUDE(0, "max-pack-size", &pack_size_limit,
@@ -3188,7 +3213,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
        if (DFS_NUM_STATES > (1 << OE_DFS_STATE_BITS))
                BUG("too many dfs states, increase OE_DFS_STATE_BITS");
 
-       check_replace_refs = 0;
+       read_replace_refs = 0;
 
        reset_pack_idx_option(&pack_idx_opts);
        git_config(git_pack_config, NULL);
@@ -3254,35 +3279,35 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
        if (pack_compression_level == -1)
                pack_compression_level = Z_DEFAULT_COMPRESSION;
        else if (pack_compression_level < 0 || pack_compression_level > Z_BEST_COMPRESSION)
-               die("bad pack compression level %d", pack_compression_level);
+               die(_("bad pack compression level %d"), pack_compression_level);
 
        if (!delta_search_threads)      /* --threads=0 means autodetect */
                delta_search_threads = online_cpus();
 
 #ifdef NO_PTHREADS
        if (delta_search_threads != 1)
-               warning("no threads support, ignoring --threads");
+               warning(_("no threads support, ignoring --threads"));
 #endif
        if (!pack_to_stdout && !pack_size_limit)
                pack_size_limit = pack_size_limit_cfg;
        if (pack_to_stdout && pack_size_limit)
-               die("--max-pack-size cannot be used to build a pack for transfer.");
+               die(_("--max-pack-size cannot be used to build a pack for transfer"));
        if (pack_size_limit && pack_size_limit < 1024*1024) {
-               warning("minimum pack size limit is 1 MiB");
+               warning(_("minimum pack size limit is 1 MiB"));
                pack_size_limit = 1024*1024;
        }
 
        if (!pack_to_stdout && thin)
-               die("--thin cannot be used to build an indexable pack.");
+               die(_("--thin cannot be used to build an indexable pack"));
 
        if (keep_unreachable && unpack_unreachable)
-               die("--keep-unreachable and --unpack-unreachable are incompatible.");
+               die(_("--keep-unreachable and --unpack-unreachable are incompatible"));
        if (!rev_list_all || !rev_list_reflog || !rev_list_index)
                unpack_unreachable_expiration = 0;
 
        if (filter_options.choice) {
                if (!pack_to_stdout)
-                       die("cannot use --filter without --stdout.");
+                       die(_("cannot use --filter without --stdout"));
                use_bitmap_index = 0;
        }
 
@@ -3356,8 +3381,9 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
                prepare_pack(window, depth);
        write_pack_file();
        if (progress)
-               fprintf(stderr, "Total %"PRIu32" (delta %"PRIu32"),"
-                       " reused %"PRIu32" (delta %"PRIu32")\n",
-                       written, written_delta, reused, reused_delta);
+               fprintf_ln(stderr,
+                          _("Total %"PRIu32" (delta %"PRIu32"),"
+                            " reused %"PRIu32" (delta %"PRIu32")"),
+                          written, written_delta, reused, reused_delta);
        return 0;
 }
index 72b0621..4916a4d 100644 (file)
@@ -118,7 +118,7 @@ int cmd_prune(int argc, const char **argv, const char *prefix)
 
        expire = TIME_MAX;
        save_commit_buffer = 0;
-       check_replace_refs = 0;
+       read_replace_refs = 0;
        ref_paranoia = 1;
        init_revisions(&revs, prefix);
 
index 4e78935..53bc5fa 100644 (file)
@@ -48,11 +48,11 @@ static enum rebase_type parse_config_rebase(const char *key, const char *value,
                return REBASE_FALSE;
        else if (v > 0)
                return REBASE_TRUE;
-       else if (!strcmp(value, "preserve"))
+       else if (!strcmp(value, "preserve") || !strcmp(value, "p"))
                return REBASE_PRESERVE;
-       else if (!strcmp(value, "merges"))
+       else if (!strcmp(value, "merges") || !strcmp(value, "m"))
                return REBASE_MERGES;
-       else if (!strcmp(value, "interactive"))
+       else if (!strcmp(value, "interactive") || !strcmp(value, "i"))
                return REBASE_INTERACTIVE;
 
        if (fatal)
index 9cd8e8c..ef4c188 100644 (file)
@@ -558,9 +558,9 @@ int cmd_push(int argc, const char **argv, const char *prefix)
                OPT_BIT( 0,  "porcelain", &flags, N_("machine-readable output"), TRANSPORT_PUSH_PORCELAIN),
                OPT_BIT('f', "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE),
                { OPTION_CALLBACK,
-                 0, CAS_OPT_NAME, &cas, N_("refname>:<expect"),
+                 0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"),
                  N_("require old value of ref to be at this value"),
-                 PARSE_OPT_OPTARG, parseopt_push_cas_option },
+                 PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, parseopt_push_cas_option },
                { OPTION_CALLBACK, 0, "recurse-submodules", &recurse_submodules, "check|on-demand|no",
                        N_("control recursive pushing of submodules"),
                        PARSE_OPT_OPTARG, option_parse_recurse_submodules },
index ebc43eb..fbbc98e 100644 (file)
@@ -133,7 +133,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
                         N_("same as -m, but discard unmerged entries")),
                { OPTION_STRING, 0, "prefix", &opts.prefix, N_("<subdirectory>/"),
                  N_("read the tree into the index under <subdirectory>/"),
-                 PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP },
+                 PARSE_OPT_NONEG },
                OPT_BOOL('u', NULL, &opts.update,
                         N_("update working tree with merge result")),
                { OPTION_CALLBACK, 0, "exclude-per-directory", &opts,
index c74ee88..07bd51f 100644 (file)
@@ -566,7 +566,7 @@ static int read_remote_branches(const char *refname,
 
        strbuf_addf(&buf, "refs/remotes/%s/", rename->old_name);
        if (starts_with(refname, buf.buf)) {
-               item = string_list_append(rename->remote_branches, xstrdup(refname));
+               item = string_list_append(rename->remote_branches, refname);
                symref = resolve_ref_unsafe(refname, RESOLVE_REF_READING,
                                            NULL, &flag);
                if (symref && (flag & REF_ISSYMREF))
@@ -612,7 +612,7 @@ static int mv(int argc, const char **argv)
        struct remote *oldremote, *newremote;
        struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT, buf3 = STRBUF_INIT,
                old_remote_context = STRBUF_INIT;
-       struct string_list remote_branches = STRING_LIST_INIT_NODUP;
+       struct string_list remote_branches = STRING_LIST_INIT_DUP;
        struct rename_info rename;
        int i, refspec_updated = 0;
 
@@ -734,6 +734,7 @@ static int mv(int argc, const char **argv)
                if (create_symref(buf.buf, buf2.buf, buf3.buf))
                        die(_("creating '%s' failed"), buf.buf);
        }
+       string_list_clear(&remote_branches, 1);
        return 0;
 }
 
index ef22d72..4f05791 100644 (file)
@@ -54,7 +54,7 @@ static int show_reference(const char *refname, const struct object_id *oid,
                        enum object_type obj_type, repl_type;
 
                        if (get_oid(refname, &object))
-                               return error("Failed to resolve '%s' as a valid ref.", refname);
+                               return error(_("failed to resolve '%s' as a valid ref"), refname);
 
                        obj_type = oid_object_info(the_repository, &object,
                                                   NULL);
@@ -83,8 +83,8 @@ static int list_replace_refs(const char *pattern, const char *format)
        else if (!strcmp(format, "long"))
                data.format = REPLACE_FORMAT_LONG;
        else
-               return error("invalid replace format '%s'\n"
-                            "valid formats are 'short', 'medium' and 'long'\n",
+               return error(_("invalid replace format '%s'\n"
+                              "valid formats are 'short', 'medium' and 'long'"),
                             format);
 
        for_each_replace_ref(the_repository, show_reference, (void *)&data);
@@ -108,7 +108,7 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
 
        for (p = argv; *p; p++) {
                if (get_oid(*p, &oid)) {
-                       error("Failed to resolve '%s' as a valid ref.", *p);
+                       error("failed to resolve '%s' as a valid ref", *p);
                        had_error = 1;
                        continue;
                }
@@ -118,7 +118,7 @@ static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
                full_hex = ref.buf + base_len;
 
                if (read_ref(ref.buf, &oid)) {
-                       error("replace ref '%s' not found.", full_hex);
+                       error(_("replace ref '%s' not found"), full_hex);
                        had_error = 1;
                        continue;
                }
@@ -134,7 +134,7 @@ static int delete_replace_ref(const char *name, const char *ref,
 {
        if (delete_ref(NULL, ref, oid, 0))
                return 1;
-       printf("Deleted replace ref '%s'\n", name);
+       printf_ln(_("Deleted replace ref '%s'"), name);
        return 0;
 }
 
@@ -146,12 +146,12 @@ static int check_ref_valid(struct object_id *object,
        strbuf_reset(ref);
        strbuf_addf(ref, "%s%s", git_replace_ref_base, oid_to_hex(object));
        if (check_refname_format(ref->buf, 0))
-               return error("'%s' is not a valid ref name.", ref->buf);
+               return error(_("'%s' is not a valid ref name"), ref->buf);
 
        if (read_ref(ref->buf, prev))
                oidclr(prev);
        else if (!force)
-               return error("replace ref '%s' already exists", ref->buf);
+               return error(_("replace ref '%s' already exists"), ref->buf);
        return 0;
 }
 
@@ -171,10 +171,10 @@ static int replace_object_oid(const char *object_ref,
        obj_type = oid_object_info(the_repository, object, NULL);
        repl_type = oid_object_info(the_repository, repl, NULL);
        if (!force && obj_type != repl_type)
-               return error("Objects must be of the same type.\n"
-                            "'%s' points to a replaced object of type '%s'\n"
-                            "while '%s' points to a replacement object of "
-                            "type '%s'.",
+               return error(_("Objects must be of the same type.\n"
+                              "'%s' points to a replaced object of type '%s'\n"
+                              "while '%s' points to a replacement object of "
+                              "type '%s'."),
                             object_ref, type_name(obj_type),
                             replace_ref, type_name(repl_type));
 
@@ -200,10 +200,10 @@ static int replace_object(const char *object_ref, const char *replace_ref, int f
        struct object_id object, repl;
 
        if (get_oid(object_ref, &object))
-               return error("Failed to resolve '%s' as a valid ref.",
+               return error(_("failed to resolve '%s' as a valid ref"),
                             object_ref);
        if (get_oid(replace_ref, &repl))
-               return error("Failed to resolve '%s' as a valid ref.",
+               return error(_("failed to resolve '%s' as a valid ref"),
                             replace_ref);
 
        return replace_object_oid(object_ref, &object, replace_ref, &repl, force);
@@ -222,7 +222,7 @@ static int export_object(const struct object_id *oid, enum object_type type,
 
        fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
        if (fd < 0)
-               return error_errno("unable to open %s for writing", filename);
+               return error_errno(_("unable to open %s for writing"), filename);
 
        argv_array_push(&cmd.args, "--no-replace-objects");
        argv_array_push(&cmd.args, "cat-file");
@@ -235,7 +235,7 @@ static int export_object(const struct object_id *oid, enum object_type type,
        cmd.out = fd;
 
        if (run_command(&cmd))
-               return error("cat-file reported failure");
+               return error(_("cat-file reported failure"));
        return 0;
 }
 
@@ -251,7 +251,7 @@ static int import_object(struct object_id *oid, enum object_type type,
 
        fd = open(filename, O_RDONLY);
        if (fd < 0)
-               return error_errno("unable to open %s for reading", filename);
+               return error_errno(_("unable to open %s for reading"), filename);
 
        if (!raw && type == OBJ_TREE) {
                const char *argv[] = { "mktree", NULL };
@@ -265,11 +265,11 @@ static int import_object(struct object_id *oid, enum object_type type,
 
                if (start_command(&cmd)) {
                        close(fd);
-                       return error("unable to spawn mktree");
+                       return error(_("unable to spawn mktree"));
                }
 
                if (strbuf_read(&result, cmd.out, 41) < 0) {
-                       error_errno("unable to read from mktree");
+                       error_errno(_("unable to read from mktree"));
                        close(fd);
                        close(cmd.out);
                        return -1;
@@ -278,11 +278,11 @@ static int import_object(struct object_id *oid, enum object_type type,
 
                if (finish_command(&cmd)) {
                        strbuf_release(&result);
-                       return error("mktree reported failure");
+                       return error(_("mktree reported failure"));
                }
                if (get_oid_hex(result.buf, oid) < 0) {
                        strbuf_release(&result);
-                       return error("mktree did not return an object name");
+                       return error(_("mktree did not return an object name"));
                }
 
                strbuf_release(&result);
@@ -291,12 +291,12 @@ static int import_object(struct object_id *oid, enum object_type type,
                int flags = HASH_FORMAT_CHECK | HASH_WRITE_OBJECT;
 
                if (fstat(fd, &st) < 0) {
-                       error_errno("unable to fstat %s", filename);
+                       error_errno(_("unable to fstat %s"), filename);
                        close(fd);
                        return -1;
                }
                if (index_fd(oid, fd, &st, type, NULL, flags) < 0)
-                       return error("unable to write object to database");
+                       return error(_("unable to write object to database"));
                /* index_fd close()s fd for us */
        }
 
@@ -315,11 +315,11 @@ static int edit_and_replace(const char *object_ref, int force, int raw)
        struct strbuf ref = STRBUF_INIT;
 
        if (get_oid(object_ref, &old_oid) < 0)
-               return error("Not a valid object name: '%s'", object_ref);
+               return error(_("not a valid object name: '%s'"), object_ref);
 
        type = oid_object_info(the_repository, &old_oid, NULL);
        if (type < 0)
-               return error("unable to get object type for %s",
+               return error(_("unable to get object type for %s"),
                             oid_to_hex(&old_oid));
 
        if (check_ref_valid(&old_oid, &prev, &ref, force)) {
@@ -335,7 +335,7 @@ static int edit_and_replace(const char *object_ref, int force, int raw)
        }
        if (launch_editor(tmpfile, NULL, NULL) < 0) {
                free(tmpfile);
-               return error("editing object file failed");
+               return error(_("editing object file failed"));
        }
        if (import_object(&new_oid, type, raw, tmpfile)) {
                free(tmpfile);
@@ -344,7 +344,7 @@ static int edit_and_replace(const char *object_ref, int force, int raw)
        free(tmpfile);
 
        if (!oidcmp(&old_oid, &new_oid))
-               return error("new object is the same as the old one: '%s'", oid_to_hex(&old_oid));
+               return error(_("new object is the same as the old one: '%s'"), oid_to_hex(&old_oid));
 
        return replace_object_oid(object_ref, &old_oid, "replacement", &new_oid, force);
 }
@@ -368,7 +368,7 @@ static int replace_parents(struct strbuf *buf, int argc, const char **argv)
                struct object_id oid;
                if (get_oid(argv[i], &oid) < 0) {
                        strbuf_release(&new_parents);
-                       return error(_("Not a valid object name: '%s'"),
+                       return error(_("not a valid object name: '%s'"),
                                     argv[i]);
                }
                if (!lookup_commit_reference(the_repository, &oid)) {
@@ -412,7 +412,7 @@ static int check_one_mergetag(struct commit *commit,
        for (i = 1; i < mergetag_data->argc; i++) {
                struct object_id oid;
                if (get_oid(mergetag_data->argv[i], &oid) < 0)
-                       return error(_("Not a valid object name: '%s'"),
+                       return error(_("not a valid object name: '%s'"),
                                     mergetag_data->argv[i]);
                if (!oidcmp(&tag->tagged->oid, &oid))
                        return 0; /* found */
@@ -442,7 +442,7 @@ static int create_graft(int argc, const char **argv, int force, int gentle)
        unsigned long size;
 
        if (get_oid(old_ref, &old_oid) < 0)
-               return error(_("Not a valid object name: '%s'"), old_ref);
+               return error(_("not a valid object name: '%s'"), old_ref);
        commit = lookup_commit_reference(the_repository, &old_oid);
        if (!commit)
                return error(_("could not parse %s"), old_ref);
@@ -457,7 +457,7 @@ static int create_graft(int argc, const char **argv, int force, int gentle)
        }
 
        if (remove_signature(&buf)) {
-               warning(_("the original commit '%s' has a gpg signature."), old_ref);
+               warning(_("the original commit '%s' has a gpg signature"), old_ref);
                warning(_("the signature will be removed in the replacement commit!"));
        }
 
@@ -476,10 +476,10 @@ static int create_graft(int argc, const char **argv, int force, int gentle)
 
        if (!oidcmp(&old_oid, &new_oid)) {
                if (gentle) {
-                       warning("graft for '%s' unnecessary", oid_to_hex(&old_oid));
+                       warning(_("graft for '%s' unnecessary"), oid_to_hex(&old_oid));
                        return 0;
                }
-               return error("new commit is the same as the old one: '%s'", oid_to_hex(&old_oid));
+               return error(_("new commit is the same as the old one: '%s'"), oid_to_hex(&old_oid));
        }
 
        return replace_object_oid(old_ref, &old_oid, "replacement", &new_oid, force);
@@ -544,7 +544,7 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
                OPT_END()
        };
 
-       check_replace_refs = 0;
+       read_replace_refs = 0;
        git_config(git_default_config, NULL);
 
        argc = parse_options(argc, argv, prefix, options, git_replace_usage, 0);
@@ -553,7 +553,7 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
                cmdmode = argc ? MODE_REPLACE : MODE_LIST;
 
        if (format && cmdmode != MODE_LIST)
-               usage_msg_opt("--format cannot be used when not listing",
+               usage_msg_opt(_("--format cannot be used when not listing"),
                              git_replace_usage, options);
 
        if (force &&
@@ -561,47 +561,47 @@ int cmd_replace(int argc, const char **argv, const char *prefix)
            cmdmode != MODE_EDIT &&
            cmdmode != MODE_GRAFT &&
            cmdmode != MODE_CONVERT_GRAFT_FILE)
-               usage_msg_opt("-f only makes sense when writing a replacement",
+               usage_msg_opt(_("-f only makes sense when writing a replacement"),
                              git_replace_usage, options);
 
        if (raw && cmdmode != MODE_EDIT)
-               usage_msg_opt("--raw only makes sense with --edit",
+               usage_msg_opt(_("--raw only makes sense with --edit"),
                              git_replace_usage, options);
 
        switch (cmdmode) {
        case MODE_DELETE:
                if (argc < 1)
-                       usage_msg_opt("-d needs at least one argument",
+                       usage_msg_opt(_("-d needs at least one argument"),
                                      git_replace_usage, options);
                return for_each_replace_name(argv, delete_replace_ref);
 
        case MODE_REPLACE:
                if (argc != 2)
-                       usage_msg_opt("bad number of arguments",
+                       usage_msg_opt(_("bad number of arguments"),
                                      git_replace_usage, options);
                return replace_object(argv[0], argv[1], force);
 
        case MODE_EDIT:
                if (argc != 1)
-                       usage_msg_opt("-e needs exactly one argument",
+                       usage_msg_opt(_("-e needs exactly one argument"),
                                      git_replace_usage, options);
                return edit_and_replace(argv[0], force, raw);
 
        case MODE_GRAFT:
                if (argc < 1)
-                       usage_msg_opt("-g needs at least one argument",
+                       usage_msg_opt(_("-g needs at least one argument"),
                                      git_replace_usage, options);
                return create_graft(argc, argv, force, 0);
 
        case MODE_CONVERT_GRAFT_FILE:
                if (argc != 0)
-                       usage_msg_opt("--convert-graft-file takes no argument",
+                       usage_msg_opt(_("--convert-graft-file takes no argument"),
                                      git_replace_usage, options);
                return !!convert_graft_file(force);
 
        case MODE_LIST:
                if (argc > 1)
-                       usage_msg_opt("only one pattern can be given with -l",
+                       usage_msg_opt(_("only one pattern can be given with -l"),
                                      git_replace_usage, options);
                return list_replace_refs(argv[0], format);
 
index 65b448e..f4d3f00 100644 (file)
@@ -285,7 +285,7 @@ int cmd_rm(int argc, const char **argv, const char *prefix)
                list.entry[list.nr].is_submodule = S_ISGITLINK(ce->ce_mode);
                if (list.entry[list.nr++].is_submodule &&
                    !is_staging_gitmodules_ok(&the_index))
-                       die (_("Please stage your changes to .gitmodules or stash them to proceed"));
+                       die(_("please stage your changes to .gitmodules or stash them to proceed"));
        }
 
        if (pathspec.nr) {
index 42fd8d1..724b484 100644 (file)
@@ -178,7 +178,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
                OPT_BOOL(0, "stdin", &from_stdin, N_("read refs from stdin")),
                OPT_BOOL(0, "helper-status", &helper_status, N_("print status from remote helper")),
                { OPTION_CALLBACK,
-                 0, CAS_OPT_NAME, &cas, N_("refname>:<expect"),
+                 0, CAS_OPT_NAME, &cas, N_("<refname>:<expect>"),
                  N_("require old value of ref to be at this value"),
                  PARSE_OPT_OPTARG, parseopt_push_cas_option },
                OPT_END()
index 608d6ba..3898a2c 100644 (file)
@@ -268,8 +268,9 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)
                         N_("Suppress commit descriptions, only provides commit count")),
                OPT_BOOL('e', "email", &log.email,
                         N_("Show the email address of each author")),
-               { OPTION_CALLBACK, 'w', NULL, &log, N_("w[,i1[,i2]]"),
-                       N_("Linewrap output"), PARSE_OPT_OPTARG, &parse_wrap_args },
+               { OPTION_CALLBACK, 'w', NULL, &log, N_("<w>[,<i1>[,<i2>]]"),
+                       N_("Linewrap output"), PARSE_OPT_OPTARG,
+                       &parse_wrap_args },
                OPT_END(),
        };
 
index 4b9d3c0..363cf85 100644 (file)
@@ -674,7 +674,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
                { OPTION_CALLBACK, 'g', "reflog", &reflog_base, N_("<n>[,<base>]"),
                            N_("show <n> most recent ref-log entries starting at "
                               "base"),
-                           PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP,
+                           PARSE_OPT_OPTARG,
                            parse_reflog_param },
                OPT_END()
        };
index 716408e..30d9413 100644 (file)
@@ -514,7 +514,7 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
        int i;
        struct object_id oid;
 
-       check_replace_refs = 0;
+       read_replace_refs = 0;
 
        git_config(git_default_config, NULL);
 
index f5c0b6a..5aee2ea 100644 (file)
@@ -969,9 +969,9 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
                        PARSE_OPT_NOARG | /* disallow --cacheinfo=<mode> form */
                        PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
                        (parse_opt_cb *) cacheinfo_callback},
-               {OPTION_CALLBACK, 0, "chmod", &set_executable_bit, N_("(+/-)x"),
+               {OPTION_CALLBACK, 0, "chmod", &set_executable_bit, "(+|-)x",
                        N_("override the executable bit of the listed files"),
-                       PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
+                       PARSE_OPT_NONEG,
                        chmod_callback},
                {OPTION_SET_INT, 0, "assume-unchanged", &mark_valid_only, NULL,
                        N_("mark files as \"not changing\""),
index decde5a..42dc4da 100644 (file)
@@ -31,7 +31,7 @@ int cmd_upload_pack(int argc, const char **argv, const char *prefix)
        };
 
        packet_trace_identity("upload-pack");
-       check_replace_refs = 0;
+       read_replace_refs = 0;
 
        argc = parse_options(argc, argv, NULL, options, upload_pack_usage, 0);
 
index c9d3c54..cdcbf82 100644 (file)
@@ -24,9 +24,8 @@ int cmd_write_tree(int argc, const char **argv, const char *unused_prefix)
        struct option write_tree_options[] = {
                OPT_BIT(0, "missing-ok", &flags, N_("allow missing objects"),
                        WRITE_TREE_MISSING_OK),
-               { OPTION_STRING, 0, "prefix", &prefix, N_("<prefix>/"),
-                 N_("write tree object for a subdirectory <prefix>") ,
-                 PARSE_OPT_LITERAL_ARGHELP },
+               OPT_STRING(0, "prefix", &prefix, N_("<prefix>/"),
+                          N_("write tree object for a subdirectory <prefix>")),
                { OPTION_BIT, 0, "ignore-cache-tree", &flags, NULL,
                  N_("only useful for debugging"),
                  PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, NULL,
index cfd5328..9799e89 100644 (file)
@@ -51,6 +51,6 @@ int write_index_as_tree(struct object_id *oid, struct index_state *index_state,
 int write_cache_as_tree(struct object_id *oid, int flags, const char *prefix);
 void prime_cache_tree(struct index_state *, struct tree *);
 
-extern int cache_tree_matches_traversal(struct cache_tree *, struct name_entry *ent, struct traverse_info *info);
+int cache_tree_matches_traversal(struct cache_tree *, struct name_entry *ent, struct traverse_info *info);
 
 #endif
diff --git a/cache.h b/cache.h
index 8dc7134..1398b2a 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -868,11 +868,9 @@ void reset_shared_repository(void);
  * Do replace refs need to be checked this run?  This variable is
  * initialized to true unless --no-replace-object is used or
  * $GIT_NO_REPLACE_OBJECTS is set, but is set to false by some
- * commands that do not want replace references to be active.  As an
- * optimization it is also set to false if replace references have
- * been sought but there were none.
+ * commands that do not want replace references to be active.
  */
-extern int check_replace_refs;
+extern int read_replace_refs;
 extern char *git_replace_ref_base;
 
 extern int fsync_object_files;
@@ -1425,18 +1423,20 @@ extern void *read_object_with_reference(const struct object_id *oid,
 extern struct object *peel_to_type(const char *name, int namelen,
                                   struct object *o, enum object_type);
 
+enum date_mode_type {
+       DATE_NORMAL = 0,
+       DATE_RELATIVE,
+       DATE_SHORT,
+       DATE_ISO8601,
+       DATE_ISO8601_STRICT,
+       DATE_RFC2822,
+       DATE_STRFTIME,
+       DATE_RAW,
+       DATE_UNIX
+};
+
 struct date_mode {
-       enum date_mode_type {
-               DATE_NORMAL = 0,
-               DATE_RELATIVE,
-               DATE_SHORT,
-               DATE_ISO8601,
-               DATE_ISO8601_STRICT,
-               DATE_RFC2822,
-               DATE_STRFTIME,
-               DATE_RAW,
-               DATE_UNIX
-       } type;
+       enum date_mode_type type;
        const char *strftime_fmt;
        int local;
 };
index ceecc88..06970f7 100755 (executable)
@@ -97,7 +97,7 @@ fi
 export DEVELOPER=1
 export DEFAULT_TEST_TARGET=prove
 export GIT_PROVE_OPTS="--timer --jobs 3 --state=failed,slow,save"
-export GIT_TEST_OPTS="--verbose-log -x"
+export GIT_TEST_OPTS="--verbose-log -x --immediate"
 export GIT_TEST_CLONE_2GB=YesPlease
 if [ "$jobname" = linux-gcc ]; then
        export CC=gcc-8
index 4f261dd..d55460a 100755 (executable)
@@ -8,13 +8,24 @@
 # Tracing executed commands would produce too much noise in the loop below.
 set +x
 
-if ! ls t/test-results/*.exit >/dev/null 2>/dev/null
+cd t/
+
+if ! ls test-results/*.exit >/dev/null 2>/dev/null
 then
        echo "Build job failed before the tests could have been run"
        exit
 fi
 
-for TEST_EXIT in t/test-results/*.exit
+case "$jobname" in
+osx-clang|osx-gcc)
+       # base64 in OSX doesn't wrap its output at 76 columns by
+       # default, but prints a single, very long line.
+       base64_opts="-b 76"
+       ;;
+esac
+
+combined_trash_size=0
+for TEST_EXIT in test-results/*.exit
 do
        if [ "$(cat "$TEST_EXIT")" != "0" ]
        then
@@ -23,5 +34,45 @@ do
                echo "$(tput setaf 1)${TEST_OUT}...$(tput sgr0)"
                echo "------------------------------------------------------------------------"
                cat "${TEST_OUT}"
+
+               test_name="${TEST_EXIT%.exit}"
+               test_name="${test_name##*/}"
+               trash_dir="trash directory.$test_name"
+               trash_tgz_b64="trash.$test_name.base64"
+               if [ -d "$trash_dir" ]
+               then
+                       tar czp "$trash_dir" |base64 $base64_opts >"$trash_tgz_b64"
+
+                       trash_size=$(wc -c <"$trash_tgz_b64")
+                       if [ $trash_size -gt 1048576 ]
+                       then
+                               # larger than 1MB
+                               echo "$(tput setaf 1)Didn't include the trash directory of '$test_name' in the trace log, it's too big$(tput sgr0)"
+                               continue
+                       fi
+
+                       new_combined_trash_size=$(($combined_trash_size + $trash_size))
+                       if [ $new_combined_trash_size -gt 1048576 ]
+                       then
+                               echo "$(tput setaf 1)Didn't include the trash directory of '$test_name' in the trace log, there is plenty of trash in there already.$(tput sgr0)"
+                               continue
+                       fi
+                       combined_trash_size=$new_combined_trash_size
+
+                       # DO NOT modify these two 'echo'-ed strings below
+                       # without updating 'ci/util/extract-trash-dirs.sh'
+                       # as well.
+                       echo "$(tput setaf 1)Start of trash directory of '$test_name':$(tput sgr0)"
+                       cat "$trash_tgz_b64"
+                       echo "$(tput setaf 1)End of trash directory of '$test_name'$(tput sgr0)"
+               fi
        fi
 done
+
+if [ $combined_trash_size -gt 0 ]
+then
+       echo "------------------------------------------------------------------------"
+       echo "Trash directories embedded in this log can be extracted by running:"
+       echo
+       echo "  curl https://api.travis-ci.org/v3/job/$TRAVIS_JOB_ID/log.txt |./ci/util/extract-trash-dirs.sh"
+fi
index fe4ee4e..5688f26 100755 (executable)
@@ -5,6 +5,25 @@
 
 . ${0%/*}/lib-travisci.sh
 
-make coccicheck
+make --jobs=2 coccicheck
+
+set +x
+
+fail=
+for cocci_patch in contrib/coccinelle/*.patch
+do
+       if test -s "$cocci_patch"
+       then
+               echo "$(tput setaf 1)Coccinelle suggests the following changes in '$cocci_patch':$(tput sgr0)"
+               cat "$cocci_patch"
+               fail=UnfortunatelyYes
+       fi
+done
+
+if test -n "$fail"
+then
+       echo "$(tput setaf 1)error: Coccinelle suggested some changes$(tput sgr0)"
+       exit 1
+fi
 
 save_good_tree
diff --git a/ci/util/extract-trash-dirs.sh b/ci/util/extract-trash-dirs.sh
new file mode 100755 (executable)
index 0000000..8e67bec
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+error () {
+       echo >&2 "error: $@"
+       exit 1
+}
+
+find_embedded_trash () {
+       while read -r line
+       do
+               case "$line" in
+               *Start\ of\ trash\ directory\ of\ \'t[0-9][0-9][0-9][0-9]-*\':*)
+                       test_name="${line#*\'}"
+                       test_name="${test_name%\'*}"
+
+                       return 0
+               esac
+       done
+
+       return 1
+}
+
+extract_embedded_trash () {
+       while read -r line
+       do
+               case "$line" in
+               *End\ of\ trash\ directory\ of\ \'$test_name\'*)
+                       return
+                       ;;
+               *)
+                       printf '%s\n' "$line"
+                       ;;
+               esac
+       done
+
+       error "unexpected end of input"
+}
+
+# Raw logs from Linux build jobs have CRLF line endings, while OSX
+# build jobs mostly have CRCRLF, except an odd line every now and
+# then that has CRCRCRLF.  'base64 -d' from 'coreutils' doesn't like
+# CRs and complains about "invalid input", so remove all CRs at the
+# end of lines.
+sed -e 's/\r*$//' | \
+while find_embedded_trash
+do
+       echo "Extracting trash directory of '$test_name'"
+
+       extract_embedded_trash |base64 -d |tar xzp
+done
diff --git a/color.c b/color.c
index b1c24c6..ebb222e 100644 (file)
--- a/color.c
+++ b/color.c
@@ -343,6 +343,9 @@ int want_color_fd(int fd, int var)
 
        static int want_auto[3] = { -1, -1, -1 };
 
+       if (fd < 1 || fd >= ARRAY_SIZE(want_auto))
+               BUG("file descriptor out of range: %d", fd);
+
        if (var < 0)
                var = git_use_color_default;
 
index b0a55ad..0034740 100644 (file)
@@ -80,28 +80,28 @@ struct commit_graph *load_commit_graph_one(const char *graph_file)
 
        if (graph_size < GRAPH_MIN_SIZE) {
                close(fd);
-               die("graph file %s is too small", graph_file);
+               die(_("graph file %s is too small"), graph_file);
        }
        graph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);
        data = (const unsigned char *)graph_map;
 
        graph_signature = get_be32(data);
        if (graph_signature != GRAPH_SIGNATURE) {
-               error("graph signature %X does not match signature %X",
+               error(_("graph signature %X does not match signature %X"),
                      graph_signature, GRAPH_SIGNATURE);
                goto cleanup_fail;
        }
 
        graph_version = *(unsigned char*)(data + 4);
        if (graph_version != GRAPH_VERSION) {
-               error("graph version %X does not match version %X",
+               error(_("graph version %X does not match version %X"),
                      graph_version, GRAPH_VERSION);
                goto cleanup_fail;
        }
 
        hash_version = *(unsigned char*)(data + 5);
        if (hash_version != GRAPH_OID_VERSION) {
-               error("hash version %X does not match version %X",
+               error(_("hash version %X does not match version %X"),
                      hash_version, GRAPH_OID_VERSION);
                goto cleanup_fail;
        }
@@ -125,7 +125,7 @@ struct commit_graph *load_commit_graph_one(const char *graph_file)
                chunk_lookup += GRAPH_CHUNKLOOKUP_WIDTH;
 
                if (chunk_offset > graph_size - GIT_MAX_RAWSZ) {
-                       error("improper chunk offset %08x%08x", (uint32_t)(chunk_offset >> 32),
+                       error(_("improper chunk offset %08x%08x"), (uint32_t)(chunk_offset >> 32),
                              (uint32_t)chunk_offset);
                        goto cleanup_fail;
                }
@@ -161,7 +161,7 @@ struct commit_graph *load_commit_graph_one(const char *graph_file)
                }
 
                if (chunk_repeated) {
-                       error("chunk id %08x appears multiple times", chunk_id);
+                       error(_("chunk id %08x appears multiple times"), chunk_id);
                        goto cleanup_fail;
                }
 
@@ -258,7 +258,7 @@ static struct commit_list **insert_parent_or_die(struct commit_graph *g,
        hashcpy(oid.hash, g->chunk_oid_lookup + g->hash_len * pos);
        c = lookup_commit(the_repository, &oid);
        if (!c)
-               die("could not find commit %s", oid_to_hex(&oid));
+               die(_("could not find commit %s"), oid_to_hex(&oid));
        c->graph_pos = pos;
        return &commit_list_insert(c, pptr)->next;
 }
@@ -562,7 +562,7 @@ static int add_packed_commits(const struct object_id *oid,
 
        oi.typep = &type;
        if (packed_object_info(the_repository, pack, offset, &oi) < 0)
-               die("unable to get type of object %s", oid_to_hex(oid));
+               die(_("unable to get type of object %s"), oid_to_hex(oid));
 
        if (type != OBJ_COMMIT)
                return 0;
@@ -727,9 +727,9 @@ void write_commit_graph(const char *obj_dir,
                        strbuf_addstr(&packname, pack_indexes->items[i].string);
                        p = add_packed_git(packname.buf, packname.len, 1);
                        if (!p)
-                               die("error adding pack %s", packname.buf);
+                               die(_("error adding pack %s"), packname.buf);
                        if (open_pack_index(p))
-                               die("error opening index for %s", packname.buf);
+                               die(_("error opening index for %s"), packname.buf);
                        for_each_object_in_pack(p, add_packed_commits, &oids);
                        close_pack(p);
                }
index 6664504..4446909 100644 (file)
--- a/config.c
+++ b/config.c
@@ -117,12 +117,12 @@ static long config_buf_ftell(struct config_source *conf)
 }
 
 #define MAX_INCLUDE_DEPTH 10
-static const char include_depth_advice[] =
+static const char include_depth_advice[] = N_(
 "exceeded maximum include depth (%d) while including\n"
 "      %s\n"
 "from\n"
 "      %s\n"
-"Do you have circular includes?";
+"Do you have circular includes?");
 static int handle_path_include(const char *path, struct config_include_data *inc)
 {
        int ret = 0;
@@ -134,7 +134,7 @@ static int handle_path_include(const char *path, struct config_include_data *inc
 
        expanded = expand_user_path(path, 0);
        if (!expanded)
-               return error("could not expand include path '%s'", path);
+               return error(_("could not expand include path '%s'"), path);
        path = expanded;
 
        /*
@@ -145,7 +145,7 @@ static int handle_path_include(const char *path, struct config_include_data *inc
                char *slash;
 
                if (!cf || !cf->path)
-                       return error("relative config includes must come from files");
+                       return error(_("relative config includes must come from files"));
 
                slash = find_last_dir_sep(cf->path);
                if (slash)
@@ -156,7 +156,7 @@ static int handle_path_include(const char *path, struct config_include_data *inc
 
        if (!access_or_die(path, R_OK, 0)) {
                if (++inc->depth > MAX_INCLUDE_DEPTH)
-                       die(include_depth_advice, MAX_INCLUDE_DEPTH, path,
+                       die(_(include_depth_advice), MAX_INCLUDE_DEPTH, path,
                            !cf ? "<unknown>" :
                            cf->name ? cf->name :
                            "the command line");
@@ -343,13 +343,13 @@ static int git_config_parse_key_1(const char *key, char **store_key, int *basele
 
        if (last_dot == NULL || last_dot == key) {
                if (!quiet)
-                       error("key does not contain a section: %s", key);
+                       error(_("key does not contain a section: %s"), key);
                return -CONFIG_NO_SECTION_OR_NAME;
        }
 
        if (!last_dot[1]) {
                if (!quiet)
-                       error("key does not contain variable name: %s", key);
+                       error(_("key does not contain variable name: %s"), key);
                return -CONFIG_NO_SECTION_OR_NAME;
        }
 
@@ -373,13 +373,13 @@ static int git_config_parse_key_1(const char *key, char **store_key, int *basele
                        if (!iskeychar(c) ||
                            (i == baselen + 1 && !isalpha(c))) {
                                if (!quiet)
-                                       error("invalid key: %s", key);
+                                       error(_("invalid key: %s"), key);
                                goto out_free_ret_1;
                        }
                        c = tolower(c);
                } else if (c == '\n') {
                        if (!quiet)
-                               error("invalid key (newline): %s", key);
+                               error(_("invalid key (newline): %s"), key);
                        goto out_free_ret_1;
                }
                if (store_key)
@@ -415,7 +415,7 @@ int git_config_parse_parameter(const char *text,
 
        pair = strbuf_split_str(text, '=', 2);
        if (!pair[0])
-               return error("bogus config parameter: %s", text);
+               return error(_("bogus config parameter: %s"), text);
 
        if (pair[0]->len && pair[0]->buf[pair[0]->len - 1] == '=') {
                strbuf_setlen(pair[0], pair[0]->len - 1);
@@ -427,7 +427,7 @@ int git_config_parse_parameter(const char *text,
        strbuf_trim(pair[0]);
        if (!pair[0]->len) {
                strbuf_list_free(pair);
-               return error("bogus config parameter: %s", text);
+               return error(_("bogus config parameter: %s"), text);
        }
 
        if (git_config_parse_key(pair[0]->buf, &canonical_name, NULL)) {
@@ -462,7 +462,7 @@ int git_config_from_parameters(config_fn_t fn, void *data)
        envw = xstrdup(env);
 
        if (sq_dequote_to_argv(envw, &argv, &nr, &alloc) < 0) {
-               ret = error("bogus format in " CONFIG_DATA_ENVIRONMENT);
+               ret = error(_("bogus format in %s"), CONFIG_DATA_ENVIRONMENT);
                goto out;
        }
 
@@ -933,7 +933,7 @@ int git_parse_ulong(const char *value, unsigned long *ret)
        return 1;
 }
 
-static int git_parse_ssize_t(const char *value, ssize_t *ret)
+int git_parse_ssize_t(const char *value, ssize_t *ret)
 {
        intmax_t tmp;
        if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(ssize_t)))
@@ -1166,7 +1166,7 @@ static int git_default_core_config(const char *var, const char *value)
                else {
                        int abbrev = git_config_int(var, value);
                        if (abbrev < minimum_abbrev || abbrev > 40)
-                               return error("abbrev length out of range: %d", abbrev);
+                               return error(_("abbrev length out of range: %d"), abbrev);
                        default_abbrev = abbrev;
                }
                return 0;
@@ -1283,7 +1283,7 @@ static int git_default_core_config(const char *var, const char *value)
                        comment_line_char = value[0];
                        auto_comment_line_char = 0;
                } else
-                       return error("core.commentChar should only be one character");
+                       return error(_("core.commentChar should only be one character"));
                return 0;
        }
 
@@ -1353,6 +1353,11 @@ static int git_default_core_config(const char *var, const char *value)
                                         var, value);
        }
 
+       if (!strcmp(var, "core.usereplacerefs")) {
+               read_replace_refs = git_config_bool(var, value);
+               return 0;
+       }
+
        /* Add other config variables here and to Documentation/config.txt. */
        return 0;
 }
@@ -1391,7 +1396,7 @@ static int git_default_branch_config(const char *var, const char *value)
                else if (!strcmp(value, "always"))
                        autorebase = AUTOREBASE_ALWAYS;
                else
-                       return error("malformed value for %s", var);
+                       return error(_("malformed value for %s"), var);
                return 0;
        }
 
@@ -1417,9 +1422,9 @@ static int git_default_push_config(const char *var, const char *value)
                else if (!strcmp(value, "current"))
                        push_default = PUSH_DEFAULT_CURRENT;
                else {
-                       error("malformed value for %s: %s", var, value);
-                       return error("Must be one of nothing, matching, simple, "
-                                    "upstream or current.");
+                       error(_("malformed value for %s: %s"), var, value);
+                       return error(_("must be one of nothing, matching, simple, "
+                                      "upstream or current"));
                }
                return 0;
        }
@@ -1598,10 +1603,10 @@ int git_config_from_blob_oid(config_fn_t fn,
 
        buf = read_object_file(oid, &type, &size);
        if (!buf)
-               return error("unable to load config blob object '%s'", name);
+               return error(_("unable to load config blob object '%s'"), name);
        if (type != OBJ_BLOB) {
                free(buf);
-               return error("reference '%s' does not point to a blob", name);
+               return error(_("reference '%s' does not point to a blob"), name);
        }
 
        ret = git_config_from_mem(fn, CONFIG_ORIGIN_BLOB, name, buf, size,
@@ -1618,7 +1623,7 @@ static int git_config_from_blob_ref(config_fn_t fn,
        struct object_id oid;
 
        if (get_oid(name, &oid) < 0)
-               return error("unable to resolve config blob '%s'", name);
+               return error(_("unable to resolve config blob '%s'"), name);
        return git_config_from_blob_oid(fn, name, &oid, data);
 }
 
@@ -1648,7 +1653,7 @@ unsigned long git_env_ulong(const char *k, unsigned long val)
 {
        const char *v = getenv(k);
        if (v && !git_parse_ulong(v, &val))
-               die("failed to parse %s", k);
+               die(_("failed to parse %s"), k);
        return val;
 }
 
@@ -2365,7 +2370,7 @@ static int store_aux_event(enum config_event_t type,
 
        if (type == CONFIG_EVENT_SECTION) {
                if (cf->var.len < 2 || cf->var.buf[cf->var.len - 1] != '.')
-                       return error("invalid section name '%s'", cf->var.buf);
+                       return error(_("invalid section name '%s'"), cf->var.buf);
 
                /* Is this the section we were looking for? */
                store->is_keys_section =
@@ -2421,7 +2426,7 @@ static int store_aux(const char *key, const char *value, void *cb)
 
 static int write_error(const char *filename)
 {
-       error("failed to write new configuration file %s", filename);
+       error(_("failed to write new configuration file %s"), filename);
 
        /* Same error code as "failed to rename". */
        return 4;
@@ -2672,7 +2677,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
         */
        fd = hold_lock_file_for_update(&lock, config_filename, 0);
        if (fd < 0) {
-               error_errno("could not lock config file %s", config_filename);
+               error_errno(_("could not lock config file %s"), config_filename);
                ret = CONFIG_NO_LOCK;
                goto out_free;
        }
@@ -2683,7 +2688,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
        in_fd = open(config_filename, O_RDONLY);
        if ( in_fd < 0 ) {
                if ( ENOENT != errno ) {
-                       error_errno("opening %s", config_filename);
+                       error_errno(_("opening %s"), config_filename);
                        ret = CONFIG_INVALID_FILE; /* same as "invalid config file" */
                        goto out_free;
                }
@@ -2718,7 +2723,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
                        store.value_regex = (regex_t*)xmalloc(sizeof(regex_t));
                        if (regcomp(store.value_regex, value_regex,
                                        REG_EXTENDED)) {
-                               error("invalid pattern: %s", value_regex);
+                               error(_("invalid pattern: %s"), value_regex);
                                FREE_AND_NULL(store.value_regex);
                                ret = CONFIG_INVALID_PATTERN;
                                goto out_free;
@@ -2743,7 +2748,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
                if (git_config_from_file_with_options(store_aux,
                                                      config_filename,
                                                      &store, &opts)) {
-                       error("invalid config file %s", config_filename);
+                       error(_("invalid config file %s"), config_filename);
                        ret = CONFIG_INVALID_FILE;
                        goto out_free;
                }
@@ -2767,7 +2772,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
                if (contents == MAP_FAILED) {
                        if (errno == ENODEV && S_ISDIR(st.st_mode))
                                errno = EISDIR;
-                       error_errno("unable to mmap '%s'", config_filename);
+                       error_errno(_("unable to mmap '%s'"), config_filename);
                        ret = CONFIG_INVALID_FILE;
                        contents = NULL;
                        goto out_free;
@@ -2776,7 +2781,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
                in_fd = -1;
 
                if (chmod(get_lock_file_path(&lock), st.st_mode & 07777) < 0) {
-                       error_errno("chmod on %s failed", get_lock_file_path(&lock));
+                       error_errno(_("chmod on %s failed"), get_lock_file_path(&lock));
                        ret = CONFIG_NO_WRITE;
                        goto out_free;
                }
@@ -2861,7 +2866,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
        }
 
        if (commit_lock_file(&lock) < 0) {
-               error_errno("could not write config file %s", config_filename);
+               error_errno(_("could not write config file %s"), config_filename);
                ret = CONFIG_NO_WRITE;
                goto out_free;
        }
@@ -2987,7 +2992,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
        memset(&store, 0, sizeof(store));
 
        if (new_name && !section_name_is_ok(new_name)) {
-               ret = error("invalid section name: %s", new_name);
+               ret = error(_("invalid section name: %s"), new_name);
                goto out_no_rollback;
        }
 
@@ -2996,7 +3001,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
 
        out_fd = hold_lock_file_for_update(&lock, config_filename, 0);
        if (out_fd < 0) {
-               ret = error("could not lock config file %s", config_filename);
+               ret = error(_("could not lock config file %s"), config_filename);
                goto out;
        }
 
@@ -3014,7 +3019,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
        }
 
        if (chmod(get_lock_file_path(&lock), st.st_mode & 07777) < 0) {
-               ret = error_errno("chmod on %s failed",
+               ret = error_errno(_("chmod on %s failed"),
                                  get_lock_file_path(&lock));
                goto out;
        }
@@ -3111,7 +3116,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
        config_file = NULL;
 commit_and_out:
        if (commit_lock_file(&lock) < 0)
-               ret = error_errno("could not write config file %s",
+               ret = error_errno(_("could not write config file %s"),
                                  config_filename);
 out:
        if (config_file)
@@ -3154,7 +3159,7 @@ int git_config_copy_section(const char *old_name, const char *new_name)
 #undef config_error_nonbool
 int config_error_nonbool(const char *var)
 {
-       return error("missing value for '%s'", var);
+       return error(_("missing value for '%s'"), var);
 }
 
 int parse_config_key(const char *var,
index bb2f506..2d5c18b 100644 (file)
--- a/config.h
+++ b/config.h
@@ -82,6 +82,7 @@ extern void git_config(config_fn_t fn, void *);
 extern int config_with_options(config_fn_t fn, void *,
                               struct git_config_source *config_source,
                               const struct config_options *opts);
+extern int git_parse_ssize_t(const char *, ssize_t *);
 extern int git_parse_ulong(const char *, unsigned long *);
 extern int git_parse_maybe_bool(const char *);
 extern int git_config_int(const char *, const char *);
@@ -188,9 +189,14 @@ struct config_set {
 
 extern void git_configset_init(struct config_set *cs);
 extern int git_configset_add_file(struct config_set *cs, const char *filename);
-extern int git_configset_get_value(struct config_set *cs, const char *key, const char **value);
 extern const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key);
 extern void git_configset_clear(struct config_set *cs);
+
+/*
+ * These functions return 1 if not found, and 0 if found, leaving the found
+ * value in the 'dest' pointer.
+ */
+extern int git_configset_get_value(struct config_set *cs, const char *key, const char **dest);
 extern int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest);
 extern int git_configset_get_string(struct config_set *cs, const char *key, char **dest);
 extern int git_configset_get_int(struct config_set *cs, const char *key, int *dest);
index 2d244ca..9a99814 100644 (file)
@@ -1,6 +1,11 @@
 ifeq ($(filter no-error,$(DEVOPTS)),)
 CFLAGS += -Werror
 endif
+ifneq ($(filter pedantic,$(DEVOPTS)),)
+CFLAGS += -pedantic
+# don't warn for each N_ use
+CFLAGS += -DUSE_PARENS_AROUND_GETTEXT_N=0
+endif
 CFLAGS += -Wdeclaration-after-statement
 CFLAGS += -Wno-format-zero-length
 CFLAGS += -Wold-style-definition
index 684fc5b..2be2f19 100644 (file)
@@ -528,7 +528,7 @@ ifneq (,$(findstring MINGW,$(uname_S)))
        COMPAT_OBJS += compat/mingw.o compat/winansi.o \
                compat/win32/pthread.o compat/win32/syslog.o \
                compat/win32/dirent.o
-       BASIC_CFLAGS += -DPROTECT_NTFS_DEFAULT=1
+       BASIC_CFLAGS += -DWIN32 -DPROTECT_NTFS_DEFAULT=1
        EXTLIBS += -lws2_32
        GITLIBS += git.res
        PTHREAD_LIBS =
index 968e91b..94547e5 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -58,7 +58,7 @@ static NORETURN void die_initial_contact(int unexpected)
         * response does not necessarily mean an ACL problem, though.
         */
        if (unexpected)
-               die(_("The remote end hung up upon initial contact"));
+               die(_("the remote end hung up upon initial contact"));
        else
                die(_("Could not read from remote repository.\n\n"
                      "Please make sure you have the correct access rights\n"
@@ -78,7 +78,7 @@ int server_supports_v2(const char *c, int die_on_error)
        }
 
        if (die_on_error)
-               die("server doesn't support '%s'", c);
+               die(_("server doesn't support '%s'"), c);
 
        return 0;
 }
@@ -100,7 +100,7 @@ int server_supports_feature(const char *c, const char *feature,
        }
 
        if (die_on_error)
-               die("server doesn't support feature '%s'", feature);
+               die(_("server doesn't support feature '%s'"), feature);
 
        return 0;
 }
@@ -111,7 +111,7 @@ static void process_capabilities_v2(struct packet_reader *reader)
                argv_array_push(&server_capabilities_v2, reader->line);
 
        if (reader->status != PACKET_READ_FLUSH)
-               die("expected flush after capabilities");
+               die(_("expected flush after capabilities"));
 }
 
 enum protocol_version discover_version(struct packet_reader *reader)
@@ -230,7 +230,7 @@ static int process_dummy_ref(const char *line)
 static void check_no_capabilities(const char *line, int len)
 {
        if (strlen(line) != len)
-               warning("Ignoring capabilities after first line '%s'",
+               warning(_("ignoring capabilities after first line '%s'"),
                        line + strlen(line));
 }
 
@@ -249,7 +249,7 @@ static int process_ref(const char *line, int len, struct ref ***list,
        if (extra_have && !strcmp(name, ".have")) {
                oid_array_append(extra_have, &old_oid);
        } else if (!strcmp(name, "capabilities^{}")) {
-               die("protocol error: unexpected capabilities^{}");
+               die(_("protocol error: unexpected capabilities^{}"));
        } else if (check_ref(name, flags)) {
                struct ref *ref = alloc_ref(name);
                oidcpy(&ref->old_oid, &old_oid);
@@ -270,9 +270,9 @@ static int process_shallow(const char *line, int len,
                return 0;
 
        if (get_oid_hex(arg, &old_oid))
-               die("protocol error: expected shallow sha-1, got '%s'", arg);
+               die(_("protocol error: expected shallow sha-1, got '%s'"), arg);
        if (!shallow_points)
-               die("repository on the other end cannot be shallow");
+               die(_("repository on the other end cannot be shallow"));
        oid_array_append(shallow_points, &old_oid);
        check_no_capabilities(line, len);
        return 1;
@@ -307,13 +307,13 @@ struct ref **get_remote_heads(struct packet_reader *reader,
                case PACKET_READ_NORMAL:
                        len = reader->pktlen;
                        if (len > 4 && skip_prefix(reader->line, "ERR ", &arg))
-                               die("remote error: %s", arg);
+                               die(_("remote error: %s"), arg);
                        break;
                case PACKET_READ_FLUSH:
                        state = EXPECTING_DONE;
                        break;
                case PACKET_READ_DELIM:
-                       die("invalid packet");
+                       die(_("invalid packet"));
                }
 
                switch (state) {
@@ -333,7 +333,7 @@ struct ref **get_remote_heads(struct packet_reader *reader,
                case EXPECTING_SHALLOW:
                        if (process_shallow(reader->line, len, shallow_points))
                                break;
-                       die("protocol error: unexpected '%s'", reader->line);
+                       die(_("protocol error: unexpected '%s'"), reader->line);
                case EXPECTING_DONE:
                        break;
                }
@@ -441,11 +441,11 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
        /* Process response from server */
        while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
                if (!process_ref_v2(reader->line, &list))
-                       die("invalid ls-refs response: %s", reader->line);
+                       die(_("invalid ls-refs response: %s"), reader->line);
        }
 
        if (reader->status != PACKET_READ_FLUSH)
-               die("expected flush after ref listing");
+               die(_("expected flush after ref listing"));
 
        return list;
 }
@@ -544,7 +544,7 @@ static enum protocol get_protocol(const char *name)
                return PROTO_SSH;
        if (!strcmp(name, "file"))
                return PROTO_FILE;
-       die("I don't handle protocol '%s'", name);
+       die(_("protocol '%s' is not supported"), name);
 }
 
 static char *host_end(char **hoststart, int removebrackets)
@@ -595,8 +595,7 @@ static void enable_keepalive(int sockfd)
        int ka = 1;
 
        if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &ka, sizeof(ka)) < 0)
-               fprintf(stderr, "unable to set SO_KEEPALIVE on socket: %s\n",
-                       strerror(errno));
+               error_errno(_("unable to set SO_KEEPALIVE on socket"));
 }
 
 #ifndef NO_IPV6
@@ -636,14 +635,15 @@ static int git_tcp_connect_sock(char *host, int flags)
        hints.ai_protocol = IPPROTO_TCP;
 
        if (flags & CONNECT_VERBOSE)
-               fprintf(stderr, "Looking up %s ... ", host);
+               fprintf(stderr, _("Looking up %s ... "), host);
 
        gai = getaddrinfo(host, port, &hints, &ai);
        if (gai)
-               die("Unable to look up %s (port %s) (%s)", host, port, gai_strerror(gai));
+               die(_("unable to look up %s (port %s) (%s)"), host, port, gai_strerror(gai));
 
        if (flags & CONNECT_VERBOSE)
-               fprintf(stderr, "done.\nConnecting to %s (port %s) ... ", host, port);
+               /* TRANSLATORS: this is the end of "Looking up %s ... " */
+               fprintf(stderr, _("done.\nConnecting to %s (port %s) ... "), host, port);
 
        for (ai0 = ai; ai; ai = ai->ai_next, cnt++) {
                sockfd = socket(ai->ai_family,
@@ -665,12 +665,13 @@ static int git_tcp_connect_sock(char *host, int flags)
        freeaddrinfo(ai0);
 
        if (sockfd < 0)
-               die("unable to connect to %s:\n%s", host, error_message.buf);
+               die(_("unable to connect to %s:\n%s"), host, error_message.buf);
 
        enable_keepalive(sockfd);
 
        if (flags & CONNECT_VERBOSE)
-               fprintf(stderr, "done.\n");
+               /* TRANSLATORS: this is the end of "Connecting to %s (port %s) ... " */
+               fprintf_ln(stderr, _("done."));
 
        strbuf_release(&error_message);
 
@@ -697,22 +698,23 @@ static int git_tcp_connect_sock(char *host, int flags)
        get_host_and_port(&host, &port);
 
        if (flags & CONNECT_VERBOSE)
-               fprintf(stderr, "Looking up %s ... ", host);
+               fprintf(stderr, _("Looking up %s ... "), host);
 
        he = gethostbyname(host);
        if (!he)
-               die("Unable to look up %s (%s)", host, hstrerror(h_errno));
+               die(_("unable to look up %s (%s)"), host, hstrerror(h_errno));
        nport = strtoul(port, &ep, 10);
        if ( ep == port || *ep ) {
                /* Not numeric */
                struct servent *se = getservbyname(port,"tcp");
                if ( !se )
-                       die("Unknown port %s", port);
+                       die(_("unknown port %s"), port);
                nport = se->s_port;
        }
 
        if (flags & CONNECT_VERBOSE)
-               fprintf(stderr, "done.\nConnecting to %s (port %s) ... ", host, port);
+               /* TRANSLATORS: this is the end of "Looking up %s ... " */
+               fprintf(stderr, _("done.\nConnecting to %s (port %s) ... "), host, port);
 
        for (cnt = 0, ap = he->h_addr_list; *ap; ap++, cnt++) {
                memset(&sa, 0, sizeof sa);
@@ -740,12 +742,13 @@ static int git_tcp_connect_sock(char *host, int flags)
        }
 
        if (sockfd < 0)
-               die("unable to connect to %s:\n%s", host, error_message.buf);
+               die(_("unable to connect to %s:\n%s"), host, error_message.buf);
 
        enable_keepalive(sockfd);
 
        if (flags & CONNECT_VERBOSE)
-               fprintf(stderr, "done.\n");
+               /* TRANSLATORS: this is the end of "Connecting to %s (port %s) ... " */
+               fprintf_ln(stderr, _("done."));
 
        return sockfd;
 }
@@ -842,9 +845,9 @@ static struct child_process *git_proxy_connect(int fd[2], char *host)
        get_host_and_port(&host, &port);
 
        if (looks_like_command_line_option(host))
-               die("strange hostname '%s' blocked", host);
+               die(_("strange hostname '%s' blocked"), host);
        if (looks_like_command_line_option(port))
-               die("strange port '%s' blocked", port);
+               die(_("strange port '%s' blocked"), port);
 
        proxy = xmalloc(sizeof(*proxy));
        child_process_init(proxy);
@@ -854,7 +857,7 @@ static struct child_process *git_proxy_connect(int fd[2], char *host)
        proxy->in = -1;
        proxy->out = -1;
        if (start_command(proxy))
-               die("cannot start proxy %s", git_proxy_command);
+               die(_("cannot start proxy %s"), git_proxy_command);
        fd[0] = proxy->out; /* read from proxy stdout */
        fd[1] = proxy->in;  /* write to proxy stdin */
        return proxy;
@@ -921,7 +924,7 @@ static enum protocol parse_connect_url(const char *url_orig, char **ret_host,
                path = strchr(end, separator);
 
        if (!path || !*path)
-               die("No path specified. See 'man git-pull' for valid url syntax");
+               die(_("no path specified; see 'git help pull' for valid url syntax"));
 
        /*
         * null-terminate hostname and point path to ~ for URL's like this:
@@ -1116,7 +1119,7 @@ static void push_ssh_options(struct argv_array *args, struct argv_array *env,
                case VARIANT_AUTO:
                        BUG("VARIANT_AUTO passed to push_ssh_options");
                case VARIANT_SIMPLE:
-                       die("ssh variant 'simple' does not support -4");
+                       die(_("ssh variant 'simple' does not support -4"));
                case VARIANT_SSH:
                case VARIANT_PLINK:
                case VARIANT_PUTTY:
@@ -1128,7 +1131,7 @@ static void push_ssh_options(struct argv_array *args, struct argv_array *env,
                case VARIANT_AUTO:
                        BUG("VARIANT_AUTO passed to push_ssh_options");
                case VARIANT_SIMPLE:
-                       die("ssh variant 'simple' does not support -6");
+                       die(_("ssh variant 'simple' does not support -6"));
                case VARIANT_SSH:
                case VARIANT_PLINK:
                case VARIANT_PUTTY:
@@ -1145,7 +1148,7 @@ static void push_ssh_options(struct argv_array *args, struct argv_array *env,
                case VARIANT_AUTO:
                        BUG("VARIANT_AUTO passed to push_ssh_options");
                case VARIANT_SIMPLE:
-                       die("ssh variant 'simple' does not support setting port");
+                       die(_("ssh variant 'simple' does not support setting port"));
                case VARIANT_SSH:
                        argv_array_push(args, "-p");
                        break;
@@ -1168,7 +1171,7 @@ static void fill_ssh_args(struct child_process *conn, const char *ssh_host,
        enum ssh_variant variant;
 
        if (looks_like_command_line_option(ssh_host))
-               die("strange hostname '%s' blocked", ssh_host);
+               die(_("strange hostname '%s' blocked"), ssh_host);
 
        ssh = get_ssh_command();
        if (ssh) {
@@ -1256,7 +1259,7 @@ struct child_process *git_connect(int fd[2], const char *url,
                child_process_init(conn);
 
                if (looks_like_command_line_option(path))
-                       die("strange pathname '%s' blocked", path);
+                       die(_("strange pathname '%s' blocked"), path);
 
                strbuf_addstr(&cmd, prog);
                strbuf_addch(&cmd, ' ');
@@ -1301,7 +1304,7 @@ struct child_process *git_connect(int fd[2], const char *url,
                argv_array_push(&conn->args, cmd.buf);
 
                if (start_command(conn))
-                       die("unable to fork");
+                       die(_("unable to fork"));
 
                fd[0] = conn->out; /* read from child's stdout */
                fd[1] = conn->in;  /* write to child's stdin */
index 22f069d..cfbfe7d 100755 (executable)
@@ -247,7 +247,7 @@ test_expect_success 'Test of resistance to modification of category on wiki for
        wiki_editpage Notconsidered "this page will not appear on local" false &&
        wiki_editpage Othercategory "this page will not appear on local" false -c=Cattwo &&
        wiki_editpage Tobeedited "this page have been modified" true -c=Catone &&
-       wiki_delete_page Tobedeleted
+       wiki_delete_page Tobedeleted &&
        git clone -c remote.origin.categories="Catone" \
                mediawiki::'"$WIKI_URL"' mw_dir_14 &&
        wiki_getallpage ref_page_14 Catone &&
index d05c613..57ff4b2 100755 (executable)
@@ -540,26 +540,10 @@ test_expect_success 'make sure exactly the right set of files ends up in the sub
                git fetch .. subproj-br &&
                git merge FETCH_HEAD &&
 
-               chks="sub1
-sub2
-sub3
-sub4" &&
-               chks_sub=$(cat <<TXT | sed '\''s,^,sub dir/,'\''
-$chks
-TXT
-) &&
-               chkms="main-sub1
-main-sub2
-main-sub3
-main-sub4" &&
-               chkms_sub=$(cat <<TXT | sed '\''s,^,sub dir/,'\''
-$chkms
-TXT
-) &&
-
-               subfiles=$(git ls-files) &&
-               check_equal "$subfiles" "$chkms
-$chks"
+               test_write_lines main-sub1 main-sub2 main-sub3 main-sub4 \
+                       sub1 sub2 sub3 sub4 >expect &&
+               git ls-files >actual &&
+               test_cmp expect actual
        )
 '
 
@@ -606,25 +590,11 @@ test_expect_success 'make sure the subproj *only* contains commits that affect t
                git fetch .. subproj-br &&
                git merge FETCH_HEAD &&
 
-               chks="sub1
-sub2
-sub3
-sub4" &&
-               chks_sub=$(cat <<TXT | sed '\''s,^,sub dir/,'\''
-$chks
-TXT
-) &&
-               chkms="main-sub1
-main-sub2
-main-sub3
-main-sub4" &&
-               chkms_sub=$(cat <<TXT | sed '\''s,^,sub dir/,'\''
-$chkms
-TXT
-) &&
-               allchanges=$(git log --name-only --pretty=format:"" | sort | sed "/^$/d") &&
-               check_equal "$allchanges" "$chkms
-$chks"
+               test_write_lines main-sub1 main-sub2 main-sub3 main-sub4 \
+                       sub1 sub2 sub3 sub4 >expect &&
+               git log --name-only --pretty=format:"" >log &&
+               sort <log | sed "/^\$/ d" >actual &&
+               test_cmp expect actual
        )
 '
 
@@ -675,29 +645,16 @@ test_expect_success 'make sure exactly the right set of files ends up in the mai
                cd "$subtree_test_count" &&
                git subtree pull --prefix="sub dir" ./"sub proj" master &&
 
-               chkm="main1
-main2" &&
-               chks="sub1
-sub2
-sub3
-sub4" &&
-               chks_sub=$(cat <<TXT | sed '\''s,^,sub dir/,'\''
-$chks
-TXT
-) &&
-               chkms="main-sub1
-main-sub2
-main-sub3
-main-sub4" &&
-               chkms_sub=$(cat <<TXT | sed '\''s,^,sub dir/,'\''
-$chkms
-TXT
-) &&
-               mainfiles=$(git ls-files) &&
-               check_equal "$mainfiles" "$chkm
-$chkms_sub
-$chks_sub"
-)
+               test_write_lines main1 main2 >chkm &&
+               test_write_lines main-sub1 main-sub2 main-sub3 main-sub4 >chkms &&
+               sed "s,^,sub dir/," chkms >chkms_sub &&
+               test_write_lines sub1 sub2 sub3 sub4 >chks &&
+               sed "s,^,sub dir/," chks >chks_sub &&
+
+               cat chkm chkms_sub chks_sub >expect &&
+               git ls-files >actual &&
+               test_cmp expect actual
+       )
 '
 
 next_test
@@ -708,7 +665,7 @@ test_expect_success 'make sure each filename changed exactly once in the entire
        test_create_commit "$subtree_test_count/sub proj" sub1 &&
        (
                cd "$subtree_test_count" &&
-               git config log.date relative
+               git config log.date relative &&
                git fetch ./"sub proj" master &&
                git subtree add --prefix="sub dir" FETCH_HEAD
        ) &&
@@ -748,37 +705,21 @@ test_expect_success 'make sure each filename changed exactly once in the entire
                cd "$subtree_test_count" &&
                git subtree pull --prefix="sub dir" ./"sub proj" master &&
 
-               chkm="main1
-main2" &&
-               chks="sub1
-sub2
-sub3
-sub4" &&
-               chks_sub=$(cat <<TXT | sed '\''s,^,sub dir/,'\''
-$chks
-TXT
-) &&
-               chkms="main-sub1
-main-sub2
-main-sub3
-main-sub4" &&
-               chkms_sub=$(cat <<TXT | sed '\''s,^,sub dir/,'\''
-$chkms
-TXT
-) &&
+               test_write_lines main1 main2 >chkm &&
+               test_write_lines sub1 sub2 sub3 sub4 >chks &&
+               test_write_lines main-sub1 main-sub2 main-sub3 main-sub4 >chkms &&
+               sed "s,^,sub dir/," chkms >chkms_sub &&
 
                # main-sub?? and /"sub dir"/main-sub?? both change, because those are the
                # changes that were split into their own history.  And "sub dir"/sub?? never
                # change, since they were *only* changed in the subtree branch.
-               allchanges=$(git log --name-only --pretty=format:"" | sort | sed "/^$/d") &&
-               expected=''"$(cat <<TXT | sort
-$chkms
-$chkm
-$chks
-$chkms_sub
-TXT
-)"'' &&
-               check_equal "$allchanges" "$expected"
+               git log --name-only --pretty=format:"" >log &&
+               sort <log >sorted-log &&
+               sed "/^$/ d" sorted-log >actual &&
+
+               cat chkms chkm chks chkms_sub >expect-unsorted &&
+               sort expect-unsorted >expect &&
+               test_cmp expect actual
        )
 '
 
diff --git a/contrib/vscode/.gitattributes b/contrib/vscode/.gitattributes
new file mode 100644 (file)
index 0000000..e89f223
--- /dev/null
@@ -0,0 +1 @@
+init.sh whitespace=-indent-with-non-tab
diff --git a/contrib/vscode/README.md b/contrib/vscode/README.md
new file mode 100644 (file)
index 0000000..8202d62
--- /dev/null
@@ -0,0 +1,14 @@
+Configuration for VS Code
+=========================
+
+[VS Code](https://code.visualstudio.com/) is a lightweight but powerful source
+code editor which runs on your desktop and is available for
+[Windows](https://code.visualstudio.com/docs/setup/windows),
+[macOS](https://code.visualstudio.com/docs/setup/mac) and
+[Linux](https://code.visualstudio.com/docs/setup/linux). Among other languages,
+it has [support for C/C++ via an extension](https://github.com/Microsoft/vscode-cpptools).
+
+To start developing Git with VS Code, simply run the Unix shell script called
+`init.sh` in this directory, which creates the configuration files in
+`.vscode/` that VS Code consumes. `init.sh` needs access to `make` and `gcc`,
+so run the script in a Git SDK shell if you are using Windows.
diff --git a/contrib/vscode/init.sh b/contrib/vscode/init.sh
new file mode 100755 (executable)
index 0000000..27de949
--- /dev/null
@@ -0,0 +1,375 @@
+#!/bin/sh
+
+die () {
+       echo "$*" >&2
+       exit 1
+}
+
+cd "$(dirname "$0")"/../.. ||
+die "Could not cd to top-level directory"
+
+mkdir -p .vscode ||
+die "Could not create .vscode/"
+
+# General settings
+
+cat >.vscode/settings.json.new <<\EOF ||
+{
+    "C_Cpp.intelliSenseEngine": "Default",
+    "C_Cpp.intelliSenseEngineFallback": "Disabled",
+    "[git-commit]": {
+        "editor.wordWrap": "wordWrapColumn",
+        "editor.wordWrapColumn": 72
+    },
+    "[c]": {
+        "editor.detectIndentation": false,
+        "editor.insertSpaces": false,
+        "editor.tabSize": 8,
+        "editor.wordWrap": "wordWrapColumn",
+        "editor.wordWrapColumn": 80,
+        "files.trimTrailingWhitespace": true
+    },
+    "files.associations": {
+        "*.h": "c",
+        "*.c": "c"
+    },
+    "cSpell.ignorePaths": [
+    ],
+    "cSpell.words": [
+        "DATAW",
+        "DBCACHED",
+        "DFCHECK",
+        "DTYPE",
+        "Hamano",
+        "HCAST",
+        "HEXSZ",
+        "HKEY",
+        "HKLM",
+        "IFGITLINK",
+        "IFINVALID",
+        "ISBROKEN",
+        "ISGITLINK",
+        "ISSYMREF",
+        "Junio",
+        "LPDWORD",
+        "LPPROC",
+        "LPWSTR",
+        "MSVCRT",
+        "NOARG",
+        "NOCOMPLETE",
+        "NOINHERIT",
+        "RENORMALIZE",
+        "STARTF",
+        "STARTUPINFOEXW",
+        "Schindelin",
+        "UCRT",
+        "YESNO",
+        "argcp",
+        "beginthreadex",
+        "committish",
+        "contentp",
+        "cpath",
+        "cpidx",
+        "ctim",
+        "dequote",
+        "envw",
+        "ewah",
+        "fdata",
+        "fherr",
+        "fhin",
+        "fhout",
+        "fragp",
+        "fsmonitor",
+        "hnsec",
+        "idents",
+        "includeif",
+        "interpr",
+        "iprog",
+        "isexe",
+        "iskeychar",
+        "kompare",
+        "mksnpath",
+        "mktag",
+        "mktree",
+        "mmblob",
+        "mmbuffer",
+        "mmfile",
+        "noenv",
+        "nparents",
+        "ntpath",
+        "ondisk",
+        "ooid",
+        "oplen",
+        "osdl",
+        "pnew",
+        "pold",
+        "ppinfo",
+        "pushf",
+        "pushv",
+        "rawsz",
+        "rebasing",
+        "reencode",
+        "repo",
+        "rerere",
+        "scld",
+        "sharedrepo",
+        "spawnv",
+        "spawnve",
+        "spawnvpe",
+        "strdup'ing",
+        "submodule",
+        "submodules",
+        "topath",
+        "topo",
+        "tpatch",
+        "unexecutable",
+        "unhide",
+        "unkc",
+        "unkv",
+        "unmark",
+        "unmatch",
+        "unsets",
+        "unshown",
+        "untracked",
+        "untrackedcache",
+        "unuse",
+        "upos",
+        "uval",
+        "vreportf",
+        "wargs",
+        "wargv",
+        "wbuffer",
+        "wcmd",
+        "wcsnicmp",
+        "wcstoutfdup",
+        "wdeltaenv",
+        "wdir",
+        "wenv",
+        "wenvblk",
+        "wenvcmp",
+        "wenviron",
+        "wenvpos",
+        "wenvsz",
+        "wfile",
+        "wfilename",
+        "wfopen",
+        "wfreopen",
+        "wfullpath",
+        "which'll",
+        "wlink",
+        "wmain",
+        "wmkdir",
+        "wmktemp",
+        "wnewpath",
+        "wotype",
+        "wpath",
+        "wpathname",
+        "wpgmptr",
+        "wpnew",
+        "wpointer",
+        "wpold",
+        "wpos",
+        "wputenv",
+        "wrmdir",
+        "wship",
+        "wtarget",
+        "wtemplate",
+        "wunlink",
+        "xcalloc",
+        "xgetcwd",
+        "xmallocz",
+        "xmemdupz",
+        "xmmap",
+        "xopts",
+        "xrealloc",
+        "xsnprintf",
+        "xutftowcs",
+        "xutftowcsn",
+        "xwcstoutf"
+    ],
+    "cSpell.ignoreRegExpList": [
+        "\\\"(DIRC|FSMN|REUC|UNTR)\\\"",
+        "\\\\u[0-9a-fA-Fx]{4}\\b",
+        "\\b(filfre|frotz|xyzzy)\\b",
+        "\\bCMIT_FMT_DEFAULT\\b",
+        "\\bde-munge\\b",
+        "\\bGET_OID_DISAMBIGUATORS\\b",
+        "\\bHASH_RENORMALIZE\\b",
+        "\\bTREESAMEness\\b",
+        "\\bUSE_STDEV\\b",
+        "\\Wchar *\\*\\W*utfs\\W",
+        "cURL's",
+        "nedmalloc'ed",
+        "ntifs\\.h",
+    ],
+}
+EOF
+die "Could not write settings.json"
+
+# Infer some setup-specific locations/names
+
+GCCPATH="$(which gcc)"
+GDBPATH="$(which gdb)"
+MAKECOMMAND="make -j5 DEVELOPER=1"
+OSNAME=
+X=
+case "$(uname -s)" in
+MINGW*)
+       GCCPATH="$(cygpath -am "$GCCPATH")"
+       GDBPATH="$(cygpath -am "$GDBPATH")"
+       MAKE_BASH="$(cygpath -am /git-cmd.exe) --command=usr\\\\bin\\\\bash.exe"
+       MAKECOMMAND="$MAKE_BASH -lc \\\"$MAKECOMMAND\\\""
+       OSNAME=Win32
+       X=.exe
+       ;;
+Linux)
+       OSNAME=Linux
+       ;;
+Darwin)
+       OSNAME=macOS
+       ;;
+esac
+
+# Default build task
+
+cat >.vscode/tasks.json.new <<EOF ||
+{
+    // See https://go.microsoft.com/fwlink/?LinkId=733558
+    // for the documentation about the tasks.json format
+    "version": "2.0.0",
+    "tasks": [
+        {
+            "label": "make",
+            "type": "shell",
+            "command": "$MAKECOMMAND",
+            "group": {
+                "kind": "build",
+                "isDefault": true
+            }
+        }
+    ]
+}
+EOF
+die "Could not install default build task"
+
+# Debugger settings
+
+cat >.vscode/launch.json.new <<EOF ||
+{
+    // Use IntelliSense to learn about possible attributes.
+    // Hover to view descriptions of existing attributes.
+    // For more information, visit:
+    // https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "(gdb) Launch",
+            "type": "cppdbg",
+            "request": "launch",
+            "program": "\${workspaceFolder}/git$X",
+            "args": [],
+            "stopAtEntry": false,
+            "cwd": "\${workspaceFolder}",
+            "environment": [],
+            "externalConsole": true,
+            "MIMode": "gdb",
+            "miDebuggerPath": "$GDBPATH",
+            "setupCommands": [
+                {
+                    "description": "Enable pretty-printing for gdb",
+                    "text": "-enable-pretty-printing",
+                    "ignoreFailures": true
+                }
+            ]
+        }
+    ]
+}
+EOF
+die "Could not write launch configuration"
+
+# C/C++ extension settings
+
+make -f - OSNAME=$OSNAME GCCPATH="$GCCPATH" vscode-init \
+       >.vscode/c_cpp_properties.json <<\EOF ||
+include Makefile
+
+vscode-init:
+       @mkdir -p .vscode && \
+       incs= && defs= && \
+       for e in $(ALL_CFLAGS) \
+                       '-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \
+                       '-DGIT_LOCALE_PATH="$(localedir_relative_SQ)"' \
+                       '-DBINDIR="$(bindir_relative_SQ)"' \
+                       '-DFALLBACK_RUNTIME_PREFIX="$(prefix_SQ)"' \
+                       '-DDEFAULT_GIT_TEMPLATE_DIR="$(template_dir_SQ)"' \
+                       '-DETC_GITCONFIG="$(ETC_GITCONFIG_SQ)"' \
+                       '-DETC_GITATTRIBUTES="$(ETC_GITATTRIBUTES_SQ)"' \
+                       '-DGIT_LOCALE_PATH="$(localedir_relative_SQ)"' \
+                       '-DCURL_DISABLE_TYPECHECK', \
+                       '-DGIT_HTML_PATH="$(htmldir_relative_SQ)"' \
+                       '-DGIT_MAN_PATH="$(mandir_relative_SQ)"' \
+                       '-DGIT_INFO_PATH="$(infodir_relative_SQ)"'; do \
+               case "$$e" in \
+               -I.) \
+                       incs="$$(printf '% 16s"$${workspaceRoot}",\n%s' \
+                               "" "$$incs")" \
+                       ;; \
+               -I/*) \
+                       incs="$$(printf '% 16s"%s",\n%s' \
+                               "" "$${e#-I}" "$$incs")" \
+                       ;; \
+               -I*) \
+                       incs="$$(printf '% 16s"$${workspaceRoot}/%s",\n%s' \
+                               "" "$${e#-I}" "$$incs")" \
+                       ;; \
+               -D*) \
+                       defs="$$(printf '% 16s"%s",\n%s' \
+                               "" "$$(echo "$${e#-D}" | sed 's/"/\\&/g')" \
+                               "$$defs")" \
+                       ;; \
+               esac; \
+       done && \
+       echo '{' && \
+       echo '    "configurations": [' && \
+       echo '        {' && \
+       echo '            "name": "$(OSNAME)",' && \
+       echo '            "intelliSenseMode": "clang-x64",' && \
+       echo '            "includePath": [' && \
+       echo "$$incs" | sort | sed '$$s/,$$//' && \
+       echo '            ],' && \
+       echo '            "defines": [' && \
+       echo "$$defs" | sort | sed '$$s/,$$//' && \
+       echo '            ],' && \
+       echo '            "browse": {' && \
+       echo '                "limitSymbolsToIncludedHeaders": true,' && \
+       echo '                "databaseFilename": "",' && \
+       echo '                "path": [' && \
+       echo '                    "$${workspaceRoot}"' && \
+       echo '                ]' && \
+       echo '            },' && \
+       echo '            "cStandard": "c11",' && \
+       echo '            "cppStandard": "c++17",' && \
+       echo '            "compilerPath": "$(GCCPATH)"' && \
+       echo '        }' && \
+       echo '    ],' && \
+       echo '    "version": 4' && \
+       echo '}'
+EOF
+die "Could not write settings for the C/C++ extension"
+
+for file in .vscode/settings.json .vscode/tasks.json .vscode/launch.json
+do
+       if test -f $file
+       then
+               if git diff --no-index --quiet --exit-code $file $file.new
+               then
+                       rm $file.new
+               else
+                       printf "The file $file.new has these changes:\n\n"
+                       git --no-pager diff --no-index $file $file.new
+                       printf "\n\nMaybe \`mv $file.new $file\`?\n\n"
+               fi
+       else
+               mv $file.new $file
+       fi
+done
index 7907efd..ce7ea0d 100644 (file)
--- a/convert.c
+++ b/convert.c
@@ -191,7 +191,7 @@ static enum eol output_eol(enum crlf_action crlf_action)
                /* fall through */
                return text_eol_is_crlf() ? EOL_CRLF : EOL_LF;
        }
-       warning("Illegal crlf_action %d\n", (int)crlf_action);
+       warning(_("illegal crlf_action %d"), (int)crlf_action);
        return core_eol;
 }
 
@@ -204,11 +204,11 @@ static void check_global_conv_flags_eol(const char *path, enum crlf_action crlf_
                 * CRLFs would not be restored by checkout
                 */
                if (conv_flags & CONV_EOL_RNDTRP_DIE)
-                       die(_("CRLF would be replaced by LF in %s."), path);
+                       die(_("CRLF would be replaced by LF in %s"), path);
                else if (conv_flags & CONV_EOL_RNDTRP_WARN)
                        warning(_("CRLF will be replaced by LF in %s.\n"
                                  "The file will have its original line"
-                                 " endings in your working directory."), path);
+                                 " endings in your working directory"), path);
        } else if (old_stats->lonelf && !new_stats->lonelf ) {
                /*
                 * CRLFs would be added by checkout
@@ -218,7 +218,7 @@ static void check_global_conv_flags_eol(const char *path, enum crlf_action crlf_
                else if (conv_flags & CONV_EOL_RNDTRP_WARN)
                        warning(_("LF will be replaced by CRLF in %s.\n"
                                  "The file will have its original line"
-                                 " endings in your working directory."), path);
+                                 " endings in your working directory"), path);
        }
 }
 
@@ -390,7 +390,7 @@ static int encode_to_git(const char *path, const char *src, size_t src_len,
                         struct strbuf *buf, const char *enc, int conv_flags)
 {
        char *dst;
-       int dst_len;
+       size_t dst_len;
        int die_on_error = conv_flags & CONV_WRITE_OBJECT;
 
        /*
@@ -453,7 +453,7 @@ static int encode_to_git(const char *path, const char *src, size_t src_len,
         */
        if (die_on_error && check_roundtrip(enc)) {
                char *re_src;
-               int re_src_len;
+               size_t re_src_len;
 
                re_src = reencode_string_len(dst, dst_len,
                                             enc, default_encoding,
@@ -481,7 +481,7 @@ static int encode_to_worktree(const char *path, const char *src, size_t src_len,
                              struct strbuf *buf, const char *enc)
 {
        char *dst;
-       int dst_len;
+       size_t dst_len;
 
        /*
         * No encoding is specified or there is nothing to encode.
@@ -493,8 +493,8 @@ static int encode_to_worktree(const char *path, const char *src, size_t src_len,
        dst = reencode_string_len(src, src_len, enc, default_encoding,
                                  &dst_len);
        if (!dst) {
-               error("failed to encode '%s' from %s to %s",
-                       path, default_encoding, enc);
+               error(_("failed to encode '%s' from %s to %s"),
+                     path, default_encoding, enc);
                return 0;
        }
 
@@ -671,7 +671,8 @@ static int filter_buffer_or_fd(int in, int out, void *data)
 
        if (start_command(&child_process)) {
                strbuf_release(&cmd);
-               return error("cannot fork to run external filter '%s'", params->cmd);
+               return error(_("cannot fork to run external filter '%s'"),
+                            params->cmd);
        }
 
        sigchain_push(SIGPIPE, SIG_IGN);
@@ -690,13 +691,14 @@ static int filter_buffer_or_fd(int in, int out, void *data)
        if (close(child_process.in))
                write_err = 1;
        if (write_err)
-               error("cannot feed the input to external filter '%s'", params->cmd);
+               error(_("cannot feed the input to external filter '%s'"),
+                     params->cmd);
 
        sigchain_pop(SIGPIPE);
 
        status = finish_command(&child_process);
        if (status)
-               error("external filter '%s' failed %d", params->cmd, status);
+               error(_("external filter '%s' failed %d"), params->cmd, status);
 
        strbuf_release(&cmd);
        return (write_err || status);
@@ -731,13 +733,13 @@ static int apply_single_file_filter(const char *path, const char *src, size_t le
                return 0;       /* error was already reported */
 
        if (strbuf_read(&nbuf, async.out, len) < 0) {
-               err = error("read from external filter '%s' failed", cmd);
+               err = error(_("read from external filter '%s' failed"), cmd);
        }
        if (close(async.out)) {
-               err = error("read from external filter '%s' failed", cmd);
+               err = error(_("read from external filter '%s' failed"), cmd);
        }
        if (finish_async(&async)) {
-               err = error("external filter '%s' failed", cmd);
+               err = error(_("external filter '%s' failed"), cmd);
        }
 
        if (!err) {
@@ -791,7 +793,7 @@ static void handle_filter_error(const struct strbuf *filter_status,
                 * Something went wrong with the protocol filter.
                 * Force shutdown and restart if another blob requires filtering.
                 */
-               error("external filter '%s' failed", entry->subprocess.cmd);
+               error(_("external filter '%s' failed"), entry->subprocess.cmd);
                subprocess_stop(&subprocess_map, &entry->subprocess);
                free(entry);
        }
@@ -839,7 +841,7 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
        else if (wanted_capability & CAP_SMUDGE)
                filter_type = "smudge";
        else
-               die("unexpected filter type");
+               die(_("unexpected filter type"));
 
        sigchain_push(SIGPIPE, SIG_IGN);
 
@@ -850,7 +852,7 @@ static int apply_multi_file_filter(const char *path, const char *src, size_t len
 
        err = strlen(path) > LARGE_PACKET_DATA_MAX - strlen("pathname=\n");
        if (err) {
-               error("path name too long for external filter");
+               error(_("path name too long for external filter"));
                goto done;
        }
 
@@ -924,8 +926,8 @@ int async_query_available_blobs(const char *cmd, struct string_list *available_p
        assert(subprocess_map_initialized);
        entry = (struct cmd2process *)subprocess_find_entry(&subprocess_map, cmd);
        if (!entry) {
-               error("external filter '%s' is not available anymore although "
-                     "not all paths have been filtered", cmd);
+               error(_("external filter '%s' is not available anymore although "
+                       "not all paths have been filtered"), cmd);
                return 0;
        }
        process = &entry->subprocess.process;
@@ -1396,7 +1398,7 @@ int convert_to_git(const struct index_state *istate,
 
        ret |= apply_filter(path, src, len, -1, dst, ca.drv, CAP_CLEAN, NULL);
        if (!ret && ca.drv && ca.drv->required)
-               die("%s: clean filter '%s' failed", path, ca.drv->name);
+               die(_("%s: clean filter '%s' failed"), path, ca.drv->name);
 
        if (ret && dst) {
                src = dst->buf;
@@ -1430,7 +1432,7 @@ void convert_to_git_filter_fd(const struct index_state *istate,
        assert(ca.drv->clean || ca.drv->process);
 
        if (!apply_filter(path, NULL, 0, fd, dst, ca.drv, CAP_CLEAN, NULL))
-               die("%s: clean filter '%s' failed", path, ca.drv->name);
+               die(_("%s: clean filter '%s' failed"), path, ca.drv->name);
 
        encode_to_git(path, dst->buf, dst->len, dst, ca.working_tree_encoding, conv_flags);
        crlf_to_git(istate, path, dst->buf, dst->len, dst, ca.crlf_action, conv_flags);
@@ -1473,7 +1475,7 @@ static int convert_to_working_tree_internal(const char *path, const char *src,
        ret_filter = apply_filter(
                path, src, len, -1, dst, ca.drv, CAP_SMUDGE, dco);
        if (!ret_filter && ca.drv && ca.drv->required)
-               die("%s: smudge filter %s failed", path, ca.drv->name);
+               die(_("%s: smudge filter %s failed"), path, ca.drv->name);
 
        return ret | ret_filter;
 }
index 01385d9..0a0fa15 100644 (file)
--- a/convert.h
+++ b/convert.h
@@ -57,35 +57,36 @@ struct delayed_checkout {
 
 extern enum eol core_eol;
 extern char *check_roundtrip_encoding;
-extern const char *get_cached_convert_stats_ascii(const struct index_state *istate,
-                                                 const char *path);
-extern const char *get_wt_convert_stats_ascii(const char *path);
-extern const char *get_convert_attr_ascii(const char *path);
+const char *get_cached_convert_stats_ascii(const struct index_state *istate,
+                                          const char *path);
+const char *get_wt_convert_stats_ascii(const char *path);
+const char *get_convert_attr_ascii(const char *path);
 
 /* returns 1 if *dst was used */
-extern int convert_to_git(const struct index_state *istate,
-                         const char *path, const char *src, size_t len,
-                         struct strbuf *dst, int conv_flags);
-extern int convert_to_working_tree(const char *path, const char *src,
-                                  size_t len, struct strbuf *dst);
-extern int async_convert_to_working_tree(const char *path, const char *src,
-                                        size_t len, struct strbuf *dst,
-                                        void *dco);
-extern int async_query_available_blobs(const char *cmd, struct string_list *available_paths);
-extern int renormalize_buffer(const struct index_state *istate,
-                             const char *path, const char *src, size_t len,
-                             struct strbuf *dst);
+int convert_to_git(const struct index_state *istate,
+                  const char *path, const char *src, size_t len,
+                  struct strbuf *dst, int conv_flags);
+int convert_to_working_tree(const char *path, const char *src,
+                           size_t len, struct strbuf *dst);
+int async_convert_to_working_tree(const char *path, const char *src,
+                                 size_t len, struct strbuf *dst,
+                                 void *dco);
+int async_query_available_blobs(const char *cmd,
+                               struct string_list *available_paths);
+int renormalize_buffer(const struct index_state *istate,
+                      const char *path, const char *src, size_t len,
+                      struct strbuf *dst);
 static inline int would_convert_to_git(const struct index_state *istate,
                                       const char *path)
 {
        return convert_to_git(istate, path, NULL, 0, NULL, 0);
 }
 /* Precondition: would_convert_to_git_filter_fd(path) == true */
-extern void convert_to_git_filter_fd(const struct index_state *istate,
-                                    const char *path, int fd,
-                                    struct strbuf *dst,
-                                    int conv_flags);
-extern int would_convert_to_git_filter_fd(const char *path);
+void convert_to_git_filter_fd(const struct index_state *istate,
+                             const char *path, int fd,
+                             struct strbuf *dst,
+                             int conv_flags);
+int would_convert_to_git_filter_fd(const char *path);
 
 /*****************************************************************
  *
@@ -95,9 +96,10 @@ extern int would_convert_to_git_filter_fd(const char *path);
 
 struct stream_filter; /* opaque */
 
-extern struct stream_filter *get_stream_filter(const char *path, const struct object_id *);
-extern void free_stream_filter(struct stream_filter *);
-extern int is_null_stream_filter(struct stream_filter *);
+struct stream_filter *get_stream_filter(const char *path,
+                                       const struct object_id *);
+void free_stream_filter(struct stream_filter *);
+int is_null_stream_filter(struct stream_filter *);
 
 /*
  * Use as much input up to *isize_p and fill output up to *osize_p;
@@ -111,8 +113,8 @@ extern int is_null_stream_filter(struct stream_filter *);
  * such filters know there is no more input coming and it is time for
  * them to produce the remaining output based on the buffered input.
  */
-extern int stream_filter(struct stream_filter *,
-                        const char *input, size_t *isize_p,
-                        char *output, size_t *osize_p);
+int stream_filter(struct stream_filter *,
+                 const char *input, size_t *isize_p,
+                 char *output, size_t *osize_p);
 
 #endif /* CONVERT_H */
diff --git a/diff.c b/diff.c
index 04d044b..f830afa 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -271,10 +271,12 @@ static int parse_color_moved(const char *arg)
                return COLOR_MOVED_ZEBRA;
        else if (!strcmp(arg, "default"))
                return COLOR_MOVED_DEFAULT;
+       else if (!strcmp(arg, "dimmed-zebra"))
+               return COLOR_MOVED_ZEBRA_DIM;
        else if (!strcmp(arg, "dimmed_zebra"))
                return COLOR_MOVED_ZEBRA_DIM;
        else
-               return error(_("color moved setting must be one of 'no', 'default', 'blocks', 'zebra', 'dimmed_zebra', 'plain'"));
+               return error(_("color moved setting must be one of 'no', 'default', 'blocks', 'zebra', 'dimmed-zebra', 'plain'"));
 }
 
 static int parse_color_moved_ws(const char *arg)
@@ -2069,8 +2071,8 @@ static void init_diff_words_data(struct emit_callback *ecbdata,
                if (regcomp(ecbdata->diff_words->word_regex,
                            o->word_regex,
                            REG_EXTENDED | REG_NEWLINE))
-                       die ("Invalid regular expression: %s",
-                            o->word_regex);
+                       die("invalid regular expression: %s",
+                           o->word_regex);
        }
        for (i = 0; i < ARRAY_SIZE(diff_words_styles); i++) {
                if (o->word_diff == diff_words_styles[i].type) {
diff --git a/diff.h b/diff.h
index a14895b..20c697d 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -258,15 +258,15 @@ const char *diff_line_prefix(struct diff_options *);
 
 extern const char mime_boundary_leader[];
 
-extern struct combine_diff_path *diff_tree_paths(
+struct combine_diff_path *diff_tree_paths(
        struct combine_diff_path *p, const struct object_id *oid,
        const struct object_id **parents_oid, int nparent,
        struct strbuf *base, struct diff_options *opt);
-extern int diff_tree_oid(const struct object_id *old_oid,
-                        const struct object_id *new_oid,
-                        const char *base, struct diff_options *opt);
-extern int diff_root_tree_oid(const struct object_id *new_oid, const char *base,
-                             struct diff_options *opt);
+int diff_tree_oid(const struct object_id *old_oid,
+                 const struct object_id *new_oid,
+                 const char *base, struct diff_options *opt);
+int diff_root_tree_oid(const struct object_id *new_oid, const char *base,
+                      struct diff_options *opt);
 
 struct combine_diff_path {
        struct combine_diff_path *next;
@@ -283,33 +283,33 @@ struct combine_diff_path {
        st_add4(sizeof(struct combine_diff_path), (l), 1, \
                st_mult(sizeof(struct combine_diff_parent), (n)))
 
-extern void show_combined_diff(struct combine_diff_path *elem, int num_parent,
-                             int dense, struct rev_info *);
+void show_combined_diff(struct combine_diff_path *elem, int num_parent,
+                       int dense, struct rev_info *);
 
-extern void diff_tree_combined(const struct object_id *oid, const struct oid_array *parents, int dense, struct rev_info *rev);
+void diff_tree_combined(const struct object_id *oid, const struct oid_array *parents, int dense, struct rev_info *rev);
 
-extern void diff_tree_combined_merge(const struct commit *commit, int dense, struct rev_info *rev);
+void diff_tree_combined_merge(const struct commit *commit, int dense, struct rev_info *rev);
 
 void diff_set_mnemonic_prefix(struct diff_options *options, const char *a, const char *b);
 
-extern int diff_can_quit_early(struct diff_options *);
+int diff_can_quit_early(struct diff_options *);
 
-extern void diff_addremove(struct diff_options *,
-                          int addremove,
-                          unsigned mode,
-                          const struct object_id *oid,
-                          int oid_valid,
-                          const char *fullpath, unsigned dirty_submodule);
+void diff_addremove(struct diff_options *,
+                   int addremove,
+                   unsigned mode,
+                   const struct object_id *oid,
+                   int oid_valid,
+                   const char *fullpath, unsigned dirty_submodule);
 
-extern void diff_change(struct diff_options *,
-                       unsigned mode1, unsigned mode2,
-                       const struct object_id *old_oid,
-                       const struct object_id *new_oid,
-                       int old_oid_valid, int new_oid_valid,
-                       const char *fullpath,
-                       unsigned dirty_submodule1, unsigned dirty_submodule2);
+void diff_change(struct diff_options *,
+                unsigned mode1, unsigned mode2,
+                const struct object_id *old_oid,
+                const struct object_id *new_oid,
+                int old_oid_valid, int new_oid_valid,
+                const char *fullpath,
+                unsigned dirty_submodule1, unsigned dirty_submodule2);
 
-extern struct diff_filepair *diff_unmerge(struct diff_options *, const char *path);
+struct diff_filepair *diff_unmerge(struct diff_options *, const char *path);
 
 #define DIFF_SETUP_REVERSE             1
 #define DIFF_SETUP_USE_CACHE           2
@@ -319,17 +319,17 @@ extern struct diff_filepair *diff_unmerge(struct diff_options *, const char *pat
  * Poor man's alternative to parse-option, to allow both stuck form
  * (--option=value) and separate form (--option value).
  */
-extern int parse_long_opt(const char *opt, const char **argv,
-                        const char **optarg);
-
-extern int git_diff_basic_config(const char *var, const char *value, void *cb);
-extern int git_diff_heuristic_config(const char *var, const char *value, void *cb);
-extern void init_diff_ui_defaults(void);
-extern int git_diff_ui_config(const char *var, const char *value, void *cb);
-extern void diff_setup(struct diff_options *);
-extern int diff_opt_parse(struct diff_options *, const char **, int, const char *);
-extern void diff_setup_done(struct diff_options *);
-extern int git_config_rename(const char *var, const char *value);
+int parse_long_opt(const char *opt, const char **argv,
+                  const char **optarg);
+
+int git_diff_basic_config(const char *var, const char *value, void *cb);
+int git_diff_heuristic_config(const char *var, const char *value, void *cb);
+void init_diff_ui_defaults(void);
+int git_diff_ui_config(const char *var, const char *value, void *cb);
+void diff_setup(struct diff_options *);
+int diff_opt_parse(struct diff_options *, const char **, int, const char *);
+void diff_setup_done(struct diff_options *);
+int git_config_rename(const char *var, const char *value);
 
 #define DIFF_DETECT_RENAME     1
 #define DIFF_DETECT_COPY       2
@@ -347,8 +347,8 @@ extern int git_config_rename(const char *var, const char *value);
 
 #define DIFF_PICKAXE_IGNORE_CASE       32
 
-extern void diffcore_std(struct diff_options *);
-extern void diffcore_fix_diff_index(struct diff_options *);
+void diffcore_std(struct diff_options *);
+void diffcore_fix_diff_index(struct diff_options *);
 
 #define COMMON_DIFF_OPTIONS_HELP \
 "\ncommon diff options:\n" \
@@ -378,9 +378,9 @@ extern void diffcore_fix_diff_index(struct diff_options *);
 "                show all files diff when -S is used and hit is found.\n" \
 "  -a  --text    treat all files as text.\n"
 
-extern int diff_queue_is_empty(void);
-extern void diff_flush(struct diff_options*);
-extern void diff_warn_rename_limit(const char *varname, int needed, int degraded_cc);
+int diff_queue_is_empty(void);
+void diff_flush(struct diff_options*);
+void diff_warn_rename_limit(const char *varname, int needed, int degraded_cc);
 
 /* diff-raw status letters */
 #define DIFF_STATUS_ADDED              'A'
@@ -402,24 +402,24 @@ extern void diff_warn_rename_limit(const char *varname, int needed, int degraded
  * This is different from find_unique_abbrev() in that
  * it stuffs the result with dots for alignment.
  */
-extern const char *diff_aligned_abbrev(const struct object_id *sha1, int);
+const char *diff_aligned_abbrev(const struct object_id *sha1, int);
 
 /* do not report anything on removed paths */
 #define DIFF_SILENT_ON_REMOVED 01
 /* report racily-clean paths as modified */
 #define DIFF_RACY_IS_MODIFIED 02
-extern int run_diff_files(struct rev_info *revs, unsigned int option);
-extern int run_diff_index(struct rev_info *revs, int cached);
+int run_diff_files(struct rev_info *revs, unsigned int option);
+int run_diff_index(struct rev_info *revs, int cached);
 
-extern int do_diff_cache(const struct object_id *, struct diff_options *);
-extern int diff_flush_patch_id(struct diff_options *, struct object_id *, int);
+int do_diff_cache(const struct object_id *, struct diff_options *);
+int diff_flush_patch_id(struct diff_options *, struct object_id *, int);
 
-extern int diff_result_code(struct diff_options *, int);
+int diff_result_code(struct diff_options *, int);
 
-extern void diff_no_index(struct rev_info *, int, const char **);
+void diff_no_index(struct rev_info *, int, const char **);
 
-extern int index_differs_from(const char *def, const struct diff_flags *flags,
-                   &nb