Merge branch 'sf/complete-stash-list'
authorJunio C Hamano <gitster@pobox.com>
Tue, 16 Oct 2018 07:16:09 +0000 (16:16 +0900)
committerJunio C Hamano <gitster@pobox.com>
Tue, 16 Oct 2018 07:16:09 +0000 (16:16 +0900)
The completion script (in contrib/) learned to complete a handful of
options "git stash list" command takes.

* sf/complete-stash-list:
  git-completion.bash: add completion for stash list

132 files changed:
.mailmap
Documentation/CodingGuidelines
Documentation/RelNotes/2.20.0.txt [new file with mode: 0644]
Documentation/config.txt
Documentation/fetch-config.txt [new file with mode: 0644]
Documentation/format-config.txt [new file with mode: 0644]
Documentation/git-archimport.txt
Documentation/git-column.txt
Documentation/git-commit-graph.txt
Documentation/git-config.txt
Documentation/git-describe.txt
Documentation/git-multi-pack-index.txt
Documentation/git-rebase.txt
Documentation/git.txt
Documentation/gitcredentials.txt
Documentation/gitcvs-config.txt [new file with mode: 0644]
Documentation/gui-config.txt [new file with mode: 0644]
Documentation/pull-config.txt [new file with mode: 0644]
Documentation/push-config.txt [new file with mode: 0644]
Documentation/receive-config.txt [new file with mode: 0644]
Documentation/sendemail-config.txt [new file with mode: 0644]
Documentation/submodule-config.txt [new file with mode: 0644]
Documentation/technical/api-history-graph.txt
Documentation/technical/commit-graph.txt
Makefile
RelNotes [changed from file to symlink]
builtin/checkout.c
builtin/commit-graph.c
builtin/commit.c
builtin/fsck.c
builtin/gc.c
builtin/multi-pack-index.c
builtin/pack-objects.c
builtin/receive-pack.c
builtin/replace.c
cache-tree.c
commit-graph.c
commit-graph.h
commit-reach.c
commit.c
commit.h
compat/poll/poll.c
compat/poll/poll.h
config.mak.uname
delta-islands.h
ewah/ewok_rlw.h
fsck.c
fsck.h
git-compat-util.h
git-rebase.sh
git.c
json-writer.h
merge-recursive.c
midx.c
midx.h
refs.c
refs.h
refs/iterator.c
refs/packed-backend.h
refs/ref-cache.h
refs/refs-internal.h
replace-object.c
replace-object.h
sequencer.c
t/README
t/helper/test-dump-fsmonitor.c
t/helper/test-dump-untracked-cache.c
t/helper/test-parse-options.c
t/helper/test-pkt-line.c
t/helper/test-repository.c
t/helper/test-tool.c
t/helper/test-tool.h
t/lib-gpg.sh
t/oid-info/README [new file with mode: 0644]
t/oid-info/hash-info [new file with mode: 0644]
t/oid-info/oid [new file with mode: 0644]
t/perf/p1450-fsck.sh [new file with mode: 0755]
t/perf/p1451-fsck-skip-list.sh [new file with mode: 0755]
t/t0000-basic.sh
t/t0002-gitfile.sh
t/t0014-alias.sh [new file with mode: 0755]
t/t0021-conversion.sh
t/t0040-parse-options.sh
t/t0064-sha1-array.sh
t/t1006-cat-file.sh
t/t1300-config.sh
t/t1303-wacky-config.sh
t/t1400-update-ref.sh
t/t1405-main-ref-store.sh
t/t1406-submodule-ref-store.sh
t/t1407-worktree-ref-store.sh
t/t2101-update-index-reupdate.sh
t/t3200-branch.sh
t/t3320-notes-merge-worktrees.sh
t/t3400-rebase.sh
t/t3417-rebase-whitespace-fix.sh
t/t3702-add-edit.sh
t/t3903-stash.sh
t/t3905-stash-include-untracked.sh
t/t4025-hunk-header.sh
t/t4117-apply-reject.sh
t/t4124-apply-ws-rule.sh
t/t4138-apply-ws-expansion.sh
t/t5317-pack-objects-filter-objects.sh
t/t5318-commit-graph.sh
t/t5319-multi-pack-index.sh
t/t5500-fetch-pack.sh
t/t5504-fetch-receive-strict.sh
t/t5551-http-fetch-smart.sh
t/t5616-partial-clone.sh
t/t5701-git-serve.sh
t/t5702-protocol-v2.sh
t/t5703-upload-pack-ref-in-want.sh
t/t6023-merge-file.sh
t/t6027-merge-binary.sh
t/t6031-merge-filemode.sh
t/t6112-rev-list-filters-objects.sh
t/t6500-gc.sh
t/t7063-status-untracked-cache.sh
t/t7201-co.sh
t/t7406-submodule-update.sh
t/t7500-commit.sh
t/t7519-status-fsmonitor.sh
t/t7800-difftool.sh
t/t9100-git-svn-basic.sh
t/t9101-git-svn-props.sh
t/t9133-git-svn-nested-git-repo.sh
t/t9600-cvsimport.sh
t/t9603-cvsimport-patchsets.sh
t/t9604-cvsimport-timestamps.sh
t/test-lib-functions.sh
upload-pack.c

index f165222..bef3352 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -25,7 +25,7 @@ Ben Walton <bdwalton@gmail.com> <bwalton@artsci.utoronto.ca>
 Benoit Sigoure <tsunanet@gmail.com> <tsuna@lrde.epita.fr>
 Bernt Hansen <bernt@norang.ca> <bernt@alumni.uwaterloo.ca>
 Brandon Casey <drafnel@gmail.com> <casey@nrlssc.navy.mil>
-brian m. carlson <sandals@crustytoothpaste.net> Brian M. Carlson <sandals@crustytoothpaste.ath.cx>
+brian m. carlson <sandals@crustytoothpaste.net>
 brian m. carlson <sandals@crustytoothpaste.net> <sandals@crustytoothpaste.ath.cx>
 Bryan Larsen <bryan@larsen.st> <bryan.larsen@gmail.com>
 Bryan Larsen <bryan@larsen.st> <bryanlarsen@yahoo.com>
index 48aa4ed..72967de 100644 (file)
@@ -118,6 +118,24 @@ For shell scripts specifically (not exhaustive):
                do this
        fi
 
+ - If a command sequence joined with && or || or | spans multiple
+   lines, put each command on a separate line and put && and || and |
+   operators at the end of each line, rather than the start. This
+   means you don't need to use \ to join lines, since the above
+   operators imply the sequence isn't finished.
+
+       (incorrect)
+       grep blob verify_pack_result \
+       | awk -f print_1.awk \
+       | sort >actual &&
+       ...
+
+       (correct)
+       grep blob verify_pack_result |
+       awk -f print_1.awk |
+       sort >actual &&
+       ...
+
  - We prefer "test" over "[ ... ]".
 
  - We do not write the noiseword "function" in front of shell
diff --git a/Documentation/RelNotes/2.20.0.txt b/Documentation/RelNotes/2.20.0.txt
new file mode 100644 (file)
index 0000000..2cc5fd7
--- /dev/null
@@ -0,0 +1,183 @@
+Git Release Notes
+=================
+
+Backward Compatibility Notes
+----------------------------
+
+ * "git branch -l <foo>" used to be a way to ask a reflog to be
+   created while creating a new branch, but that is no longer the
+   case.  It is a short-hand for "git branch --list <foo>" now.
+
+ * "git push" into refs/tags/* hierarchy is rejected without getting
+   forced, but "git fetch" (misguidedly) used the "fast forwarding"
+   rule used for the refs/heads/* hierarchy; this has been corrected,
+   which means some fetches of tags that did not fail with older
+   version of Git will fail without "--force" with this version.
+
+
+Updates since v2.19
+-------------------
+
+UI, Workflows & Features
+
+ * Running "git clone" against a project that contain two files with
+   pathnames that differ only in cases on a case insensitive
+   filesystem would result in one of the files lost because the
+   underlying filesystem is incapable of holding both at the same
+   time.  An attempt is made to detect such a case and warn.
+
+ * "git checkout -b newbranch [HEAD]" should not have to do as much as
+   checking out a commit different from HEAD.  An attempt is made to
+   optimize this special case.
+
+ * "git rev-list --stdin </dev/null" used to be an error; it now shows
+   no output without an error.  "git rev-list --stdin --default HEAD"
+   still falls back to the given default when nothing is given on the
+   standard input.
+
+ * Lift code from GitHub to restrict delta computation so that an
+   object that exists in one fork is not made into a delta against
+   another object that does not appear in the same forked repository.
+
+ * "git format-patch" learned new "--interdiff" and "--range-diff"
+   options to explain the difference between this version and the
+   previous attempt in the cover letter (or after the tree-dashes as
+   a comment).
+
+ * "git mailinfo" used in "git am" learned to make a best-effort
+   recovery of a patch corrupted by MUA that sends text/plain with
+   format=flawed option.
+   (merge 3aa4d81f88 rs/mailinfo-format-flowed later to maint).
+
+ * The rules used by "git push" and "git fetch" to determine if a ref
+   can or cannot be updated were inconsistent; specifically, fetching
+   to update existing tags were allowed even though tags are supposed
+   to be unmoving anchoring points.  "git fetch" was taught to forbid
+   updates to existing tags without the "--force" option.
+
+ * "git multi-pack-index" learned to detect corruption in the .midx
+   file it uses, and this feature has been integrated into "git fsck".
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * When there are too many packfiles in a repository (which is not
+   recommended), looking up an object in these would require
+   consulting many pack .idx files; a new mechanism to have a single
+   file that consolidates all of these .idx files is introduced.
+
+ * "git submodule update" is getting rewritten piece-by-piece into C.
+
+ * The code for computing history reachability has been shuffled,
+   obtained a bunch of new tests to cover them, and then being
+   improved.
+
+ * The unpack_trees() API used in checking out a branch and merging
+   walks one or more trees along with the index.  When the cache-tree
+   in the index tells us that we are walking a tree whose flattened
+   contents is known (i.e. matches a span in the index), as linearly
+   scanning a span in the index is much more efficient than having to
+   open tree objects recursively and listing their entries, the walk
+   can be optimized, which has been done.
+
+ * When creating a thin pack, which allows objects to be made into a
+   delta against another object that is not in the resulting pack but
+   is known to be present on the receiving end, the code learned to
+   take advantage of the reachability bitmap; this allows the server
+   to send a delta against a base beyond the "boundary" commit.
+
+ * spatch transformation to replace boolean uses of !hashcmp() to
+   newly introduced oideq() is added, and applied, to regain
+   performance lost due to support of multiple hash algorithms.
+
+ * Fix a bug in which the same path could be registered under multiple
+   worktree entries if the path was missing (for instance, was removed
+   manually).  Also, as a convenience, expand the number of cases in
+   which --force is applicable.
+
+ * Split Documentation/config.txt for easier maintenance.
+   (merge 6014363f0b nd/config-split later to maint).
+
+ * Test helper binaries clean-up.
+   (merge c9a1f4161f nd/test-tool later to maint).
+
+ * Various tests have been updated to make it easier to swap the
+   hash function used for object identification.
+   (merge ae0c89d41b bc/hash-independent-tests later to maint).
+
+ * Update fsck.skipList implementation and documentation.
+   (merge 371a655074 ab/fsck-skiplist later to maint).
+
+
+Fixes since v2.19
+-----------------
+
+ * "git interpret-trailers" and its underlying machinery had a buggy
+   code that attempted to ignore patch text after commit log message,
+   which triggered in various codepaths that will always get the log
+   message alone and never get such an input.
+   (merge 66e83d9b41 jk/trailer-fixes later to maint).
+
+ * Malformed or crafted data in packstream can make our code attempt
+   to read or write past the allocated buffer and abort, instead of
+   reporting an error, which has been fixed.
+
+ * "git rebase -i" did not clear the state files correctly when a run
+   of "squash/fixup" is aborted and then the user manually amended the
+   commit instead, which has been corrected.
+   (merge 10d2f35436 js/rebase-i-autosquash-fix later to maint).
+
+ * When fsmonitor is in use, after operation on submodules updates
+   .gitmodules, we lost track of the fact that we did so and relied on
+   stale fsmonitor data.
+   (merge 43f1180814 bp/mv-submodules-with-fsmonitor later to maint).
+
+ * Fix for a long-standing bug that leaves the index file corrupt when
+   it shrinks during a partial commit.
+   (merge 6c003d6ffb jk/reopen-tempfile-truncate later to maint).
+
+ * Further fix for O_APPEND emulation on Windows
+   (merge eeaf7ddac7 js/mingw-o-append later to maint).
+
+ * A corner case bugfix in "git rerere" code.
+   (merge ad2bf0d9b4 en/rerere-multi-stage-1-fix later to maint).
+
+ * "git add ':(attr:foo)'" is not supported and is supposed to be
+   rejected while the command line arguments are parsed, but we fail
+   to reject such a command line upfront.
+   (merge 84d938b732 nd/attr-pathspec-fix later to maint).
+
+ * Recent update broke the reachability algorithm when refs (e.g.
+   tags) that point at objects that are not commit were involved,
+   which has been fixed.
+
+ * "git rebase" etc. in Git 2.19 fails to abort when given an empty
+   commit log message as result of editing, which has been corrected.
+   (merge a3ec9eaf38 en/sequencer-empty-edit-result-aborts later to maint).
+
+ * The code to backfill objects in lazily cloned repository did not
+   work correctly, which has been corrected.
+   (merge e68302011c jt/lazy-object-fetch-fix later to maint).
+
+ * Update error messages given by "git remote" and make them consistent.
+   (merge 5025425dff ms/remote-error-message-update later to maint).
+
+ * "git update-ref" learned to make both "--no-deref" and "--stdin"
+   work at the same time.
+   (merge d345e9fbe7 en/update-ref-no-deref-stdin later to maint).
+
+ * Recently added "range-diff" had a corner-case bug to cause it
+   segfault, which has been corrected.
+   (merge e467a90c7a tg/range-diff-corner-case-fix later to maint).
+
+ * Code cleanup, docfix, build fix, etc.
+   (merge 96a7501aad ts/doc-build-manpage-xsl-quietly later to maint).
+   (merge b9b07efdb2 tg/conflict-marker-size later to maint).
+   (merge fa0aeea770 sg/doc-trace-appends later to maint).
+   (merge d64324cb60 tb/void-check-attr later to maint).
+   (merge c3b9bc94b9 en/double-semicolon-fix later to maint).
+   (merge 79336116f5 sg/t3701-tighten-trace later to maint).
+   (merge 801fa63a90 jk/dev-build-format-security later to maint).
+   (merge 0597dd62ba sb/string-list-remove-unused later to maint).
+   (merge db2d36fad8 bw/protocol-v2 later to maint).
+   (merge 456d7cd3a9 sg/split-index-test later to maint).
index ad0f451..f6f4c21 100644 (file)
@@ -225,7 +225,7 @@ boolean::
        false;; Boolean false literals are `no`, `off`, `false`,
                `0` and the empty string.
 +
-When converting value to the canonical form using `--bool` type
+When converting a value to its canonical form using the `--type=bool` type
 specifier, 'git config' will ensure that the output is "true" or
 "false" (spelled in lowercase).
 
@@ -832,12 +832,6 @@ core.packedRefsTimeout::
        all; -1 means to try indefinitely. Default is 1000 (i.e.,
        retry for 1 second).
 
-sequence.editor::
-       Text editor used by `git rebase -i` for editing the rebase instruction file.
-       The value is meant to be interpreted by the shell when it is used.
-       It can be overridden by the `GIT_SEQUENCE_EDITOR` environment variable.
-       When not configured the default commit message editor is used instead.
-
 core.pager::
        Text viewer for use by Git commands (e.g., 'less').  The value
        is meant to be interpreted by the shell.  The order of preference
@@ -1520,159 +1514,9 @@ fastimport.unpackLimit::
        operation complete faster, especially on slow filesystems.  If
        not set, the value of `transfer.unpackLimit` is used instead.
 
-fetch.recurseSubmodules::
-       This option can be either set to a boolean value or to 'on-demand'.
-       Setting it to a boolean changes the behavior of fetch and pull to
-       unconditionally recurse into submodules when set to true or to not
-       recurse at all when set to false. When set to 'on-demand' (the default
-       value), fetch and pull will only recurse into a populated submodule
-       when its superproject retrieves a commit that updates the submodule's
-       reference.
-
-fetch.fsckObjects::
-       If it is set to true, git-fetch-pack will check all fetched
-       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
-       transfer is below this
-       limit, then the objects will be unpacked into loose object
-       files. However if the number of received objects equals or
-       exceeds this limit then the received pack will be stored as
-       a pack, after adding any missing delta bases.  Storing the
-       pack from a push can make the push operation complete faster,
-       especially on slow filesystems.  If not set, the value of
-       `transfer.unpackLimit` is used instead.
-
-fetch.prune::
-       If true, fetch will automatically behave as if the `--prune`
-       option was given on the command line.  See also `remote.<name>.prune`
-       and the PRUNING section of linkgit:git-fetch[1].
-
-fetch.pruneTags::
-       If true, fetch will automatically behave as if the
-       `refs/tags/*:refs/tags/*` refspec was provided when pruning,
-       if not set already. This allows for setting both this option
-       and `fetch.prune` to maintain a 1=1 mapping to upstream
-       refs. See also `remote.<name>.pruneTags` and the PRUNING
-       section of linkgit:git-fetch[1].
-
-fetch.output::
-       Control how ref update status is printed. Valid values are
-       `full` and `compact`. Default value is `full`. See section
-       OUTPUT in linkgit:git-fetch[1] for detail.
-
-fetch.negotiationAlgorithm::
-       Control how information about the commits in the local repository is
-       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; 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
-       'format-patch'.  The value can also be a double quoted string
-       which will enable attachments as the default and set the
-       value as the boundary.  See the --attach option in
-       linkgit:git-format-patch[1].
-
-format.from::
-       Provides the default value for the `--from` option to format-patch.
-       Accepts a boolean value, or a name and email address.  If false,
-       format-patch defaults to `--no-from`, using commit authors directly in
-       the "From:" field of patch mails.  If true, format-patch defaults to
-       `--from`, using your committer identity in the "From:" field of patch
-       mails and including a "From:" field in the body of the patch mail if
-       different.  If set to a non-boolean value, format-patch uses that
-       value instead of your committer identity.  Defaults to false.
-
-format.numbered::
-       A boolean which can enable or disable sequence numbers in patch
-       subjects.  It defaults to "auto" which enables it only if there
-       is more than one patch.  It can be enabled or disabled for all
-       messages by setting it to "true" or "false".  See --numbered
-       option in linkgit:git-format-patch[1].
-
-format.headers::
-       Additional email headers to include in a patch to be submitted
-       by mail.  See linkgit:git-format-patch[1].
-
-format.to::
-format.cc::
-       Additional recipients to include in a patch to be submitted
-       by mail.  See the --to and --cc options in
-       linkgit:git-format-patch[1].
-
-format.subjectPrefix::
-       The default for format-patch is to output files with the '[PATCH]'
-       subject prefix. Use this variable to change that prefix.
-
-format.signature::
-       The default for format-patch is to output a signature containing
-       the Git version number. Use this variable to change that default.
-       Set this variable to the empty string ("") to suppress
-       signature generation.
-
-format.signatureFile::
-       Works just like format.signature except the contents of the
-       file specified by this variable will be used as the signature.
-
-format.suffix::
-       The default for format-patch is to output files with the suffix
-       `.patch`. Use this variable to change that suffix (make sure to
-       include the dot if you want it).
-
-format.pretty::
-       The default pretty format for log/show/whatchanged command,
-       See linkgit:git-log[1], linkgit:git-show[1],
-       linkgit:git-whatchanged[1].
-
-format.thread::
-       The default threading style for 'git format-patch'.  Can be
-       a boolean value, or `shallow` or `deep`.  `shallow` threading
-       makes every mail a reply to the head of the series,
-       where the head is chosen from the cover letter, the
-       `--in-reply-to`, and the first patch mail, in this order.
-       `deep` threading makes every mail a reply to the previous one.
-       A true boolean value is the same as `shallow`, and a false
-       value disables threading.
-
-format.signOff::
-       A boolean value which lets you enable the `-s/--signoff` option of
-       format-patch by default. *Note:* Adding the Signed-off-by: line to a
-       patch should be a conscious act and means that you certify you have
-       the rights to submit this work under the same open source license.
-       Please see the 'SubmittingPatches' document for further discussion.
-
-format.coverLetter::
-       A boolean that controls whether to generate a cover-letter when
-       format-patch is invoked, but in addition can be set to "auto", to
-       generate a cover-letter only when there's more than one patch.
-
-format.outputDirectory::
-       Set a custom directory to store the resulting files instead of the
-       current working directory.
-
-format.useAutoBase::
-       A boolean value which lets you enable the `--base=auto` option of
-       format-patch by default.
+include::fetch-config.txt[]
+
+include::format-config.txt[]
 
 filter.<driver>.clean::
        The command which is used to convert the content of a worktree
@@ -1723,12 +1567,16 @@ 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
+       The path to a list of object names (i.e. one unabbreviated 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.
+       be ignored. On versions of Git 2.20 and later comments ('#'), empty
+       lines, and any leading and trailing whitespace is ignored. Everything
+       but a SHA-1 per line will error out on older versions.
++
+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.
 +
 Like `fsck.<msg-id>` this variable has corresponding
 `receive.fsck.skipList` and `fetch.fsck.skipList` variants.
@@ -1738,6 +1586,15 @@ Unlike variables like `color.ui` and `core.editor` the
 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.
++
+Older versions of Git (before 2.20) documented that the object names
+list should be sorted. This was never a requirement, the object names
+could appear in any order, but when reading the list we tracked whether
+the list was sorted for the purposes of an internal binary search
+implementation, which could save itself some work with an already sorted
+list. Unless you had a humongous list there was no reason to go out of
+your way to pre-sort the list. After Git version 2.20 a hash implementation
+is used instead, so there's now no reason to pre-sort the list.
 
 gc.aggressiveDepth::
        The depth parameter used in the delta compression
@@ -1786,7 +1643,8 @@ gc.writeCommitGraph::
        for details.
 
 gc.logExpiry::
-       If the file gc.log exists, then `git gc --auto` won't run
+       If the file gc.log exists, then `git gc --auto` will print
+       its content and exit with status zero instead of running
        unless that file is more than 'gc.logExpiry' old.  Default is
        "1.day".  See `gc.pruneExpire` for more ways to specify its
        value.
@@ -1847,73 +1705,7 @@ gc.rerereUnresolved::
        You can also use more human-readable "1.month.ago", etc.
        The default is 15 days.  See linkgit:git-rerere[1].
 
-gitcvs.commitMsgAnnotation::
-       Append this string to each commit message. Set to empty string
-       to disable this feature. Defaults to "via git-CVS emulator".
-
-gitcvs.enabled::
-       Whether the CVS server interface is enabled for this repository.
-       See linkgit:git-cvsserver[1].
-
-gitcvs.logFile::
-       Path to a log file where the CVS server interface well... logs
-       various stuff. See linkgit:git-cvsserver[1].
-
-gitcvs.usecrlfattr::
-       If true, the server will look up the end-of-line conversion
-       attributes for files to determine the `-k` modes to use. If
-       the attributes force Git to treat a file as text,
-       the `-k` mode will be left blank so CVS clients will
-       treat it as text. If they suppress text conversion, the file
-       will be set with '-kb' mode, which suppresses any newline munging
-       the client might otherwise do. If the attributes do not allow
-       the file type to be determined, then `gitcvs.allBinary` is
-       used. See linkgit:gitattributes[5].
-
-gitcvs.allBinary::
-       This is used if `gitcvs.usecrlfattr` does not resolve
-       the correct '-kb' mode to use. If true, all
-       unresolved files are sent to the client in
-       mode '-kb'. This causes the client to treat them
-       as binary files, which suppresses any newline munging it
-       otherwise might do. Alternatively, if it is set to "guess",
-       then the contents of the file are examined to decide if
-       it is binary, similar to `core.autocrlf`.
-
-gitcvs.dbName::
-       Database used by git-cvsserver to cache revision information
-       derived from the Git repository. The exact meaning depends on the
-       used database driver, for SQLite (which is the default driver) this
-       is a filename. Supports variable substitution (see
-       linkgit:git-cvsserver[1] for details). May not contain semicolons (`;`).
-       Default: '%Ggitcvs.%m.sqlite'
-
-gitcvs.dbDriver::
-       Used Perl DBI driver. You can specify any available driver
-       for this here, but it might not work. git-cvsserver is tested
-       with 'DBD::SQLite', reported to work with 'DBD::Pg', and
-       reported *not* to work with 'DBD::mysql'. Experimental feature.
-       May not contain double colons (`:`). Default: 'SQLite'.
-       See linkgit:git-cvsserver[1].
-
-gitcvs.dbUser, gitcvs.dbPass::
-       Database user and password. Only useful if setting `gitcvs.dbDriver`,
-       since SQLite has no concept of database users and/or passwords.
-       'gitcvs.dbUser' supports variable substitution (see
-       linkgit:git-cvsserver[1] for details).
-
-gitcvs.dbTableNamePrefix::
-       Database table name prefix.  Prepended to the names of any
-       database tables used, allowing a single database to be used
-       for several repositories.  Supports variable substitution (see
-       linkgit:git-cvsserver[1] for details).  Any non-alphabetic
-       characters will be replaced with underscores.
-
-All gitcvs variables except for `gitcvs.usecrlfattr` and
-`gitcvs.allBinary` can also be specified as
-'gitcvs.<access_method>.<varname>' (where 'access_method'
-is one of "ext" and "pserver") to make them apply only for the given
-access method.
+include::gitcvs-config.txt[]
 
 gitweb.category::
 gitweb.description::
@@ -1978,63 +1770,7 @@ gpg.<format>.program::
        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.
-
-gui.diffContext::
-       Specifies how many context lines should be used in calls to diff
-       made by the linkgit:git-gui[1]. The default is "5".
-
-gui.displayUntracked::
-       Determines if linkgit:git-gui[1] shows untracked files
-       in the file list. The default is "true".
-
-gui.encoding::
-       Specifies the default encoding to use for displaying of
-       file contents in linkgit:git-gui[1] and linkgit:gitk[1].
-       It can be overridden by setting the 'encoding' attribute
-       for relevant files (see linkgit:gitattributes[5]).
-       If this option is not set, the tools default to the
-       locale encoding.
-
-gui.matchTrackingBranch::
-       Determines if new branches created with linkgit:git-gui[1] should
-       default to tracking remote branches with matching names or
-       not. Default: "false".
-
-gui.newBranchTemplate::
-       Is used as suggested name when creating new branches using the
-       linkgit:git-gui[1].
-
-gui.pruneDuringFetch::
-       "true" if linkgit:git-gui[1] should prune remote-tracking branches when
-       performing a fetch. The default value is "false".
-
-gui.trustmtime::
-       Determines if linkgit:git-gui[1] should trust the file modification
-       timestamp or not. By default the timestamps are not trusted.
-
-gui.spellingDictionary::
-       Specifies the dictionary used for spell checking commit messages in
-       the linkgit:git-gui[1]. When set to "none" spell checking is turned
-       off.
-
-gui.fastCopyBlame::
-       If true, 'git gui blame' uses `-C` instead of `-C -C` for original
-       location detection. It makes blame significantly faster on huge
-       repositories at the expense of less thorough copy detection.
-
-gui.copyBlameThreshold::
-       Specifies the threshold to use in 'git gui blame' original location
-       detection, measured in alphanumeric characters. See the
-       linkgit:git-blame[1] manual for more information on copy detection.
-
-gui.blamehistoryctx::
-       Specifies the radius of history context in days to show in
-       linkgit:gitk[1] for the selected commit, when the `Show History
-       Context` menu item is invoked from 'git gui blame'. If this
-       variable is set to zero, the whole history is shown.
+include::gui-config.txt[]
 
 guitool.<name>.cmd::
        Specifies the shell command line to execute when the corresponding item
@@ -2860,282 +2596,13 @@ protocol.version::
 
 --
 
-pull.ff::
-       By default, Git does not create an extra merge commit when merging
-       a commit that is a descendant of the current commit. Instead, the
-       tip of the current branch is fast-forwarded. When set to `false`,
-       this variable tells Git to create an extra merge commit in such
-       a case (equivalent to giving the `--no-ff` option from the command
-       line). When set to `only`, only such fast-forward merges are
-       allowed (equivalent to giving the `--ff-only` option from the
-       command line). This setting overrides `merge.ff` when pulling.
-
-pull.rebase::
-       When true, rebase branches on top of the fetched branch, instead
-       of merging the default branch from the default remote when "git
-       pull" is run. See "branch.<name>.rebase" for setting this on a
-       per-branch basis.
-+
-When `merges`, pass the `--rebase-merges` option to 'git rebase'
-so that the local merge commits are included in the rebase (see
-linkgit:git-rebase[1] for details).
-+
-When preserve, also pass `--preserve-merges` along to 'git rebase'
-so that locally committed merge commits will not be flattened
-by running 'git pull'.
-+
-When the value is `interactive`, the rebase is run in interactive mode.
-+
-*NOTE*: this is a possibly dangerous operation; do *not* use
-it unless you understand the implications (see linkgit:git-rebase[1]
-for details).
-
-pull.octopus::
-       The default merge strategy to use when pulling multiple branches
-       at once.
-
-pull.twohead::
-       The default merge strategy to use when pulling a single branch.
-
-push.default::
-       Defines the action `git push` should take if no refspec is
-       explicitly given.  Different values are well-suited for
-       specific workflows; for instance, in a purely central workflow
-       (i.e. the fetch source is equal to the push destination),
-       `upstream` is probably what you want.  Possible values are:
-+
---
-
-* `nothing` - do not push anything (error out) unless a refspec is
-  explicitly given. This is primarily meant for people who want to
-  avoid mistakes by always being explicit.
-
-* `current` - push the current branch to update a branch with the same
-  name on the receiving end.  Works in both central and non-central
-  workflows.
+include::pull-config.txt[]
 
-* `upstream` - push the current branch back to the branch whose
-  changes are usually integrated into the current branch (which is
-  called `@{upstream}`).  This mode only makes sense if you are
-  pushing to the same repository you would normally pull from
-  (i.e. central workflow).
-
-* `tracking` - This is a deprecated synonym for `upstream`.
-
-* `simple` - in centralized workflow, work like `upstream` with an
-  added safety to refuse to push if the upstream branch's name is
-  different from the local one.
-+
-When pushing to a remote that is different from the remote you normally
-pull from, work as `current`.  This is the safest option and is suited
-for beginners.
-+
-This mode has become the default in Git 2.0.
-
-* `matching` - push all branches having the same name on both ends.
-  This makes the repository you are pushing to remember the set of
-  branches that will be pushed out (e.g. if you always push 'maint'
-  and 'master' there and no other branches, the repository you push
-  to will have these two branches, and your local 'maint' and
-  'master' will be pushed there).
-+
-To use this mode effectively, you have to make sure _all_ the
-branches you would push out are ready to be pushed out before
-running 'git push', as the whole point of this mode is to allow you
-to push all of the branches in one go.  If you usually finish work
-on only one branch and push out the result, while other branches are
-unfinished, this mode is not for you.  Also this mode is not
-suitable for pushing into a shared central repository, as other
-people may add new branches there, or update the tip of existing
-branches outside your control.
-+
-This used to be the default, but not since Git 2.0 (`simple` is the
-new default).
-
---
-
-push.followTags::
-       If set to true enable `--follow-tags` option by default.  You
-       may override this configuration at time of push by specifying
-       `--no-follow-tags`.
-
-push.gpgSign::
-       May be set to a boolean value, or the string 'if-asked'. A true
-       value causes all pushes to be GPG signed, as if `--signed` is
-       passed to linkgit:git-push[1]. The string 'if-asked' causes
-       pushes to be signed if the server supports it, as if
-       `--signed=if-asked` is passed to 'git push'. A false value may
-       override a value from a lower-priority config file. An explicit
-       command-line flag always overrides this config option.
-
-push.pushOption::
-       When no `--push-option=<option>` argument is given from the
-       command line, `git push` behaves as if each <value> of
-       this variable is given as `--push-option=<value>`.
-+
-This is a multi-valued variable, and an empty value can be used in a
-higher priority configuration file (e.g. `.git/config` in a
-repository) to clear the values inherited from a lower priority
-configuration files (e.g. `$HOME/.gitconfig`).
-+
---
-
-Example:
-
-/etc/gitconfig
-  push.pushoption = a
-  push.pushoption = b
-
-~/.gitconfig
-  push.pushoption = c
-
-repo/.git/config
-  push.pushoption =
-  push.pushoption = b
-
-This will result in only b (a and c are cleared).
-
---
-
-push.recurseSubmodules::
-       Make sure all submodule commits used by the revisions to be pushed
-       are available on a remote-tracking branch. If the value is 'check'
-       then Git will verify that all submodule commits that changed in the
-       revisions to be pushed are available on at least one remote of the
-       submodule. If any commits are missing, the push will be aborted and
-       exit with non-zero status. If the value is 'on-demand' then all
-       submodules that changed in the revisions to be pushed will be
-       pushed. If on-demand was not able to push all necessary revisions
-       it will also be aborted and exit with non-zero status. If the value
-       is 'no' then default behavior of ignoring submodules when pushing
-       is retained. You may override this configuration at time of push by
-       specifying '--recurse-submodules=check|on-demand|no'.
+include::push-config.txt[]
 
 include::rebase-config.txt[]
 
-receive.advertiseAtomic::
-       By default, git-receive-pack will advertise the atomic push
-       capability to its clients. If you don't want to advertise this
-       capability, set this variable to false.
-
-receive.advertisePushOptions::
-       When set to true, git-receive-pack will advertise the push options
-       capability to its clients. False by default.
-
-receive.autogc::
-       By default, git-receive-pack will run "git-gc --auto" after
-       receiving data from git-push and updating refs.  You can stop
-       it by setting this variable to false.
-
-receive.certNonceSeed::
-       By setting this variable to a string, `git receive-pack`
-       will accept a `git push --signed` and verifies it by using
-       a "nonce" protected by HMAC using this string as a secret
-       key.
-
-receive.certNonceSlop::
-       When a `git push --signed` sent a push certificate with a
-       "nonce" that was issued by a receive-pack serving the same
-       repository within this many seconds, export the "nonce"
-       found in the certificate to `GIT_PUSH_CERT_NONCE` to the
-       hooks (instead of what the receive-pack asked the sending
-       side to include).  This may allow writing checks in
-       `pre-receive` and `post-receive` a bit easier.  Instead of
-       checking `GIT_PUSH_CERT_NONCE_SLOP` environment variable
-       that records by how many seconds the nonce is stale to
-       decide if they want to accept the certificate, they only
-       can check `GIT_PUSH_CERT_NONCE_STATUS` is `OK`.
-
-receive.fsckObjects::
-       If it is set to true, git-receive-pack will check all received
-       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>::
-       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::
-       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
-       produce no output (if `--quiet` was specified) while processing
-       the pack, causing some networks to drop the TCP connection.
-       With this option set, if `receive-pack` does not transmit
-       any data in this phase for `receive.keepAlive` seconds, it will
-       send a short keepalive packet.  The default is 5 seconds; set
-       to 0 to disable keepalives entirely.
-
-receive.unpackLimit::
-       If the number of objects received in a push is below this
-       limit then the objects will be unpacked into loose object
-       files. However if the number of received objects equals or
-       exceeds this limit then the received pack will be stored as
-       a pack, after adding any missing delta bases.  Storing the
-       pack from a push can make the push operation complete faster,
-       especially on slow filesystems.  If not set, the value of
-       `transfer.unpackLimit` is used instead.
-
-receive.maxInputSize::
-       If the size of the incoming pack stream is larger than this
-       limit, then git-receive-pack will error out, instead of
-       accepting the pack file. If not set or set to 0, then the size
-       is unlimited.
-
-receive.denyDeletes::
-       If set to true, git-receive-pack will deny a ref update that deletes
-       the ref. Use this to prevent such a ref deletion via a push.
-
-receive.denyDeleteCurrent::
-       If set to true, git-receive-pack will deny a ref update that
-       deletes the currently checked out branch of a non-bare repository.
-
-receive.denyCurrentBranch::
-       If set to true or "refuse", git-receive-pack will deny a ref update
-       to the currently checked out branch of a non-bare repository.
-       Such a push is potentially dangerous because it brings the HEAD
-       out of sync with the index and working tree. If set to "warn",
-       print a warning of such a push to stderr, but allow the push to
-       proceed. If set to false or "ignore", allow such pushes with no
-       message. Defaults to "refuse".
-+
-Another option is "updateInstead" which will update the working
-tree if pushing into the current branch.  This option is
-intended for synchronizing working directories when one side is not easily
-accessible via interactive ssh (e.g. a live web site, hence the requirement
-that the working directory be clean). This mode also comes in handy when
-developing inside a VM to test and fix code on different Operating Systems.
-+
-By default, "updateInstead" will refuse the push if the working tree or
-the index have any difference from the HEAD, but the `push-to-checkout`
-hook can be used to customize this.  See linkgit:githooks[5].
-
-receive.denyNonFastForwards::
-       If set to true, git-receive-pack will deny a ref update which is
-       not a fast-forward. Use this to prevent such an update via a push,
-       even if that push is forced. This configuration variable is
-       set when initializing a shared repository.
-
-receive.hideRefs::
-       This variable is the same as `transfer.hideRefs`, but applies
-       only to `receive-pack` (and so affects pushes, but not fetches).
-       An attempt to update or delete a hidden ref by `git push` is
-       rejected.
-
-receive.updateServerInfo::
-       If set to true, git-receive-pack will run git-update-server-info
-       after receiving data from git-push and updating refs.
-
-receive.shallowUpdate::
-       If set to true, .git/shallow can be updated when new refs
-       require new shallow roots. Otherwise those refs are rejected.
+include::receive-config.txt[]
 
 remote.pushDefault::
        The remote to push to by default.  Overrides
@@ -3261,71 +2728,15 @@ rerere.enabled::
        `$GIT_DIR`, e.g. if "rerere" was previously used in the
        repository.
 
-sendemail.identity::
-       A configuration identity. When given, causes values in the
-       'sendemail.<identity>' subsection to take precedence over
-       values in the 'sendemail' section. The default identity is
-       the value of `sendemail.identity`.
-
-sendemail.smtpEncryption::
-       See linkgit:git-send-email[1] for description.  Note that this
-       setting is not subject to the 'identity' mechanism.
-
-sendemail.smtpssl (deprecated)::
-       Deprecated alias for 'sendemail.smtpEncryption = ssl'.
-
-sendemail.smtpsslcertpath::
-       Path to ca-certificates (either a directory or a single file).
-       Set it to an empty string to disable certificate verification.
-
-sendemail.<identity>.*::
-       Identity-specific versions of the 'sendemail.*' parameters
-       found below, taking precedence over those when this
-       identity is selected, through either the command-line or
-       `sendemail.identity`.
-
-sendemail.aliasesFile::
-sendemail.aliasFileType::
-sendemail.annotate::
-sendemail.bcc::
-sendemail.cc::
-sendemail.ccCmd::
-sendemail.chainReplyTo::
-sendemail.confirm::
-sendemail.envelopeSender::
-sendemail.from::
-sendemail.multiEdit::
-sendemail.signedoffbycc::
-sendemail.smtpPass::
-sendemail.suppresscc::
-sendemail.suppressFrom::
-sendemail.to::
-sendemail.tocmd::
-sendemail.smtpDomain::
-sendemail.smtpServer::
-sendemail.smtpServerPort::
-sendemail.smtpServerOption::
-sendemail.smtpUser::
-sendemail.thread::
-sendemail.transferEncoding::
-sendemail.validate::
-sendemail.xmailer::
-       See linkgit:git-send-email[1] for description.
-
-sendemail.signedoffcc (deprecated)::
-       Deprecated alias for `sendemail.signedoffbycc`.
-
-sendemail.smtpBatchSize::
-       Number of messages to be sent per connection, after that a relogin
-       will happen.  If the value is 0 or undefined, send all messages in
-       one connection.
-       See also the `--batch-size` option of linkgit:git-send-email[1].
-
-sendemail.smtpReloginDelay::
-       Seconds wait before reconnecting to smtp server.
-       See also the `--relogin-delay` option of linkgit:git-send-email[1].
-
-showbranch.default::
+include::sendemail-config.txt[]
+
+sequence.editor::
+       Text editor used by `git rebase -i` for editing the rebase instruction file.
+       The value is meant to be interpreted by the shell when it is used.
+       It can be overridden by the `GIT_SEQUENCE_EDITOR` environment variable.
+       When not configured the default commit message editor is used instead.
+
+showBranch.default::
        The default set of branches for linkgit:git-show-branch[1].
        See linkgit:git-show-branch[1].
 
@@ -3437,88 +2848,7 @@ stash.showStat::
        option will show diffstat of the stash entry.  Defaults to true.
        See description of 'show' command in linkgit:git-stash[1].
 
-submodule.<name>.url::
-       The URL for a submodule. This variable is copied from the .gitmodules
-       file to the git config via 'git submodule init'. The user can change
-       the configured URL before obtaining the submodule via 'git submodule
-       update'. If neither submodule.<name>.active or submodule.active are
-       set, the presence of this variable is used as a fallback to indicate
-       whether the submodule is of interest to git commands.
-       See linkgit:git-submodule[1] and linkgit:gitmodules[5] for details.
-
-submodule.<name>.update::
-       The method by which a submodule is updated by 'git submodule update',
-       which is the only affected command, others such as
-       'git checkout --recurse-submodules' are unaffected. It exists for
-       historical reasons, when 'git submodule' was the only command to
-       interact with submodules; settings like `submodule.active`
-       and `pull.rebase` are more specific. It is populated by
-       `git submodule init` from the linkgit:gitmodules[5] file.
-       See description of 'update' command in linkgit:git-submodule[1].
-
-submodule.<name>.branch::
-       The remote branch name for a submodule, used by `git submodule
-       update --remote`.  Set this option to override the value found in
-       the `.gitmodules` file.  See linkgit:git-submodule[1] and
-       linkgit:gitmodules[5] for details.
-
-submodule.<name>.fetchRecurseSubmodules::
-       This option can be used to control recursive fetching of this
-       submodule. It can be overridden by using the --[no-]recurse-submodules
-       command-line option to "git fetch" and "git pull".
-       This setting will override that from in the linkgit:gitmodules[5]
-       file.
-
-submodule.<name>.ignore::
-       Defines under what circumstances "git status" and the diff family show
-       a submodule as modified. When set to "all", it will never be considered
-       modified (but it will nonetheless show up in the output of status and
-       commit when it has been staged), "dirty" will ignore all changes
-       to the submodules work tree and
-       takes only differences between the HEAD of the submodule and the commit
-       recorded in the superproject into account. "untracked" will additionally
-       let submodules with modified tracked files in their work tree show up.
-       Using "none" (the default when this option is not set) also shows
-       submodules that have untracked files in their work tree as changed.
-       This setting overrides any setting made in .gitmodules for this submodule,
-       both settings can be overridden on the command line by using the
-       "--ignore-submodules" option. The 'git submodule' commands are not
-       affected by this setting.
-
-submodule.<name>.active::
-       Boolean value indicating if the submodule is of interest to git
-       commands.  This config option takes precedence over the
-       submodule.active config option. See linkgit:gitsubmodules[7] for
-       details.
-
-submodule.active::
-       A repeated field which contains a pathspec used to match against a
-       submodule's path to determine if the submodule is of interest to git
-       commands. See linkgit:gitsubmodules[7] for details.
-
-submodule.recurse::
-       Specifies if commands recurse into submodules by default. This
-       applies to all commands that have a `--recurse-submodules` option,
-       except `clone`.
-       Defaults to false.
-
-submodule.fetchJobs::
-       Specifies how many submodules are fetched/cloned at the same time.
-       A positive integer allows up to that number of submodules fetched
-       in parallel. A value of 0 will give some reasonable default.
-       If unset, it defaults to 1.
-
-submodule.alternateLocation::
-       Specifies how the submodules obtain alternates when submodules are
-       cloned. Possible values are `no`, `superproject`.
-       By default `no` is assumed, which doesn't add references. When the
-       value is set to `superproject` the submodule to be cloned computes
-       its alternates location relative to the superprojects alternate.
-
-submodule.alternateErrorStrategy::
-       Specifies how to treat errors with the alternates for a submodule
-       as computed via `submodule.alternateLocation`. Possible values are
-       `ignore`, `info`, `die`. Default is `die`.
+include::submodule-config.txt[]
 
 tag.forceSignAnnotated::
        A boolean to specify whether annotated tags created should be GPG signed.
@@ -3666,15 +2996,15 @@ uploadpack.packObjectsHook::
        was run. I.e., `upload-pack` will feed input intended for
        `pack-objects` to the hook, and expects a completed packfile on
        stdout.
-
-uploadpack.allowFilter::
-       If this option is set, `upload-pack` will support partial
-       clone and partial fetch object filtering.
 +
 Note that this configuration variable is ignored if it is seen in the
 repository-level config (this is a safety measure against fetching from
 untrusted repositories).
 
+uploadpack.allowFilter::
+       If this option is set, `upload-pack` will support partial
+       clone and partial fetch object filtering.
+
 uploadpack.allowRefInWant::
        If this option is set, `upload-pack` will support the `ref-in-want`
        feature of the protocol version 2 `fetch` command.  This feature
diff --git a/Documentation/fetch-config.txt b/Documentation/fetch-config.txt
new file mode 100644 (file)
index 0000000..cbfad6c
--- /dev/null
@@ -0,0 +1,65 @@
+fetch.recurseSubmodules::
+       This option can be either set to a boolean value or to 'on-demand'.
+       Setting it to a boolean changes the behavior of fetch and pull to
+       unconditionally recurse into submodules when set to true or to not
+       recurse at all when set to false. When set to 'on-demand' (the default
+       value), fetch and pull will only recurse into a populated submodule
+       when its superproject retrieves a commit that updates the submodule's
+       reference.
+
+fetch.fsckObjects::
+       If it is set to true, git-fetch-pack will check all fetched
+       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
+       transfer is below this
+       limit, then the objects will be unpacked into loose object
+       files. However if the number of received objects equals or
+       exceeds this limit then the received pack will be stored as
+       a pack, after adding any missing delta bases.  Storing the
+       pack from a push can make the push operation complete faster,
+       especially on slow filesystems.  If not set, the value of
+       `transfer.unpackLimit` is used instead.
+
+fetch.prune::
+       If true, fetch will automatically behave as if the `--prune`
+       option was given on the command line.  See also `remote.<name>.prune`
+       and the PRUNING section of linkgit:git-fetch[1].
+
+fetch.pruneTags::
+       If true, fetch will automatically behave as if the
+       `refs/tags/*:refs/tags/*` refspec was provided when pruning,
+       if not set already. This allows for setting both this option
+       and `fetch.prune` to maintain a 1=1 mapping to upstream
+       refs. See also `remote.<name>.pruneTags` and the PRUNING
+       section of linkgit:git-fetch[1].
+
+fetch.output::
+       Control how ref update status is printed. Valid values are
+       `full` and `compact`. Default value is `full`. See section
+       OUTPUT in linkgit:git-fetch[1] for detail.
+
+fetch.negotiationAlgorithm::
+       Control how information about the commits in the local repository is
+       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; 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].
diff --git a/Documentation/format-config.txt b/Documentation/format-config.txt
new file mode 100644 (file)
index 0000000..dc77941
--- /dev/null
@@ -0,0 +1,87 @@
+format.attach::
+       Enable multipart/mixed attachments as the default for
+       'format-patch'.  The value can also be a double quoted string
+       which will enable attachments as the default and set the
+       value as the boundary.  See the --attach option in
+       linkgit:git-format-patch[1].
+
+format.from::
+       Provides the default value for the `--from` option to format-patch.
+       Accepts a boolean value, or a name and email address.  If false,
+       format-patch defaults to `--no-from`, using commit authors directly in
+       the "From:" field of patch mails.  If true, format-patch defaults to
+       `--from`, using your committer identity in the "From:" field of patch
+       mails and including a "From:" field in the body of the patch mail if
+       different.  If set to a non-boolean value, format-patch uses that
+       value instead of your committer identity.  Defaults to false.
+
+format.numbered::
+       A boolean which can enable or disable sequence numbers in patch
+       subjects.  It defaults to "auto" which enables it only if there
+       is more than one patch.  It can be enabled or disabled for all
+       messages by setting it to "true" or "false".  See --numbered
+       option in linkgit:git-format-patch[1].
+
+format.headers::
+       Additional email headers to include in a patch to be submitted
+       by mail.  See linkgit:git-format-patch[1].
+
+format.to::
+format.cc::
+       Additional recipients to include in a patch to be submitted
+       by mail.  See the --to and --cc options in
+       linkgit:git-format-patch[1].
+
+format.subjectPrefix::
+       The default for format-patch is to output files with the '[PATCH]'
+       subject prefix. Use this variable to change that prefix.
+
+format.signature::
+       The default for format-patch is to output a signature containing
+       the Git version number. Use this variable to change that default.
+       Set this variable to the empty string ("") to suppress
+       signature generation.
+
+format.signatureFile::
+       Works just like format.signature except the contents of the
+       file specified by this variable will be used as the signature.
+
+format.suffix::
+       The default for format-patch is to output files with the suffix
+       `.patch`. Use this variable to change that suffix (make sure to
+       include the dot if you want it).
+
+format.pretty::
+       The default pretty format for log/show/whatchanged command,
+       See linkgit:git-log[1], linkgit:git-show[1],
+       linkgit:git-whatchanged[1].
+
+format.thread::
+       The default threading style for 'git format-patch'.  Can be
+       a boolean value, or `shallow` or `deep`.  `shallow` threading
+       makes every mail a reply to the head of the series,
+       where the head is chosen from the cover letter, the
+       `--in-reply-to`, and the first patch mail, in this order.
+       `deep` threading makes every mail a reply to the previous one.
+       A true boolean value is the same as `shallow`, and a false
+       value disables threading.
+
+format.signOff::
+       A boolean value which lets you enable the `-s/--signoff` option of
+       format-patch by default. *Note:* Adding the Signed-off-by: line to a
+       patch should be a conscious act and means that you certify you have
+       the rights to submit this work under the same open source license.
+       Please see the 'SubmittingPatches' document for further discussion.
+
+format.coverLetter::
+       A boolean that controls whether to generate a cover-letter when
+       format-patch is invoked, but in addition can be set to "auto", to
+       generate a cover-letter only when there's more than one patch.
+
+format.outputDirectory::
+       Set a custom directory to store the resulting files instead of the
+       current working directory.
+
+format.useAutoBase::
+       A boolean value which lets you enable the `--base=auto` option of
+       format-patch by default.
index ea70653..a595a0f 100644 (file)
@@ -3,7 +3,7 @@ git-archimport(1)
 
 NAME
 ----
-git-archimport - Import an Arch repository into Git
+git-archimport - Import a GNU Arch repository into Git
 
 
 SYNOPSIS
@@ -14,7 +14,8 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Imports a project from one or more Arch repositories. It will follow branches
+Imports a project from one or more GNU Arch repositories.
+It will follow branches
 and repositories within the namespaces defined by the <archive/branch>
 parameters supplied. If it cannot find the remote branch a merge comes from
 it will just import it as a regular commit. If it can find it, it will mark it
index 03d1846..763afab 100644 (file)
@@ -13,7 +13,10 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-This command formats its input into multiple columns.
+This command formats the lines of its standard input into a table with
+multiple columns. Each input line occupies one cell of the table. It
+is used internally by other git commands to format output into
+columns.
 
 OPTIONS
 -------
@@ -23,7 +26,7 @@ OPTIONS
 
 --mode=<mode>::
        Specify layout mode. See configuration variable column.ui for option
-       syntax.
+       syntax in linkgit:git-config[1].
 
 --raw-mode=<n>::
        Same as --mode but take mode encoded as a number. This is mainly used
@@ -43,6 +46,34 @@ OPTIONS
 --padding=<N>::
        The number of spaces between columns. One space by default.
 
+EXAMPLES
+------
+
+Format data by columns:
+------------
+$ seq 1 24 | git column --mode=column --padding=5
+1      4      7      10     13     16     19     22
+2      5      8      11     14     17     20     23
+3      6      9      12     15     18     21     24
+------------
+
+Format data by rows:
+------------
+$ seq 1 21 | git column --mode=row --padding=5
+1      2      3      4      5      6      7
+8      9      10     11     12     13     14
+15     16     17     18     19     20     21
+------------
+
+List some tags in a table with unequal column widths:
+------------
+$ git tag --list 'v2.4.*' --column=row,dense
+v2.4.0  v2.4.0-rc0  v2.4.0-rc1  v2.4.0-rc2  v2.4.0-rc3
+v2.4.1  v2.4.10     v2.4.11     v2.4.12     v2.4.2
+v2.4.3  v2.4.4      v2.4.5      v2.4.6      v2.4.7
+v2.4.8  v2.4.9
+------------
+
 GIT
 ---
 Part of the linkgit:git[1] suite
index dececb7..624470e 100644 (file)
@@ -3,7 +3,7 @@ git-commit-graph(1)
 
 NAME
 ----
-git-commit-graph - Write and verify Git commit graph files
+git-commit-graph - Write and verify Git commit-graph files
 
 
 SYNOPSIS
@@ -17,24 +17,24 @@ SYNOPSIS
 DESCRIPTION
 -----------
 
-Manage the serialized commit graph file.
+Manage the serialized commit-graph file.
 
 
 OPTIONS
 -------
 --object-dir::
-       Use given directory for the location of packfiles and commit graph
+       Use given directory for the location of packfiles and commit-graph
        file. This parameter exists to specify the location of an alternate
-       that only has the objects directory, not a full .git directory. The
-       commit graph file is expected to be at <dir>/info/commit-graph and
-       the packfiles are expected to be in <dir>/pack.
+       that only has the objects directory, not a full `.git` directory. The
+       commit-graph file is expected to be at `<dir>/info/commit-graph` and
+       the packfiles are expected to be in `<dir>/pack`.
 
 
 COMMANDS
 --------
 'write'::
 
-Write a commit graph file based on the commits found in packfiles.
+Write a commit-graph file based on the commits found in packfiles.
 +
 With the `--stdin-packs` option, generate the new commit graph by
 walking objects only in the specified pack-indexes. (Cannot be combined
@@ -54,8 +54,8 @@ existing commit-graph file.
 
 'read'::
 
-Read a graph file given by the commit-graph file and output basic
-details about the graph file. Used for debugging purposes.
+Read the commit-graph file and output basic details about it.
+Used for debugging purposes.
 
 'verify'::
 
@@ -66,27 +66,28 @@ database. Used to check for corrupted data.
 EXAMPLES
 --------
 
-* Write a commit graph file for the packed commits in your local .git folder.
+* Write a commit-graph file for the packed commits in your local `.git`
+  directory.
 +
 ------------------------------------------------
 $ git commit-graph write
 ------------------------------------------------
 
-* Write a graph file, extending the current graph file using commits
-* in <pack-index>.
+* Write a commit-graph file, extending the current commit-graph file
+  using commits in `<pack-index>`.
 +
 ------------------------------------------------
 $ echo <pack-index> | git commit-graph write --stdin-packs
 ------------------------------------------------
 
-* Write a graph file containing all reachable commits.
+* Write a commit-graph file containing all reachable commits.
 +
 ------------------------------------------------
 $ git show-ref -s | git commit-graph write --stdin-commits
 ------------------------------------------------
 
-* Write a graph file containing all commits in the current
-* commit-graph file along with those reachable from HEAD.
+* Write a commit-graph file containing all commits in the current
+  commit-graph file along with those reachable from `HEAD`.
 +
 ------------------------------------------------
 $ git rev-parse HEAD | git commit-graph write --stdin-commits --append
index 8e24043..5e87d82 100644 (file)
@@ -188,8 +188,8 @@ Valid `<type>`'s include:
 --bool-or-int::
 --path::
 --expiry-date::
-  Historical options for selecting a type specifier. Prefer instead `--type`,
-  (see: above).
+  Historical options for selecting a type specifier. Prefer instead `--type`
+  (see above).
 
 --no-type::
   Un-sets the previously set type specifier (if one was previously set). This
@@ -442,9 +442,9 @@ For URLs in `https://weak.example.com`, `http.sslVerify` is set to
 false, while it is set to `true` for all others:
 
 ------------
-% git config --bool --get-urlmatch http.sslverify https://good.example.com
+% git config --type=bool --get-urlmatch http.sslverify https://good.example.com
 true
-% git config --bool --get-urlmatch http.sslverify https://weak.example.com
+% git config --type=bool --get-urlmatch http.sslverify https://weak.example.com
 false
 % git config --get-urlmatch http https://weak.example.com
 http.cookieFile /tmp/cookie.txt
index e027fb8..ccdc5f8 100644 (file)
@@ -18,7 +18,9 @@ The command finds the most recent tag that is reachable from a
 commit.  If the tag points to the commit, then only the tag is
 shown.  Otherwise, it suffixes the tag name with the number of
 additional commits on top of the tagged object and the
-abbreviated object name of the most recent commit.
+abbreviated object name of the most recent commit. The result
+is a "human-readable" object name which can also be used to
+identify the commit to other git commands.
 
 By default (without --all or --tags) `git describe` only shows
 annotated tags.  For more information about creating annotated tags
index 1f97e79..f7778a2 100644 (file)
@@ -27,6 +27,10 @@ write::
        When given as the verb, write a new MIDX file to
        `<dir>/packs/multi-pack-index`.
 
+verify::
+       When given as the verb, verify the contents of the MIDX file
+       at `<dir>/packs/multi-pack-index`.
+
 
 EXAMPLES
 --------
@@ -43,6 +47,12 @@ $ git multi-pack-index write
 $ git multi-pack-index --object-dir <alt> write
 -----------------------------------------------
 
+* Verify the MIDX file for the packfiles in the current .git folder.
++
+-----------------------------------------------
+$ git multi-pack-index verify
+-----------------------------------------------
+
 
 SEE ALSO
 --------
index 1fbc6eb..432baab 100644 (file)
@@ -954,7 +954,7 @@ command fails, it is rescheduled immediately, with a helpful message how
 to proceed.
 
 The `reset` command resets the HEAD, index and worktree to the specified
-revision. It is isimilar to an `exec git reset --hard <label>`, but
+revision. It is similar to an `exec git reset --hard <label>`, but
 refuses to overwrite untracked files. If the `reset` command fails, it is
 rescheduled immediately, with a helpful message how to edit the todo list
 (this typically happens when a `reset` command was inserted into the todo
index 74a9d7e..2ac9b1c 100644 (file)
@@ -76,7 +76,7 @@ Note that omitting the `=` in `git -c foo.bar ...` is allowed and sets
 `foo.bar` to the boolean true value (just like `[foo]bar` would in a
 config file). Including the equals but with an empty value (like `git -c
 foo.bar= ...`) sets `foo.bar` to the empty string which `git config
---bool` will convert to `false`.
+--type=bool` will convert to `false`.
 
 --exec-path[=<path>]::
        Path to wherever your core Git programs are installed.
@@ -858,7 +858,9 @@ Reporting Bugs
 
 Report bugs to the Git mailing list <git@vger.kernel.org> where the
 development and maintenance is primarily done.  You do not have to be
-subscribed to the list to send a message there.
+subscribed to the list to send a message there.  See the list archive
+at https://public-inbox.org/git for previous bug reports and other
+discussions.
 
 Issues which are security relevant should be disclosed privately to
 the Git Security mailing list <git-security@googlegroups.com>.
index f970196..adc7596 100644 (file)
@@ -133,6 +133,12 @@ compares hostnames exactly, without considering whether two hosts are part of
 the same domain. Likewise, a config entry for `http://example.com` would not
 match: Git compares the protocols exactly.
 
+If the "pattern" URL does include a path component, then this too must match
+exactly: the context `https://example.com/bar/baz.git` will match a config
+entry for `https://example.com/bar/baz.git` (in addition to matching the config
+entry for `https://example.com`) but will not match a config entry for
+`https://example.com/bar`.
+
 
 CONFIGURATION OPTIONS
 ---------------------
diff --git a/Documentation/gitcvs-config.txt b/Documentation/gitcvs-config.txt
new file mode 100644 (file)
index 0000000..02da427
--- /dev/null
@@ -0,0 +1,67 @@
+gitcvs.commitMsgAnnotation::
+       Append this string to each commit message. Set to empty string
+       to disable this feature. Defaults to "via git-CVS emulator".
+
+gitcvs.enabled::
+       Whether the CVS server interface is enabled for this repository.
+       See linkgit:git-cvsserver[1].
+
+gitcvs.logFile::
+       Path to a log file where the CVS server interface well... logs
+       various stuff. See linkgit:git-cvsserver[1].
+
+gitcvs.usecrlfattr::
+       If true, the server will look up the end-of-line conversion
+       attributes for files to determine the `-k` modes to use. If
+       the attributes force Git to treat a file as text,
+       the `-k` mode will be left blank so CVS clients will
+       treat it as text. If they suppress text conversion, the file
+       will be set with '-kb' mode, which suppresses any newline munging
+       the client might otherwise do. If the attributes do not allow
+       the file type to be determined, then `gitcvs.allBinary` is
+       used. See linkgit:gitattributes[5].
+
+gitcvs.allBinary::
+       This is used if `gitcvs.usecrlfattr` does not resolve
+       the correct '-kb' mode to use. If true, all
+       unresolved files are sent to the client in
+       mode '-kb'. This causes the client to treat them
+       as binary files, which suppresses any newline munging it
+       otherwise might do. Alternatively, if it is set to "guess",
+       then the contents of the file are examined to decide if
+       it is binary, similar to `core.autocrlf`.
+
+gitcvs.dbName::
+       Database used by git-cvsserver to cache revision information
+       derived from the Git repository. The exact meaning depends on the
+       used database driver, for SQLite (which is the default driver) this
+       is a filename. Supports variable substitution (see
+       linkgit:git-cvsserver[1] for details). May not contain semicolons (`;`).
+       Default: '%Ggitcvs.%m.sqlite'
+
+gitcvs.dbDriver::
+       Used Perl DBI driver. You can specify any available driver
+       for this here, but it might not work. git-cvsserver is tested
+       with 'DBD::SQLite', reported to work with 'DBD::Pg', and
+       reported *not* to work with 'DBD::mysql'. Experimental feature.
+       May not contain double colons (`:`). Default: 'SQLite'.
+       See linkgit:git-cvsserver[1].
+
+gitcvs.dbUser, gitcvs.dbPass::
+       Database user and password. Only useful if setting `gitcvs.dbDriver`,
+       since SQLite has no concept of database users and/or passwords.
+       'gitcvs.dbUser' supports variable substitution (see
+       linkgit:git-cvsserver[1] for details).
+
+gitcvs.dbTableNamePrefix::
+       Database table name prefix.  Prepended to the names of any
+       database tables used, allowing a single database to be used
+       for several repositories.  Supports variable substitution (see
+       linkgit:git-cvsserver[1] for details).  Any non-alphabetic
+       characters will be replaced with underscores.
+
+All gitcvs variables except for `gitcvs.usecrlfattr` and
+`gitcvs.allBinary` can also be specified as
+'gitcvs.<access_method>.<varname>' (where 'access_method'
+is one of "ext" and "pserver") to make them apply only for the given
+access method.
diff --git a/Documentation/gui-config.txt b/Documentation/gui-config.txt
new file mode 100644 (file)
index 0000000..d30831a
--- /dev/null
@@ -0,0 +1,57 @@
+gui.commitMsgWidth::
+       Defines how wide the commit message window is in the
+       linkgit:git-gui[1]. "75" is the default.
+
+gui.diffContext::
+       Specifies how many context lines should be used in calls to diff
+       made by the linkgit:git-gui[1]. The default is "5".
+
+gui.displayUntracked::
+       Determines if linkgit:git-gui[1] shows untracked files
+       in the file list. The default is "true".
+
+gui.encoding::
+       Specifies the default encoding to use for displaying of
+       file contents in linkgit:git-gui[1] and linkgit:gitk[1].
+       It can be overridden by setting the 'encoding' attribute
+       for relevant files (see linkgit:gitattributes[5]).
+       If this option is not set, the tools default to the
+       locale encoding.
+
+gui.matchTrackingBranch::
+       Determines if new branches created with linkgit:git-gui[1] should
+       default to tracking remote branches with matching names or
+       not. Default: "false".
+
+gui.newBranchTemplate::
+       Is used as suggested name when creating new branches using the
+       linkgit:git-gui[1].
+
+gui.pruneDuringFetch::
+       "true" if linkgit:git-gui[1] should prune remote-tracking branches when
+       performing a fetch. The default value is "false".
+
+gui.trustmtime::
+       Determines if linkgit:git-gui[1] should trust the file modification
+       timestamp or not. By default the timestamps are not trusted.
+
+gui.spellingDictionary::
+       Specifies the dictionary used for spell checking commit messages in
+       the linkgit:git-gui[1]. When set to "none" spell checking is turned
+       off.
+
+gui.fastCopyBlame::
+       If true, 'git gui blame' uses `-C` instead of `-C -C` for original
+       location detection. It makes blame significantly faster on huge
+       repositories at the expense of less thorough copy detection.
+
+gui.copyBlameThreshold::
+       Specifies the threshold to use in 'git gui blame' original location
+       detection, measured in alphanumeric characters. See the
+       linkgit:git-blame[1] manual for more information on copy detection.
+
+gui.blamehistoryctx::
+       Specifies the radius of history context in days to show in
+       linkgit:gitk[1] for the selected commit, when the `Show History
+       Context` menu item is invoked from 'git gui blame'. If this
+       variable is set to zero, the whole history is shown.
diff --git a/Documentation/pull-config.txt b/Documentation/pull-config.txt
new file mode 100644 (file)
index 0000000..bb23a99
--- /dev/null
@@ -0,0 +1,36 @@
+pull.ff::
+       By default, Git does not create an extra merge commit when merging
+       a commit that is a descendant of the current commit. Instead, the
+       tip of the current branch is fast-forwarded. When set to `false`,
+       this variable tells Git to create an extra merge commit in such
+       a case (equivalent to giving the `--no-ff` option from the command
+       line). When set to `only`, only such fast-forward merges are
+       allowed (equivalent to giving the `--ff-only` option from the
+       command line). This setting overrides `merge.ff` when pulling.
+
+pull.rebase::
+       When true, rebase branches on top of the fetched branch, instead
+       of merging the default branch from the default remote when "git
+       pull" is run. See "branch.<name>.rebase" for setting this on a
+       per-branch basis.
++
+When `merges`, pass the `--rebase-merges` option to 'git rebase'
+so that the local merge commits are included in the rebase (see
+linkgit:git-rebase[1] for details).
++
+When preserve, also pass `--preserve-merges` along to 'git rebase'
+so that locally committed merge commits will not be flattened
+by running 'git pull'.
++
+When the value is `interactive`, the rebase is run in interactive mode.
++
+*NOTE*: this is a possibly dangerous operation; do *not* use
+it unless you understand the implications (see linkgit:git-rebase[1]
+for details).
+
+pull.octopus::
+       The default merge strategy to use when pulling multiple branches
+       at once.
+
+pull.twohead::
+       The default merge strategy to use when pulling a single branch.
diff --git a/Documentation/push-config.txt b/Documentation/push-config.txt
new file mode 100644 (file)
index 0000000..0a0e000
--- /dev/null
@@ -0,0 +1,113 @@
+push.default::
+       Defines the action `git push` should take if no refspec is
+       explicitly given.  Different values are well-suited for
+       specific workflows; for instance, in a purely central workflow
+       (i.e. the fetch source is equal to the push destination),
+       `upstream` is probably what you want.  Possible values are:
++
+--
+
+* `nothing` - do not push anything (error out) unless a refspec is
+  explicitly given. This is primarily meant for people who want to
+  avoid mistakes by always being explicit.
+
+* `current` - push the current branch to update a branch with the same
+  name on the receiving end.  Works in both central and non-central
+  workflows.
+
+* `upstream` - push the current branch back to the branch whose
+  changes are usually integrated into the current branch (which is
+  called `@{upstream}`).  This mode only makes sense if you are
+  pushing to the same repository you would normally pull from
+  (i.e. central workflow).
+
+* `tracking` - This is a deprecated synonym for `upstream`.
+
+* `simple` - in centralized workflow, work like `upstream` with an
+  added safety to refuse to push if the upstream branch's name is
+  different from the local one.
++
+When pushing to a remote that is different from the remote you normally
+pull from, work as `current`.  This is the safest option and is suited
+for beginners.
++
+This mode has become the default in Git 2.0.
+
+* `matching` - push all branches having the same name on both ends.
+  This makes the repository you are pushing to remember the set of
+  branches that will be pushed out (e.g. if you always push 'maint'
+  and 'master' there and no other branches, the repository you push
+  to will have these two branches, and your local 'maint' and
+  'master' will be pushed there).
++
+To use this mode effectively, you have to make sure _all_ the
+branches you would push out are ready to be pushed out before
+running 'git push', as the whole point of this mode is to allow you
+to push all of the branches in one go.  If you usually finish work
+on only one branch and push out the result, while other branches are
+unfinished, this mode is not for you.  Also this mode is not
+suitable for pushing into a shared central repository, as other
+people may add new branches there, or update the tip of existing
+branches outside your control.
++
+This used to be the default, but not since Git 2.0 (`simple` is the
+new default).
+
+--
+
+push.followTags::
+       If set to true enable `--follow-tags` option by default.  You
+       may override this configuration at time of push by specifying
+       `--no-follow-tags`.
+
+push.gpgSign::
+       May be set to a boolean value, or the string 'if-asked'. A true
+       value causes all pushes to be GPG signed, as if `--signed` is
+       passed to linkgit:git-push[1]. The string 'if-asked' causes
+       pushes to be signed if the server supports it, as if
+       `--signed=if-asked` is passed to 'git push'. A false value may
+       override a value from a lower-priority config file. An explicit
+       command-line flag always overrides this config option.
+
+push.pushOption::
+       When no `--push-option=<option>` argument is given from the
+       command line, `git push` behaves as if each <value> of
+       this variable is given as `--push-option=<value>`.
++
+This is a multi-valued variable, and an empty value can be used in a
+higher priority configuration file (e.g. `.git/config` in a
+repository) to clear the values inherited from a lower priority
+configuration files (e.g. `$HOME/.gitconfig`).
++
+--
+
+Example:
+
+/etc/gitconfig
+  push.pushoption = a
+  push.pushoption = b
+
+~/.gitconfig
+  push.pushoption = c
+
+repo/.git/config
+  push.pushoption =
+  push.pushoption = b
+
+This will result in only b (a and c are cleared).
+
+--
+
+push.recurseSubmodules::
+       Make sure all submodule commits used by the revisions to be pushed
+       are available on a remote-tracking branch. If the value is 'check'
+       then Git will verify that all submodule commits that changed in the
+       revisions to be pushed are available on at least one remote of the
+       submodule. If any commits are missing, the push will be aborted and
+       exit with non-zero status. If the value is 'on-demand' then all
+       submodules that changed in the revisions to be pushed will be
+       pushed. If on-demand was not able to push all necessary revisions
+       it will also be aborted and exit with non-zero status. If the value
+       is 'no' then default behavior of ignoring submodules when pushing
+       is retained. You may override this configuration at time of push by
+       specifying '--recurse-submodules=check|on-demand|no'.
diff --git a/Documentation/receive-config.txt b/Documentation/receive-config.txt
new file mode 100644 (file)
index 0000000..65f78aa
--- /dev/null
@@ -0,0 +1,123 @@
+receive.advertiseAtomic::
+       By default, git-receive-pack will advertise the atomic push
+       capability to its clients. If you don't want to advertise this
+       capability, set this variable to false.
+
+receive.advertisePushOptions::
+       When set to true, git-receive-pack will advertise the push options
+       capability to its clients. False by default.
+
+receive.autogc::
+       By default, git-receive-pack will run "git-gc --auto" after
+       receiving data from git-push and updating refs.  You can stop
+       it by setting this variable to false.
+
+receive.certNonceSeed::
+       By setting this variable to a string, `git receive-pack`
+       will accept a `git push --signed` and verifies it by using
+       a "nonce" protected by HMAC using this string as a secret
+       key.
+
+receive.certNonceSlop::
+       When a `git push --signed` sent a push certificate with a
+       "nonce" that was issued by a receive-pack serving the same
+       repository within this many seconds, export the "nonce"
+       found in the certificate to `GIT_PUSH_CERT_NONCE` to the
+       hooks (instead of what the receive-pack asked the sending
+       side to include).  This may allow writing checks in
+       `pre-receive` and `post-receive` a bit easier.  Instead of
+       checking `GIT_PUSH_CERT_NONCE_SLOP` environment variable
+       that records by how many seconds the nonce is stale to
+       decide if they want to accept the certificate, they only
+       can check `GIT_PUSH_CERT_NONCE_STATUS` is `OK`.
+
+receive.fsckObjects::
+       If it is set to true, git-receive-pack will check all received
+       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>::
+       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::
+       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
+       produce no output (if `--quiet` was specified) while processing
+       the pack, causing some networks to drop the TCP connection.
+       With this option set, if `receive-pack` does not transmit
+       any data in this phase for `receive.keepAlive` seconds, it will
+       send a short keepalive packet.  The default is 5 seconds; set
+       to 0 to disable keepalives entirely.
+
+receive.unpackLimit::
+       If the number of objects received in a push is below this
+       limit then the objects will be unpacked into loose object
+       files. However if the number of received objects equals or
+       exceeds this limit then the received pack will be stored as
+       a pack, after adding any missing delta bases.  Storing the
+       pack from a push can make the push operation complete faster,
+       especially on slow filesystems.  If not set, the value of
+       `transfer.unpackLimit` is used instead.
+
+receive.maxInputSize::
+       If the size of the incoming pack stream is larger than this
+       limit, then git-receive-pack will error out, instead of
+       accepting the pack file. If not set or set to 0, then the size
+       is unlimited.
+
+receive.denyDeletes::
+       If set to true, git-receive-pack will deny a ref update that deletes
+       the ref. Use this to prevent such a ref deletion via a push.
+
+receive.denyDeleteCurrent::
+       If set to true, git-receive-pack will deny a ref update that
+       deletes the currently checked out branch of a non-bare repository.
+
+receive.denyCurrentBranch::
+       If set to true or "refuse", git-receive-pack will deny a ref update
+       to the currently checked out branch of a non-bare repository.
+       Such a push is potentially dangerous because it brings the HEAD
+       out of sync with the index and working tree. If set to "warn",
+       print a warning of such a push to stderr, but allow the push to
+       proceed. If set to false or "ignore", allow such pushes with no
+       message. Defaults to "refuse".
++
+Another option is "updateInstead" which will update the working
+tree if pushing into the current branch.  This option is
+intended for synchronizing working directories when one side is not easily
+accessible via interactive ssh (e.g. a live web site, hence the requirement
+that the working directory be clean). This mode also comes in handy when
+developing inside a VM to test and fix code on different Operating Systems.
++
+By default, "updateInstead" will refuse the push if the working tree or
+the index have any difference from the HEAD, but the `push-to-checkout`
+hook can be used to customize this.  See linkgit:githooks[5].
+
+receive.denyNonFastForwards::
+       If set to true, git-receive-pack will deny a ref update which is
+       not a fast-forward. Use this to prevent such an update via a push,
+       even if that push is forced. This configuration variable is
+       set when initializing a shared repository.
+
+receive.hideRefs::
+       This variable is the same as `transfer.hideRefs`, but applies
+       only to `receive-pack` (and so affects pushes, but not fetches).
+       An attempt to update or delete a hidden ref by `git push` is
+       rejected.
+
+receive.updateServerInfo::
+       If set to true, git-receive-pack will run git-update-server-info
+       after receiving data from git-push and updating refs.
+
+receive.shallowUpdate::
+       If set to true, .git/shallow can be updated when new refs
+       require new shallow roots. Otherwise those refs are rejected.
diff --git a/Documentation/sendemail-config.txt b/Documentation/sendemail-config.txt
new file mode 100644 (file)
index 0000000..0006faf
--- /dev/null
@@ -0,0 +1,63 @@
+sendemail.identity::
+       A configuration identity. When given, causes values in the
+       'sendemail.<identity>' subsection to take precedence over
+       values in the 'sendemail' section. The default identity is
+       the value of `sendemail.identity`.
+
+sendemail.smtpEncryption::
+       See linkgit:git-send-email[1] for description.  Note that this
+       setting is not subject to the 'identity' mechanism.
+
+sendemail.smtpssl (deprecated)::
+       Deprecated alias for 'sendemail.smtpEncryption = ssl'.
+
+sendemail.smtpsslcertpath::
+       Path to ca-certificates (either a directory or a single file).
+       Set it to an empty string to disable certificate verification.
+
+sendemail.<identity>.*::
+       Identity-specific versions of the 'sendemail.*' parameters
+       found below, taking precedence over those when this
+       identity is selected, through either the command-line or
+       `sendemail.identity`.
+
+sendemail.aliasesFile::
+sendemail.aliasFileType::
+sendemail.annotate::
+sendemail.bcc::
+sendemail.cc::
+sendemail.ccCmd::
+sendemail.chainReplyTo::
+sendemail.confirm::
+sendemail.envelopeSender::
+sendemail.from::
+sendemail.multiEdit::
+sendemail.signedoffbycc::
+sendemail.smtpPass::
+sendemail.suppresscc::
+sendemail.suppressFrom::
+sendemail.to::
+sendemail.tocmd::
+sendemail.smtpDomain::
+sendemail.smtpServer::
+sendemail.smtpServerPort::
+sendemail.smtpServerOption::
+sendemail.smtpUser::
+sendemail.thread::
+sendemail.transferEncoding::
+sendemail.validate::
+sendemail.xmailer::
+       See linkgit:git-send-email[1] for description.
+
+sendemail.signedoffcc (deprecated)::
+       Deprecated alias for `sendemail.signedoffbycc`.
+
+sendemail.smtpBatchSize::
+       Number of messages to be sent per connection, after that a relogin
+       will happen.  If the value is 0 or undefined, send all messages in
+       one connection.
+       See also the `--batch-size` option of linkgit:git-send-email[1].
+
+sendemail.smtpReloginDelay::
+       Seconds wait before reconnecting to smtp server.
+       See also the `--relogin-delay` option of linkgit:git-send-email[1].
diff --git a/Documentation/submodule-config.txt b/Documentation/submodule-config.txt
new file mode 100644 (file)
index 0000000..0a1293b
--- /dev/null
@@ -0,0 +1,82 @@
+submodule.<name>.url::
+       The URL for a submodule. This variable is copied from the .gitmodules
+       file to the git config via 'git submodule init'. The user can change
+       the configured URL before obtaining the submodule via 'git submodule
+       update'. If neither submodule.<name>.active or submodule.active are
+       set, the presence of this variable is used as a fallback to indicate
+       whether the submodule is of interest to git commands.
+       See linkgit:git-submodule[1] and linkgit:gitmodules[5] for details.
+
+submodule.<name>.update::
+       The method by which a submodule is updated by 'git submodule update',
+       which is the only affected command, others such as
+       'git checkout --recurse-submodules' are unaffected. It exists for
+       historical reasons, when 'git submodule' was the only command to
+       interact with submodules; settings like `submodule.active`
+       and `pull.rebase` are more specific. It is populated by
+       `git submodule init` from the linkgit:gitmodules[5] file.
+       See description of 'update' command in linkgit:git-submodule[1].
+
+submodule.<name>.branch::
+       The remote branch name for a submodule, used by `git submodule
+       update --remote`.  Set this option to override the value found in
+       the `.gitmodules` file.  See linkgit:git-submodule[1] and
+       linkgit:gitmodules[5] for details.
+
+submodule.<name>.fetchRecurseSubmodules::
+       This option can be used to control recursive fetching of this
+       submodule. It can be overridden by using the --[no-]recurse-submodules
+       command-line option to "git fetch" and "git pull".
+       This setting will override that from in the linkgit:gitmodules[5]
+       file.
+
+submodule.<name>.ignore::
+       Defines under what circumstances "git status" and the diff family show
+       a submodule as modified. When set to "all", it will never be considered
+       modified (but it will nonetheless show up in the output of status and
+       commit when it has been staged), "dirty" will ignore all changes
+       to the submodules work tree and
+       takes only differences between the HEAD of the submodule and the commit
+       recorded in the superproject into account. "untracked" will additionally
+       let submodules with modified tracked files in their work tree show up.
+       Using "none" (the default when this option is not set) also shows
+       submodules that have untracked files in their work tree as changed.
+       This setting overrides any setting made in .gitmodules for this submodule,
+       both settings can be overridden on the command line by using the
+       "--ignore-submodules" option. The 'git submodule' commands are not
+       affected by this setting.
+
+submodule.<name>.active::
+       Boolean value indicating if the submodule is of interest to git
+       commands.  This config option takes precedence over the
+       submodule.active config option. See linkgit:gitsubmodules[7] for
+       details.
+
+submodule.active::
+       A repeated field which contains a pathspec used to match against a
+       submodule's path to determine if the submodule is of interest to git
+       commands. See linkgit:gitsubmodules[7] for details.
+
+submodule.recurse::
+       Specifies if commands recurse into submodules by default. This
+       applies to all commands that have a `--recurse-submodules` option,
+       except `clone`.
+       Defaults to false.
+
+submodule.fetchJobs::
+       Specifies how many submodules are fetched/cloned at the same time.
+       A positive integer allows up to that number of submodules fetched
+       in parallel. A value of 0 will give some reasonable default.
+       If unset, it defaults to 1.
+
+submodule.alternateLocation::
+       Specifies how the submodules obtain alternates when submodules are
+       cloned. Possible values are `no`, `superproject`.
+       By default `no` is assumed, which doesn't add references. When the
+       value is set to `superproject` the submodule to be cloned computes
+       its alternates location relative to the superprojects alternate.
+
+submodule.alternateErrorStrategy::
+       Specifies how to treat errors with the alternates for a submodule
+       as computed via `submodule.alternateLocation`. Possible values are
+       `ignore`, `info`, `die`. Default is `die`.
index 18142b6..d0d1707 100644 (file)
@@ -80,7 +80,7 @@ Calling sequence
   it is invoked.
 
 * For each commit, call `graph_next_line()` repeatedly, until
-  `graph_is_commit_finished()` returns non-zero.  Each call go
+  `graph_is_commit_finished()` returns non-zero.  Each call to
   `graph_next_line()` will output a single line of the graph.  The resulting
   lines will not contain any newlines.  `graph_next_line()` returns 1 if the
   resulting line contains the current commit, or 0 if this is merely a line
@@ -115,7 +115,6 @@ struct commit *commit;
 struct git_graph *graph = graph_init(opts);
 
 while ((commit = get_revision(opts)) != NULL) {
-       graph_update(graph, commit);
        while (!graph_is_commit_finished(graph))
        {
                struct strbuf sb;
index c664acb..7805b09 100644 (file)
@@ -15,13 +15,13 @@ There are two main costs here:
 1. Decompressing and parsing commits.
 2. Walking the entire graph to satisfy topological order constraints.
 
-The commit graph file is a supplemental data structure that accelerates
+The commit-graph file is a supplemental data structure that accelerates
 commit graph walks. If a user downgrades or disables the 'core.commitGraph'
 config setting, then the existing ODB is sufficient. The file is stored
 as "commit-graph" either in the .git/objects/info directory or in the info
 directory of an alternate.
 
-The commit graph file stores the commit graph structure along with some
+The commit-graph file stores the commit graph structure along with some
 extra metadata to speed up graph walks. By listing commit OIDs in lexi-
 cographic order, we can identify an integer position for each commit and
 refer to the parents of a commit using those integer positions. We use
@@ -103,7 +103,7 @@ that of a parent.
 Design Details
 --------------
 
-- The commit graph file is stored in a file named 'commit-graph' in the
+- The commit-graph file is stored in a file named 'commit-graph' in the
   .git/objects/info directory. This could be stored in the info directory
   of an alternate.
 
@@ -112,12 +112,24 @@ Design Details
 - The file format includes parameters for the object ID hash function,
   so a future change of hash algorithm does not require a change in format.
 
+- Commit grafts and replace objects can change the shape of the commit
+  history. The latter can also be enabled/disabled on the fly using
+  `--no-replace-objects`. This leads to difficultly storing both possible
+  interpretations of a commit id, especially when computing generation
+  numbers. The commit-graph will not be read or written when
+  replace-objects or grafts are present.
+
+- Shallow clones create grafts of commits by dropping their parents. This
+  leads the commit-graph to think those commits have generation number 1.
+  If and when those commits are made unshallow, those generation numbers
+  become invalid. Since shallow clones are intended to restrict the commit
+  history to a very small set of commits, the commit-graph feature is less
+  helpful for these clones, anyway. The commit-graph will not be read or
+  written when shallow commits are present.
+
 Future Work
 -----------
 
-- The commit graph feature currently does not honor commit grafts. This can
-  be remedied by duplicating or refactoring the current graft logic.
-
 - After computing and storing generation numbers, we must make graph
   walks aware of generation numbers to gain the performance benefits they
   enable. This will mostly be accomplished by swapping a commit-date-ordered
@@ -127,7 +139,7 @@ Future Work
     - 'log --topo-order'
     - 'tag --merged'
 
-- A server could provide a commit graph file as part of the network protocol
+- A server could provide a commit-graph file as part of the network protocol
   to avoid extra calculations by clients. This feature is only of benefit if
   the user is willing to trust the file, because verifying the file is correct
   is as hard as computing it from scratch.
index 13e1c52..5bf1af3 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -709,7 +709,9 @@ TEST_BUILTINS_OBJS += test-date.o
 TEST_BUILTINS_OBJS += test-delta.o
 TEST_BUILTINS_OBJS += test-drop-caches.o
 TEST_BUILTINS_OBJS += test-dump-cache-tree.o
+TEST_BUILTINS_OBJS += test-dump-fsmonitor.o
 TEST_BUILTINS_OBJS += test-dump-split-index.o
+TEST_BUILTINS_OBJS += test-dump-untracked-cache.o
 TEST_BUILTINS_OBJS += test-example-decorate.o
 TEST_BUILTINS_OBJS += test-genrandom.o
 TEST_BUILTINS_OBJS += test-hashmap.o
@@ -720,7 +722,9 @@ TEST_BUILTINS_OBJS += test-match-trees.o
 TEST_BUILTINS_OBJS += test-mergesort.o
 TEST_BUILTINS_OBJS += test-mktemp.o
 TEST_BUILTINS_OBJS += test-online-cpus.o
+TEST_BUILTINS_OBJS += test-parse-options.o
 TEST_BUILTINS_OBJS += test-path-utils.o
+TEST_BUILTINS_OBJS += test-pkt-line.o
 TEST_BUILTINS_OBJS += test-prio-queue.o
 TEST_BUILTINS_OBJS += test-reach.o
 TEST_BUILTINS_OBJS += test-read-cache.o
@@ -731,8 +735,8 @@ TEST_BUILTINS_OBJS += test-repository.o
 TEST_BUILTINS_OBJS += test-revision-walking.o
 TEST_BUILTINS_OBJS += test-run-command.o
 TEST_BUILTINS_OBJS += test-scrap-cache-tree.o
-TEST_BUILTINS_OBJS += test-sha1-array.o
 TEST_BUILTINS_OBJS += test-sha1.o
+TEST_BUILTINS_OBJS += test-sha1-array.o
 TEST_BUILTINS_OBJS += test-sigchain.o
 TEST_BUILTINS_OBJS += test-strcmp-offset.o
 TEST_BUILTINS_OBJS += test-string-list.o
@@ -743,12 +747,10 @@ TEST_BUILTINS_OBJS += test-wildmatch.o
 TEST_BUILTINS_OBJS += test-windows-named-pipe.o
 TEST_BUILTINS_OBJS += test-write-cache.o
 
-TEST_PROGRAMS_NEED_X += test-dump-fsmonitor
-TEST_PROGRAMS_NEED_X += test-dump-untracked-cache
+# Do not add more tests here unless they have extra dependencies. Add
+# them in TEST_BUILTINS_OBJS above.
 TEST_PROGRAMS_NEED_X += test-fake-ssh
 TEST_PROGRAMS_NEED_X += test-line-buffer
-TEST_PROGRAMS_NEED_X += test-parse-options
-TEST_PROGRAMS_NEED_X += test-pkt-line
 TEST_PROGRAMS_NEED_X += test-svn-fe
 TEST_PROGRAMS_NEED_X += test-tool
 
@@ -1794,6 +1796,7 @@ ifndef V
        QUIET_MSGFMT   = @echo '   ' MSGFMT $@;
        QUIET_GCOV     = @echo '   ' GCOV $@;
        QUIET_SP       = @echo '   ' SP $<;
+       QUIET_HDR      = @echo '   ' HDR $<;
        QUIET_RC       = @echo '   ' RC $@;
        QUIET_SUBDIR0  = +@subdir=
        QUIET_SUBDIR1  = ;$(NO_SUBDIR) echo '   ' SUBDIR $$subdir; \
@@ -2676,6 +2679,17 @@ $(SP_OBJ): %.sp: %.c GIT-CFLAGS FORCE
 .PHONY: sparse $(SP_OBJ)
 sparse: $(SP_OBJ)
 
+GEN_HDRS := command-list.h unicode-width.h
+EXCEPT_HDRS := $(GEN_HDRS) compat% xdiff%
+CHK_HDRS = $(filter-out $(EXCEPT_HDRS),$(patsubst ./%,%,$(LIB_H)))
+HCO = $(patsubst %.h,%.hco,$(CHK_HDRS))
+
+$(HCO): %.hco: %.h FORCE
+       $(QUIET_HDR)$(CC) -include git-compat-util.h -I. -o /dev/null -c -xc $<
+
+.PHONY: hdr-check $(HCO)
+hdr-check: $(HCO)
+
 .PHONY: style
 style:
        git clang-format --style file --diff --extensions c,h
deleted file mode 100644 (file)
index 007bc065dd88d6fbbde553c550c58b363fc29c40..0000000000000000000000000000000000000000
--- a/RelNotes
+++ /dev/null
@@ -1,167 +0,0 @@
-Git Release Notes
-=================
-
-Backward Compatibility Notes
-----------------------------
-
- * "git branch -l <foo>" used to be a way to ask a reflog to be
-   created while creating a new branch, but that is no longer the
-   case.  It is a short-hand for "git branch --list <foo>" now.
-
- * "git push" into refs/tags/* hierarchy is rejected without getting
-   forced, but "git fetch" (misguidedly) used the "fast forwarding"
-   rule used for the refs/heads/* hierarchy; this has been corrected,
-   which means some fetches of tags that did not fail with older
-   version of Git will fail without "--force" with this version.
-
-
-Updates since v2.19
--------------------
-
-UI, Workflows & Features
-
- * Running "git clone" against a project that contain two files with
-   pathnames that differ only in cases on a case insensitive
-   filesystem would result in one of the files lost because the
-   underlying filesystem is incapable of holding both at the same
-   time.  An attempt is made to detect such a case and warn.
-
- * "git checkout -b newbranch [HEAD]" should not have to do as much as
-   checking out a commit different from HEAD.  An attempt is made to
-   optimize this special case.
-
- * "git rev-list --stdin </dev/null" used to be an error; it now shows
-   no output without an error.  "git rev-list --stdin --default HEAD"
-   still falls back to the given default when nothing is given on the
-   standard input.
-
- * Lift code from GitHub to restrict delta computation so that an
-   object that exists in one fork is not made into a delta against
-   another object that does not appear in the same forked repository.
-
- * "git format-patch" learned new "--interdiff" and "--range-diff"
-   options to explain the difference between this version and the
-   previous attempt in the cover letter (or after the tree-dashes as
-   a comment).
-
- * "git mailinfo" used in "git am" learned to make a best-effort
-   recovery of a patch corrupted by MUA that sends text/plain with
-   format=flawed option.
-   (merge 3aa4d81f88 rs/mailinfo-format-flowed later to maint).
-
- * The rules used by "git push" and "git fetch" to determine if a ref
-   can or cannot be updated were inconsistent; specifically, fetching
-   to update existing tags were allowed even though tags are supposed
-   to be unmoving anchoring points.  "git fetch" was taught to forbid
-   updates to existing tags without the "--force" option.
-
-
-Performance, Internal Implementation, Development Support etc.
-
- * When there are too many packfiles in a repository (which is not
-   recommended), looking up an object in these would require
-   consulting many pack .idx files; a new mechanism to have a single
-   file that consolidates all of these .idx files is introduced.
-
- * "git submodule update" is getting rewritten piece-by-piece into C.
-
- * The code for computing history reachability has been shuffled,
-   obtained a bunch of new tests to cover them, and then being
-   improved.
-
- * The unpack_trees() API used in checking out a branch and merging
-   walks one or more trees along with the index.  When the cache-tree
-   in the index tells us that we are walking a tree whose flattened
-   contents is known (i.e. matches a span in the index), as linearly
-   scanning a span in the index is much more efficient than having to
-   open tree objects recursively and listing their entries, the walk
-   can be optimized, which has been done.
-
- * When creating a thin pack, which allows objects to be made into a
-   delta against another object that is not in the resulting pack but
-   is known to be present on the receiving end, the code learned to
-   take advantage of the reachability bitmap; this allows the server
-   to send a delta against a base beyond the "boundary" commit.
-
- * spatch transformation to replace boolean uses of !hashcmp() to
-   newly introduced oideq() is added, and applied, to regain
-   performance lost due to support of multiple hash algorithms.
-
- * Fix a bug in which the same path could be registered under multiple
-   worktree entries if the path was missing (for instance, was removed
-   manually).  Also, as a convenience, expand the number of cases in
-   which --force is applicable.
-
-
-Fixes since v2.19
------------------
-
- * "git interpret-trailers" and its underlying machinery had a buggy
-   code that attempted to ignore patch text after commit log message,
-   which triggered in various codepaths that will always get the log
-   message alone and never get such an input.
-   (merge 66e83d9b41 jk/trailer-fixes later to maint).
-
- * Malformed or crafted data in packstream can make our code attempt
-   to read or write past the allocated buffer and abort, instead of
-   reporting an error, which has been fixed.
-
- * "git rebase -i" did not clear the state files correctly when a run
-   of "squash/fixup" is aborted and then the user manually amended the
-   commit instead, which has been corrected.
-   (merge 10d2f35436 js/rebase-i-autosquash-fix later to maint).
-
- * When fsmonitor is in use, after operation on submodules updates
-   .gitmodules, we lost track of the fact that we did so and relied on
-   stale fsmonitor data.
-   (merge 43f1180814 bp/mv-submodules-with-fsmonitor later to maint).
-
- * Fix for a long-standing bug that leaves the index file corrupt when
-   it shrinks during a partial commit.
-   (merge 6c003d6ffb jk/reopen-tempfile-truncate later to maint).
-
- * Further fix for O_APPEND emulation on Windows
-   (merge eeaf7ddac7 js/mingw-o-append later to maint).
-
- * A corner case bugfix in "git rerere" code.
-   (merge ad2bf0d9b4 en/rerere-multi-stage-1-fix later to maint).
-
- * "git add ':(attr:foo)'" is not supported and is supposed to be
-   rejected while the command line arguments are parsed, but we fail
-   to reject such a command line upfront.
-   (merge 84d938b732 nd/attr-pathspec-fix later to maint).
-
- * Recent update broke the reachability algorithm when refs (e.g.
-   tags) that point at objects that are not commit were involved,
-   which has been fixed.
-
- * "git rebase" etc. in Git 2.19 fails to abort when given an empty
-   commit log message as result of editing, which has been corrected.
-   (merge a3ec9eaf38 en/sequencer-empty-edit-result-aborts later to maint).
-
- * The code to backfill objects in lazily cloned repository did not
-   work correctly, which has been corrected.
-   (merge e68302011c jt/lazy-object-fetch-fix later to maint).
-
- * Update error messages given by "git remote" and make them consistent.
-   (merge 5025425dff ms/remote-error-message-update later to maint).
-
- * "git update-ref" learned to make both "--no-deref" and "--stdin"
-   work at the same time.
-   (merge d345e9fbe7 en/update-ref-no-deref-stdin later to maint).
-
- * Recently added "range-diff" had a corner-case bug to cause it
-   segfault, which has been corrected.
-   (merge e467a90c7a tg/range-diff-corner-case-fix later to maint).
-
- * Code cleanup, docfix, build fix, etc.
-   (merge 96a7501aad ts/doc-build-manpage-xsl-quietly later to maint).
-   (merge b9b07efdb2 tg/conflict-marker-size later to maint).
-   (merge fa0aeea770 sg/doc-trace-appends later to maint).
-   (merge d64324cb60 tb/void-check-attr later to maint).
-   (merge c3b9bc94b9 en/double-semicolon-fix later to maint).
-   (merge 79336116f5 sg/t3701-tighten-trace later to maint).
-   (merge 801fa63a90 jk/dev-build-format-security later to maint).
-   (merge 0597dd62ba sb/string-list-remove-unused later to maint).
-   (merge db2d36fad8 bw/protocol-v2 later to maint).
-   (merge 456d7cd3a9 sg/split-index-test later to maint).
new file mode 120000 (symlink)
index 0000000000000000000000000000000000000000..8d0b1654d25536f72abe885634c36412ae8b3246
--- /dev/null
+++ b/RelNotes
@@ -0,0 +1 @@
+Documentation/RelNotes/2.20.0.txt
\ No newline at end of file
index b30b487..902c067 100644 (file)
@@ -497,7 +497,8 @@ static int skip_merge_working_tree(const struct checkout_opts *opts,
         * We must do the merge if we are actually moving to a new commit.
         */
        if (!old_branch_info->commit || !new_branch_info->commit ||
-               oidcmp(&old_branch_info->commit->object.oid, &new_branch_info->commit->object.oid))
+               !oideq(&old_branch_info->commit->object.oid,
+                      &new_branch_info->commit->object.oid))
                return 0;
 
        /*
index 0bf0c48..22b974f 100644 (file)
@@ -120,6 +120,8 @@ static int graph_read(int argc, const char **argv)
        return 0;
 }
 
+extern int read_replace_refs;
+
 static int graph_write(int argc, const char **argv)
 {
        struct string_list *pack_indexes = NULL;
@@ -150,8 +152,10 @@ static int graph_write(int argc, const char **argv)
        if (!opts.obj_dir)
                opts.obj_dir = get_object_directory();
 
+       read_replace_refs = 0;
+
        if (opts.reachable) {
-               write_commit_graph_reachable(opts.obj_dir, opts.append);
+               write_commit_graph_reachable(opts.obj_dir, opts.append, 1);
                return 0;
        }
 
@@ -171,7 +175,8 @@ static int graph_write(int argc, const char **argv)
        write_commit_graph(opts.obj_dir,
                           pack_indexes,
                           commit_hex,
-                          opts.append);
+                          opts.append,
+                          1);
 
        string_list_clear(&lines, 0);
        return 0;
index b57d8e4..1d5292e 100644 (file)
@@ -874,6 +874,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
                s->use_color = 0;
                commitable = run_status(s->fp, index_file, prefix, 1, s);
                s->use_color = saved_color_setting;
+               string_list_clear(&s->change, 1);
        } else {
                struct object_id oid;
                const char *parent = "HEAD";
@@ -1654,7 +1655,7 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
                      "not exceeded, and then \"git reset HEAD\" to recover."));
 
        if (git_env_bool(GIT_TEST_COMMIT_GRAPH, 0))
-               write_commit_graph_reachable(get_object_directory(), 0);
+               write_commit_graph_reachable(get_object_directory(), 0, 0);
 
        rerere(0);
        run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
index 63c8578..06eb421 100644 (file)
@@ -848,5 +848,23 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
                }
        }
 
+       if (!git_config_get_bool("core.multipackindex", &i) && i) {
+               struct child_process midx_verify = CHILD_PROCESS_INIT;
+               const char *midx_argv[] = { "multi-pack-index", "verify", NULL, NULL, NULL };
+
+               midx_verify.argv = midx_argv;
+               midx_verify.git_cmd = 1;
+               if (run_command(&midx_verify))
+                       errors_found |= ERROR_COMMIT_GRAPH;
+
+               prepare_alt_odb(the_repository);
+               for (alt =  the_repository->objects->alt_odb_list; alt; alt = alt->next) {
+                       midx_argv[2] = "--object-dir";
+                       midx_argv[3] = alt->path;
+                       if (run_command(&midx_verify))
+                               errors_found |= ERROR_COMMIT_GRAPH;
+               }
+       }
+
        return errors_found;
 }
index 2b59226..871a56f 100644 (file)
@@ -441,10 +441,16 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
        return NULL;
 }
 
+/*
+ * Returns 0 if there was no previous error and gc can proceed, 1 if
+ * gc should not proceed due to an error in the last run. Prints a
+ * message and returns -1 if an error occured while reading gc.log
+ */
 static int report_last_gc_error(void)
 {
        struct strbuf sb = STRBUF_INIT;
        int ret = 0;
+       ssize_t len;
        struct stat st;
        char *gc_log_path = git_pathdup("gc.log");
 
@@ -452,39 +458,47 @@ static int report_last_gc_error(void)
                if (errno == ENOENT)
                        goto done;
 
-               ret = error_errno(_("Can't stat %s"), gc_log_path);
+               ret = error_errno(_("cannot stat '%s'"), gc_log_path);
                goto done;
        }
 
        if (st.st_mtime < gc_log_expire_time)
                goto done;
 
-       ret = strbuf_read_file(&sb, gc_log_path, 0);
-       if (ret > 0)
-               ret = error(_("The last gc run reported the following. "
+       len = strbuf_read_file(&sb, gc_log_path, 0);
+       if (len < 0)
+               ret = error_errno(_("cannot read '%s'"), gc_log_path);
+       else if (len > 0) {
+               /*
+                * A previous gc failed.  Report the error, and don't
+                * bother with an automatic gc run since it is likely
+                * to fail in the same way.
+                */
+               warning(_("The last gc run reported the following. "
                               "Please correct the root cause\n"
                               "and remove %s.\n"
                               "Automatic cleanup will not be performed "
                               "until the file is removed.\n\n"
                               "%s"),
                            gc_log_path, sb.buf);
+               ret = 1;
+       }
        strbuf_release(&sb);
 done:
        free(gc_log_path);
        return ret;
 }
 
-static int gc_before_repack(void)
+static void gc_before_repack(void)
 {
        if (pack_refs && run_command_v_opt(pack_refs_cmd.argv, RUN_GIT_CMD))
-               return error(FAILED_RUN, pack_refs_cmd.argv[0]);
+               die(FAILED_RUN, pack_refs_cmd.argv[0]);
 
        if (prune_reflogs && run_command_v_opt(reflog.argv, RUN_GIT_CMD))
-               return error(FAILED_RUN, reflog.argv[0]);
+               die(FAILED_RUN, reflog.argv[0]);
 
        pack_refs = 0;
        prune_reflogs = 0;
-       return 0;
 }
 
 int cmd_gc(int argc, const char **argv, const char *prefix)
@@ -565,13 +579,17 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
                        fprintf(stderr, _("See \"git help gc\" for manual housekeeping.\n"));
                }
                if (detach_auto) {
-                       if (report_last_gc_error())
-                               return -1;
+                       int ret = report_last_gc_error();
+                       if (ret < 0)
+                               /* an I/O error occured, already reported */
+                               exit(128);
+                       if (ret == 1)
+                               /* Last gc --auto failed. Skip this one. */
+                               return 0;
 
                        if (lock_repo_for_gc(force, &pid))
                                return 0;
-                       if (gc_before_repack())
-                               return -1;
+                       gc_before_repack(); /* dies on failure */
                        delete_tempfile(&pidfile);
 
                        /*
@@ -611,13 +629,12 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
                atexit(process_log_file_at_exit);
        }
 
-       if (gc_before_repack())
-               return -1;
+       gc_before_repack();
 
        if (!repository_format_precious_objects) {
                close_all_packs(the_repository->objects);
                if (run_command_v_opt(repack.argv, RUN_GIT_CMD))
-                       return error(FAILED_RUN, repack.argv[0]);
+                       die(FAILED_RUN, repack.argv[0]);
 
                if (prune_expire) {
                        argv_array_push(&prune, prune_expire);
@@ -627,18 +644,18 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
                                argv_array_push(&prune,
                                                "--exclude-promisor-objects");
                        if (run_command_v_opt(prune.argv, RUN_GIT_CMD))
-                               return error(FAILED_RUN, prune.argv[0]);
+                               die(FAILED_RUN, prune.argv[0]);
                }
        }
 
        if (prune_worktrees_expire) {
                argv_array_push(&prune_worktrees, prune_worktrees_expire);
                if (run_command_v_opt(prune_worktrees.argv, RUN_GIT_CMD))
-                       return error(FAILED_RUN, prune_worktrees.argv[0]);
+                       die(FAILED_RUN, prune_worktrees.argv[0]);
        }
 
        if (run_command_v_opt(rerere.argv, RUN_GIT_CMD))
-               return error(FAILED_RUN, rerere.argv[0]);
+               die(FAILED_RUN, rerere.argv[0]);
 
        report_garbage = report_pack_garbage;
        reprepare_packed_git(the_repository);
@@ -646,7 +663,8 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
                clean_pack_garbage();
 
        if (gc_write_commit_graph)
-               write_commit_graph_reachable(get_object_directory(), 0);
+               write_commit_graph_reachable(get_object_directory(), 0,
+                                            !quiet && !daemonized);
 
        if (auto_gc && too_many_loose_objects())
                warning(_("There are too many unreachable loose objects; "
index 2633efd..fca70f8 100644 (file)
@@ -5,7 +5,7 @@
 #include "midx.h"
 
 static char const * const builtin_multi_pack_index_usage[] = {
-       N_("git multi-pack-index [--object-dir=<dir>] write"),
+       N_("git multi-pack-index [--object-dir=<dir>] (write|verify)"),
        NULL
 };
 
@@ -42,6 +42,8 @@ int cmd_multi_pack_index(int argc, const char **argv,
 
        if (!strcmp(argv[0], "write"))
                return write_midx_file(opts.object_dir);
+       if (!strcmp(argv[0], "verify"))
+               return verify_midx_file(opts.object_dir);
 
        die(_("unrecognized verb: %s"), argv[0]);
 }
index e6316d2..c6370f2 100644 (file)
@@ -1469,6 +1469,57 @@ static void cleanup_preferred_base(void)
        done_pbase_paths_num = done_pbase_paths_alloc = 0;
 }
 
+/*
+ * Return 1 iff the object specified by "delta" can be sent
+ * literally as a delta against the base in "base_sha1". If
+ * so, then *base_out will point to the entry in our packing
+ * list, or NULL if we must use the external-base list.
+ *
+ * Depth value does not matter - find_deltas() will
+ * never consider reused delta as the base object to
+ * deltify other objects against, in order to avoid
+ * circular deltas.
+ */
+static int can_reuse_delta(const unsigned char *base_sha1,
+                          struct object_entry *delta,
+                          struct object_entry **base_out)
+{
+       struct object_entry *base;
+
+       if (!base_sha1)
+               return 0;
+
+       /*
+        * First see if we're already sending the base (or it's explicitly in
+        * our "excluded" list).
+        */
+       base = packlist_find(&to_pack, base_sha1, NULL);
+       if (base) {
+               if (!in_same_island(&delta->idx.oid, &base->idx.oid))
+                       return 0;
+               *base_out = base;
+               return 1;
+       }
+
+       /*
+        * Otherwise, reachability bitmaps may tell us if the receiver has it,
+        * even if it was buried too deep in history to make it into the
+        * packing list.
+        */
+       if (thin && bitmap_has_sha1_in_uninteresting(bitmap_git, base_sha1)) {
+               if (use_delta_islands) {
+                       struct object_id base_oid;
+                       hashcpy(base_oid.hash, base_sha1);
+                       if (!in_same_island(&delta->idx.oid, &base_oid))
+                               return 0;
+               }
+               *base_out = NULL;
+               return 1;
+       }
+
+       return 0;
+}
+
 static void check_object(struct object_entry *entry)
 {
        unsigned long canonical_size;
@@ -1555,22 +1606,7 @@ static void check_object(struct object_entry *entry)
                        break;
                }
 
-               if (base_ref && (
-                   (base_entry = packlist_find(&to_pack, base_ref, NULL)) ||
-                   (thin &&
-                    bitmap_has_sha1_in_uninteresting(bitmap_git, base_ref))) &&
-                   in_same_island(&entry->idx.oid, &base_entry->idx.oid)) {
-                       /*
-                        * If base_ref was set above that means we wish to
-                        * reuse delta data, and either we found that object in
-                        * the list of objects we want to pack, or it's one we
-                        * know the receiver has.
-                        *
-                        * Depth value does not matter - find_deltas() will
-                        * never consider reused delta as the base object to
-                        * deltify other objects against, in order to avoid
-                        * circular deltas.
-                        */
+               if (can_reuse_delta(base_ref, entry, &base_entry)) {
                        oe_set_type(entry, entry->in_pack_type);
                        SET_SIZE(entry, in_pack_size); /* delta size */
                        SET_DELTA_SIZE(entry, in_pack_size);
index 4d30001..95740f4 100644 (file)
@@ -1834,7 +1834,7 @@ static void prepare_shallow_update(struct command *commands,
        /*
         * keep hooks happy by forcing a temporary shallow file via
         * env variable because we can't add --shallow-file to every
-        * command. check_everything_connected() will be done with
+        * command. check_connected() will be done with
         * true .git/shallow though.
         */
        setenv(GIT_SHALLOW_FILE_ENVIRONMENT, alt_shallow_file, 1);
index 8e67e09..30a661e 100644 (file)
@@ -39,7 +39,8 @@ struct show_data {
        enum replace_format format;
 };
 
-static int show_reference(const char *refname, const struct object_id *oid,
+static int show_reference(struct repository *r, const char *refname,
+                         const struct object_id *oid,
                          int flag, void *cb_data)
 {
        struct show_data *data = cb_data;
@@ -56,9 +57,8 @@ static int show_reference(const char *refname, const struct object_id *oid,
                        if (get_oid(refname, &object))
                                return error(_("failed to resolve '%s' as a valid ref"), refname);
 
-                       obj_type = oid_object_info(the_repository, &object,
-                                                  NULL);
-                       repl_type = oid_object_info(the_repository, oid, NULL);
+                       obj_type = oid_object_info(r, &object, NULL);
+                       repl_type = oid_object_info(r, oid, NULL);
 
                        printf("%s (%s) -> %s (%s)\n", refname, type_name(obj_type),
                               oid_to_hex(oid), type_name(repl_type));
index 5ce5146..9c5cf2c 100644 (file)
@@ -781,7 +781,7 @@ static void verify_one(struct index_state *istate,
                strbuf_add(&tree_buf, oid->hash, the_hash_algo->rawsz);
        }
        hash_object_file(tree_buf.buf, tree_buf.len, tree_type, &new_oid);
-       if (oidcmp(&new_oid, &it->oid))
+       if (!oideq(&new_oid, &it->oid))
                BUG("cache-tree for path %.*s does not match. "
                    "Expected %s got %s", len, path->buf,
                    oid_to_hex(&new_oid), oid_to_hex(&it->oid));
index 7f4519e..a686758 100644 (file)
@@ -13,6 +13,9 @@
 #include "commit-graph.h"
 #include "object-store.h"
 #include "alloc.h"
+#include "hashmap.h"
+#include "replace-object.h"
+#include "progress.h"
 
 #define GRAPH_SIGNATURE 0x43475048 /* "CGPH" */
 #define GRAPH_CHUNKID_OIDFANOUT 0x4f494446 /* "OIDF" */
@@ -56,6 +59,28 @@ static struct commit_graph *alloc_commit_graph(void)
        return g;
 }
 
+extern int read_replace_refs;
+
+static int commit_graph_compatible(struct repository *r)
+{
+       if (!r->gitdir)
+               return 0;
+
+       if (read_replace_refs) {
+               prepare_replace_object(r);
+               if (hashmap_get_size(&r->objects->replace_map->map))
+                       return 0;
+       }
+
+       prepare_commit_graft(r);
+       if (r->parsed_objects && r->parsed_objects->grafts_nr)
+               return 0;
+       if (is_repository_shallow(r))
+               return 0;
+
+       return 1;
+}
+
 struct commit_graph *load_commit_graph_one(const char *graph_file)
 {
        void *graph_map;
@@ -224,6 +249,9 @@ static int prepare_commit_graph(struct repository *r)
                 */
                return 0;
 
+       if (!commit_graph_compatible(r))
+               return 0;
+
        obj_dir = r->objects->objectdir;
        prepare_commit_graph_one(r, obj_dir);
        prepare_alt_odb(r);
@@ -252,10 +280,10 @@ int generation_numbers_enabled(struct repository *r)
        return !!first_generation;
 }
 
-static void close_commit_graph(void)
+void close_commit_graph(struct repository *r)
 {
-       free_commit_graph(the_repository->objects->commit_graph);
-       the_repository->objects->commit_graph = NULL;
+       free_commit_graph(r->objects->commit_graph);
+       r->objects->commit_graph = NULL;
 }
 
 static int bsearch_graph(struct commit_graph *g, struct object_id *oid, uint32_t *pos)
@@ -567,6 +595,8 @@ struct packed_oid_list {
        struct object_id *list;
        int nr;
        int alloc;
+       struct progress *progress;
+       int progress_done;
 };
 
 static int add_packed_commits(const struct object_id *oid,
@@ -579,6 +609,9 @@ static int add_packed_commits(const struct object_id *oid,
        off_t offset = nth_packed_object_offset(pack, pos);
        struct object_info oi = OBJECT_INFO_INIT;
 
+       if (list->progress)
+               display_progress(list->progress, ++list->progress_done);
+
        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));
@@ -606,12 +639,18 @@ static void add_missing_parents(struct packed_oid_list *oids, struct commit *com
        }
 }
 
-static void close_reachable(struct packed_oid_list *oids)
+static void close_reachable(struct packed_oid_list *oids, int report_progress)
 {
        int i;
        struct commit *commit;
+       struct progress *progress = NULL;
+       int j = 0;
 
+       if (report_progress)
+               progress = start_delayed_progress(
+                       _("Annotating commits in commit graph"), 0);
        for (i = 0; i < oids->nr; i++) {
+               display_progress(progress, ++j);
                commit = lookup_commit(the_repository, &oids->list[i]);
                if (commit)
                        commit->object.flags |= UNINTERESTING;
@@ -623,6 +662,7 @@ static void close_reachable(struct packed_oid_list *oids)
         * closure.
         */
        for (i = 0; i < oids->nr; i++) {
+               display_progress(progress, ++j);
                commit = lookup_commit(the_repository, &oids->list[i]);
 
                if (commit && !parse_commit(commit))
@@ -630,19 +670,28 @@ static void close_reachable(struct packed_oid_list *oids)
        }
 
        for (i = 0; i < oids->nr; i++) {
+               display_progress(progress, ++j);
                commit = lookup_commit(the_repository, &oids->list[i]);
 
                if (commit)
                        commit->object.flags &= ~UNINTERESTING;
        }
+       stop_progress(&progress);
 }
 
-static void compute_generation_numbers(struct packed_commit_list* commits)
+static void compute_generation_numbers(struct packed_commit_list* commits,
+                                      int report_progress)
 {
        int i;
        struct commit_list *list = NULL;
+       struct progress *progress = NULL;
 
+       if (report_progress)
+               progress = start_progress(
+                       _("Computing commit graph generation numbers"),
+                       commits->nr);
        for (i = 0; i < commits->nr; i++) {
+               display_progress(progress, i + 1);
                if (commits->list[i]->generation != GENERATION_NUMBER_INFINITY &&
                    commits->list[i]->generation != GENERATION_NUMBER_ZERO)
                        continue;
@@ -674,6 +723,7 @@ static void compute_generation_numbers(struct packed_commit_list* commits)
                        }
                }
        }
+       stop_progress(&progress);
 }
 
 static int add_ref_to_list(const char *refname,
@@ -686,19 +736,20 @@ static int add_ref_to_list(const char *refname,
        return 0;
 }
 
-void write_commit_graph_reachable(const char *obj_dir, int append)
+void write_commit_graph_reachable(const char *obj_dir, int append,
+                                 int report_progress)
 {
        struct string_list list;
 
        string_list_init(&list, 1);
        for_each_ref(add_ref_to_list, &list);
-       write_commit_graph(obj_dir, NULL, &list, append);
+       write_commit_graph(obj_dir, NULL, &list, append, report_progress);
 }
 
 void write_commit_graph(const char *obj_dir,
                        struct string_list *pack_indexes,
                        struct string_list *commit_hex,
-                       int append)
+                       int append, int report_progress)
 {
        struct packed_oid_list oids;
        struct packed_commit_list commits;
@@ -711,9 +762,15 @@ void write_commit_graph(const char *obj_dir,
        int num_chunks;
        int num_extra_edges;
        struct commit_list *parent;
+       struct progress *progress = NULL;
+
+       if (!commit_graph_compatible(the_repository))
+               return;
 
        oids.nr = 0;
        oids.alloc = approximate_object_count() / 4;
+       oids.progress = NULL;
+       oids.progress_done = 0;
 
        if (append) {
                prepare_commit_graph_one(the_repository, obj_dir);
@@ -740,6 +797,11 @@ void write_commit_graph(const char *obj_dir,
                int dirlen;
                strbuf_addf(&packname, "%s/pack/", obj_dir);
                dirlen = packname.len;
+               if (report_progress) {
+                       oids.progress = start_delayed_progress(
+                               _("Finding commits for commit graph"), 0);
+                       oids.progress_done = 0;
+               }
                for (i = 0; i < pack_indexes->nr; i++) {
                        struct packed_git *p;
                        strbuf_setlen(&packname, dirlen);
@@ -752,15 +814,21 @@ void write_commit_graph(const char *obj_dir,
                        for_each_object_in_pack(p, add_packed_commits, &oids, 0);
                        close_pack(p);
                }
+               stop_progress(&oids.progress);
                strbuf_release(&packname);
        }
 
        if (commit_hex) {
+               if (report_progress)
+                       progress = start_delayed_progress(
+                               _("Finding commits for commit graph"),
+                               commit_hex->nr);
                for (i = 0; i < commit_hex->nr; i++) {
                        const char *end;
                        struct object_id oid;
                        struct commit *result;
 
+                       display_progress(progress, i + 1);
                        if (commit_hex->items[i].string &&
                            parse_oid_hex(commit_hex->items[i].string, &oid, &end))
                                continue;
@@ -773,12 +841,18 @@ void write_commit_graph(const char *obj_dir,
                                oids.nr++;
                        }
                }
+               stop_progress(&progress);
        }
 
-       if (!pack_indexes && !commit_hex)
+       if (!pack_indexes && !commit_hex) {
+               if (report_progress)
+                       oids.progress = start_delayed_progress(
+                               _("Finding commits for commit graph"), 0);
                for_each_packed_object(add_packed_commits, &oids, 0);
+               stop_progress(&oids.progress);
+       }
 
-       close_reachable(&oids);
+       close_reachable(&oids, report_progress);
 
        QSORT(oids.list, oids.nr, commit_compare);
 
@@ -818,7 +892,7 @@ void write_commit_graph(const char *obj_dir,
        if (commits.nr >= GRAPH_PARENT_MISSING)
                die(_("too many commits to write graph"));
 
-       compute_generation_numbers(&commits);
+       compute_generation_numbers(&commits, report_progress);
 
        graph_name = get_commit_graph_filename(obj_dir);
        if (safe_create_leading_directories(graph_name))
@@ -864,7 +938,7 @@ void write_commit_graph(const char *obj_dir,
        write_graph_chunk_data(f, GRAPH_OID_LEN, commits.list, commits.nr);
        write_graph_chunk_large_edges(f, commits.list, commits.nr);
 
-       close_commit_graph();
+       close_commit_graph(the_repository);
        finalize_hashfile(f, NULL, CSUM_HASH_IN_STREAM | CSUM_FSYNC);
        commit_lock_file(&lk);
 
@@ -897,6 +971,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
        int generation_zero = 0;
        struct hashfile *f;
        int devnull;
+       struct progress *progress = NULL;
 
        if (!g) {
                graph_report("no commit-graph file loaded");
@@ -964,11 +1039,14 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
        if (verify_commit_graph_error & ~VERIFY_COMMIT_GRAPH_ERROR_HASH)
                return verify_commit_graph_error;
 
+       progress = start_progress(_("Verifying commits in commit graph"),
+                                 g->num_commits);
        for (i = 0; i < g->num_commits; i++) {
                struct commit *graph_commit, *odb_commit;
                struct commit_list *graph_parents, *odb_parents;
                uint32_t max_generation = 0;
 
+               display_progress(progress, i + 1);
                hashcpy(cur_oid.hash, g->chunk_oid_lookup + g->hash_len * i);
 
                graph_commit = lookup_commit(r, &cur_oid);
@@ -1045,6 +1123,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g)
                                     graph_commit->date,
                                     odb_commit->date);
        }
+       stop_progress(&progress);
 
        return verify_commit_graph_error;
 }
index b050476..9db40b4 100644 (file)
@@ -60,14 +60,16 @@ struct commit_graph *load_commit_graph_one(const char *graph_file);
  */
 int generation_numbers_enabled(struct repository *r);
 
-void write_commit_graph_reachable(const char *obj_dir, int append);
+void write_commit_graph_reachable(const char *obj_dir, int append,
+                                 int report_progress);
 void write_commit_graph(const char *obj_dir,
                        struct string_list *pack_indexes,
                        struct string_list *commit_hex,
-                       int append);
+                       int append, int report_progress);
 
 int verify_commit_graph(struct repository *r, struct commit_graph *g);
 
+void close_commit_graph(struct repository *);
 void free_commit_graph(struct commit_graph *);
 
 #endif
index 00e5cee..9f79ce0 100644 (file)
@@ -426,7 +426,7 @@ struct contains_stack {
 static int in_commit_list(const struct commit_list *want, struct commit *c)
 {
        for (; want; want = want->next)
-               if (!oidcmp(&want->item->object.oid, &c->object.oid))
+               if (oideq(&want->item->object.oid, &c->object.oid))
                        return 1;
        return 0;
 }
@@ -561,7 +561,8 @@ int can_all_from_reach_with_flag(struct object_array *from,
                from_one = deref_tag(the_repository, from_one,
                                     "a from object", 0);
                if (!from_one || from_one->type != OBJ_COMMIT) {
-                       /* no way to tell if this is reachable by
+                       /*
+                        * no way to tell if this is reachable by
                         * looking at the ancestry chain alone, so
                         * leave a note to ourselves not to worry about
                         * this object anymore.
@@ -625,10 +626,7 @@ int can_all_from_reach_with_flag(struct object_array *from,
        }
 
 cleanup:
-       for (i = 0; i < nr_commits; i++) {
-               clear_commit_marks(list[i], RESULT);
-               clear_commit_marks(list[i], assign_flag);
-       }
+       clear_commit_marks_many(nr_commits, list, RESULT | assign_flag);
        free(list);
 
        for (i = 0; i < from->nr; i++)
index d0f199e..dc8a39d 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -209,7 +209,7 @@ static int read_graft_file(struct repository *r, const char *graft_file)
        return 0;
 }
 
-static void prepare_commit_graft(struct repository *r)
+void prepare_commit_graft(struct repository *r)
 {
        char *graft_file;
 
index 2b1a734..1d260d6 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -202,6 +202,7 @@ typedef int (*each_commit_graft_fn)(const struct commit_graft *, void *);
 
 struct commit_graft *read_graft_line(struct strbuf *line);
 int register_commit_graft(struct repository *r, struct commit_graft *, int);
+void prepare_commit_graft(struct repository *r);
 struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid);
 
 /* largest positive number a signed 32-bit integer can contain */
index 7ed3fbb..ad5dcde 100644 (file)
@@ -29,9 +29,6 @@
 
 #include <sys/types.h>
 
-/* Specification.  */
-#include <poll.h>
-
 #include <errno.h>
 #include <limits.h>
 #include <assert.h>
@@ -55,6 +52,9 @@
 # include <unistd.h>
 #endif
 
+/* Specification.  */
+#include "poll.h"
+
 #ifdef HAVE_SYS_IOCTL_H
 # include <sys/ioctl.h>
 #endif
index cd19952..1e15973 100644 (file)
 #ifndef _GL_POLL_H
 #define _GL_POLL_H
 
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600
+/* Vista has its own, socket-only poll() */
+#undef POLLIN
+#undef POLLPRI
+#undef POLLOUT
+#undef POLLERR
+#undef POLLHUP
+#undef POLLNVAL
+#undef POLLRDNORM
+#undef POLLRDBAND
+#undef POLLWRNORM
+#undef POLLWRBAND
+#define pollfd compat_pollfd
+#endif
+
 /* fake a poll(2) environment */
 #define POLLIN      0x0001      /* any readable data available   */
 #define POLLPRI     0x0002      /* OOB/Urgent readable data      */
index e47af72..8acdeb7 100644 (file)
@@ -381,8 +381,6 @@ ifeq ($(uname_S),Windows)
        NO_PYTHON = YesPlease
        BLK_SHA1 = YesPlease
        ETAGS_TARGET = ETAGS
-       NO_INET_PTON = YesPlease
-       NO_INET_NTOP = YesPlease
        NO_POSIX_GOODIES = UnfortunatelyYes
        NATIVE_CRLF = YesPlease
        DEFAULT_HELP_FORMAT = html
@@ -529,8 +527,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
        NO_REGEX = YesPlease
        NO_PYTHON = YesPlease
        ETAGS_TARGET = ETAGS
-       NO_INET_PTON = YesPlease
-       NO_INET_NTOP = YesPlease
        NO_POSIX_GOODIES = UnfortunatelyYes
        DEFAULT_HELP_FORMAT = html
        COMPAT_CFLAGS += -DNOGDI -Icompat -Icompat/win32
index f972573..b635cd0 100644 (file)
@@ -1,6 +1,10 @@
 #ifndef DELTA_ISLANDS_H
 #define DELTA_ISLANDS_H
 
+struct object_id;
+struct packing_data;
+struct commit;
+
 int island_delta_cmp(const struct object_id *a, const struct object_id *b);
 int in_same_island(const struct object_id *, const struct object_id *);
 void resolve_tree_islands(int progress, struct packing_data *to_pack);
index 7cdfdd0..d487966 100644 (file)
@@ -19,6 +19,8 @@
 #ifndef __EWOK_RLW_H__
 #define __EWOK_RLW_H__
 
+#include "ewok.h"
+
 #define RLW_RUNNING_BITS (sizeof(eword_t) * 4)
 #define RLW_LITERAL_BITS (sizeof(eword_t) * 8 - 1 - RLW_RUNNING_BITS)
 
diff --git a/fsck.c b/fsck.c
index 0f56977..38624d2 100644 (file)
--- a/fsck.c
+++ b/fsck.c
@@ -10,7 +10,6 @@
 #include "fsck.h"
 #include "refs.h"
 #include "utf8.h"
-#include "sha1-array.h"
 #include "decorate.h"
 #include "oidset.h"
 #include "packfile.h"
@@ -184,40 +183,37 @@ static int fsck_msg_type(enum fsck_msg_id msg_id,
 
 static void init_skiplist(struct fsck_options *options, const char *path)
 {
-       static struct oid_array skiplist = OID_ARRAY_INIT;
-       int sorted, fd;
-       char buffer[GIT_MAX_HEXSZ + 1];
+       FILE *fp;
+       struct strbuf sb = STRBUF_INIT;
        struct object_id oid;
 
-       if (options->skiplist)
-               sorted = options->skiplist->sorted;
-       else {
-               sorted = 1;
-               options->skiplist = &skiplist;
-       }
-
-       fd = open(path, O_RDONLY);
-       if (fd < 0)
+       fp = fopen(path, "r");
+       if (!fp)
                die("Could not open skip list: %s", path);
-       for (;;) {
+       while (!strbuf_getline(&sb, fp)) {
                const char *p;
-               int result = read_in_full(fd, buffer, sizeof(buffer));
-               if (result < 0)
-                       die_errno("Could not read '%s'", path);
-               if (!result)
-                       break;
-               if (parse_oid_hex(buffer, &oid, &p) || *p != '\n')
-                       die("Invalid SHA-1: %s", buffer);
-               oid_array_append(&skiplist, &oid);
-               if (sorted && skiplist.nr > 1 &&
-                               oidcmp(&skiplist.oid[skiplist.nr - 2],
-                                      &oid) > 0)
-                       sorted = 0;
-       }
-       close(fd);
+               const char *hash;
 
-       if (sorted)
-               skiplist.sorted = 1;
+               /*
+                * Allow trailing comments, leading whitespace
+                * (including before commits), and empty or whitespace
+                * only lines.
+                */
+               hash = strchr(sb.buf, '#');
+               if (hash)
+                       strbuf_setlen(&sb, hash - sb.buf);
+               strbuf_trim(&sb);
+               if (!sb.len)
+                       continue;
+
+               if (parse_oid_hex(sb.buf, &oid, &p) || *p != '\0')
+                       die("Invalid SHA-1: %s", sb.buf);
+               oidset_insert(&options->skiplist, &oid);
+       }
+       if (ferror(fp))
+               die_errno("Could not read '%s'", path);
+       fclose(fp);
+       strbuf_release(&sb);
 }
 
 static int parse_msg_type(const char *str)
@@ -322,9 +318,7 @@ static void append_msg_id(struct strbuf *sb, const char *msg_id)
 
 static int object_on_skiplist(struct fsck_options *opts, struct object *obj)
 {
-       if (opts && opts->skiplist && obj)
-               return oid_array_lookup(opts->skiplist, &obj->oid) >= 0;
-       return 0;
+       return opts && obj && oidset_contains(&opts->skiplist, &obj->oid);
 }
 
 __attribute__((format (printf, 4, 5)))
diff --git a/fsck.h b/fsck.h
index 0c7e8c9..b95595a 100644 (file)
--- a/fsck.h
+++ b/fsck.h
@@ -1,6 +1,8 @@
 #ifndef GIT_FSCK_H
 #define GIT_FSCK_H
 
+#include "oidset.h"
+
 #define FSCK_ERROR 1
 #define FSCK_WARN 2
 #define FSCK_IGNORE 3
@@ -35,12 +37,12 @@ struct fsck_options {
        fsck_error error_func;
        unsigned strict:1;
        int *msg_type;
-       struct oid_array *skiplist;
+       struct oidset skiplist;
        struct decoration *object_names;
 };
 
-#define FSCK_OPTIONS_DEFAULT { NULL, fsck_error_function, 0, NULL }
-#define FSCK_OPTIONS_STRICT { NULL, fsck_error_function, 1, NULL }
+#define FSCK_OPTIONS_DEFAULT { NULL, fsck_error_function, 0, NULL, OIDSET_INIT }
+#define FSCK_OPTIONS_STRICT { NULL, fsck_error_function, 1, NULL, OIDSET_INIT }
 
 /* descend in all linked child objects
  * the return value is:
index 5f2e909..48c9555 100644 (file)
 #define _SGI_SOURCE 1
 
 #if defined(WIN32) && !defined(__CYGWIN__) /* Both MinGW and MSVC */
-# if defined (_MSC_VER) && !defined(_WIN32_WINNT)
-#  define _WIN32_WINNT 0x0502
+# if !defined(_WIN32_WINNT)
+#  define _WIN32_WINNT 0x0600
 # endif
 #define WIN32_LEAN_AND_MEAN  /* stops windows.h including winsock.h */
 #include <winsock2.h>
index 7973447..45b6ee9 100755 (executable)
@@ -553,15 +553,15 @@ then
        # Note: incompatibility with --interactive is just a strong warning;
        #       git-rebase.txt caveats with "unless you know what you are doing"
        test -n "$rebase_merges" &&
-               die "$(gettext "error: cannot combine '--preserve_merges' with '--rebase-merges'")"
+               die "$(gettext "error: cannot combine '--preserve-merges' with '--rebase-merges'")"
 fi
 
 if test -n "$rebase_merges"
 then
        test -n "$strategy_opts" &&
-               die "$(gettext "error: cannot combine '--rebase_merges' with '--strategy-option'")"
+               die "$(gettext "error: cannot combine '--rebase-merges' with '--strategy-option'")"
        test -n "$strategy" &&
-               die "$(gettext "error: cannot combine '--rebase_merges' with '--strategy'")"
+               die "$(gettext "error: cannot combine '--rebase-merges' with '--strategy'")"
 fi
 
 if test -z "$rebase_root"
diff --git a/git.c b/git.c
index a6f4b44..5920f80 100644 (file)
--- a/git.c
+++ b/git.c
@@ -675,6 +675,8 @@ static void execv_dashed_external(const char **argv)
 static int run_argv(int *argcp, const char ***argv)
 {
        int done_alias = 0;
+       struct string_list cmd_list = STRING_LIST_INIT_NODUP;
+       struct string_list_item *seen;
 
        while (1) {
                /*
@@ -692,17 +694,37 @@ static int run_argv(int *argcp, const char ***argv)
                /* .. then try the external ones */
                execv_dashed_external(*argv);
 
-               /* It could be an alias -- this works around the insanity
+               seen = unsorted_string_list_lookup(&cmd_list, *argv[0]);
+               if (seen) {
+                       int i;
+                       struct strbuf sb = STRBUF_INIT;
+                       for (i = 0; i < cmd_list.nr; i++) {
+                               struct string_list_item *item = &cmd_list.items[i];
+
+                               strbuf_addf(&sb, "\n  %s", item->string);
+                               if (item == seen)
+                                       strbuf_addstr(&sb, " <==");
+                               else if (i == cmd_list.nr - 1)
+                                       strbuf_addstr(&sb, " ==>");
+                       }
+                       die(_("alias loop detected: expansion of '%s' does"
+                             " not terminate:%s"), cmd_list.items[0].string, sb.buf);
+               }
+
+               string_list_append(&cmd_list, *argv[0]);
+
+               /*
+                * It could be an alias -- this works around the insanity
                 * of overriding "git log" with "git show" by having
                 * alias.log = show
                 */
-               if (done_alias)
-                       break;
                if (!handle_alias(argcp, argv))
                        break;
                done_alias = 1;
        }
 
+       string_list_clear(&cmd_list, 0);
+
        return done_alias;
 }
 
index fc18acc..83906b0 100644 (file)
@@ -42,6 +42,8 @@
  * of the given strings.
  */
 
+#include "strbuf.h"
+
 struct json_writer
 {
        /*
index fa87341..0684dab 100644 (file)
@@ -1274,14 +1274,14 @@ static int merge_submodule(struct merge_options *o,
        return 0;
 }
 
-static int merge_file_1(struct merge_options *o,
-                       const struct diff_filespec *one,
-                       const struct diff_filespec *a,
-                       const struct diff_filespec *b,
-                       const char *filename,
-                       const char *branch1,
-                       const char *branch2,
-                       struct merge_file_info *result)
+static int merge_mode_and_contents(struct merge_options *o,
+                                  const struct diff_filespec *one,
+                                  const struct diff_filespec *a,
+                                  const struct diff_filespec *b,
+                                  const char *filename,
+                                  const char *branch1,
+                                  const char *branch2,
+                                  struct merge_file_info *result)
 {
        result->merge = 0;
        result->clean = 1;
@@ -1366,56 +1366,6 @@ static int merge_file_1(struct merge_options *o,
        return 0;
 }
 
-static int merge_file_special_markers(struct merge_options *o,
-                                     const struct diff_filespec *one,
-                                     const struct diff_filespec *a,
-                                     const struct diff_filespec *b,
-                                     const char *target_filename,
-                                     const char *branch1,
-                                     const char *filename1,
-                                     const char *branch2,
-                                     const char *filename2,
-                                     struct merge_file_info *mfi)
-{
-       char *side1 = NULL;
-       char *side2 = NULL;
-       int ret;
-
-       if (filename1)
-               side1 = xstrfmt("%s:%s", branch1, filename1);
-       if (filename2)
-               side2 = xstrfmt("%s:%s", branch2, filename2);
-
-       ret = merge_file_1(o, one, a, b, target_filename,
-                          side1 ? side1 : branch1,
-                          side2 ? side2 : branch2, mfi);
-
-       free(side1);
-       free(side2);
-       return ret;
-}
-
-static int merge_file_one(struct merge_options *o,
-                         const char *path,
-                         const struct object_id *o_oid, int o_mode,
-                         const struct object_id *a_oid, int a_mode,
-                         const struct object_id *b_oid, int b_mode,
-                         const char *branch1,
-                         const char *branch2,
-                         struct merge_file_info *mfi)
-{
-       struct diff_filespec one, a, b;
-
-       one.path = a.path = b.path = (char *)path;
-       oidcpy(&one.oid, o_oid);
-       one.mode = o_mode;
-       oidcpy(&a.oid, a_oid);
-       a.mode = a_mode;
-       oidcpy(&b.oid, b_oid);
-       b.mode = b_mode;
-       return merge_file_1(o, &one, &a, &b, path, branch1, branch2, mfi);
-}
-
 static int handle_rename_via_dir(struct merge_options *o,
                                 struct diff_filepair *pair,
                                 const char *rename_branch,
@@ -1659,11 +1609,8 @@ static int handle_rename_rename_1to2(struct merge_options *o,
                struct merge_file_info mfi;
                struct diff_filespec other;
                struct diff_filespec *add;
-               if (merge_file_one(o, one->path,
-                                &one->oid, one->mode,
-                                &a->oid, a->mode,
-                                &b->oid, b->mode,
-                                ci->branch1, ci->branch2, &mfi))
+               if (merge_mode_and_contents(o, one, a, b, one->path,
+                                           ci->branch1, ci->branch2, &mfi))
                        return -1;
 
                /*
@@ -1729,14 +1676,10 @@ static int handle_rename_rename_2to1(struct merge_options *o,
 
        path_side_1_desc = xstrfmt("%s (was %s)", path, a->path);
        path_side_2_desc = xstrfmt("%s (was %s)", path, b->path);
-       if (merge_file_special_markers(o, a, c1, &ci->ren1_other,
-                                      path_side_1_desc,
-                                      o->branch1, c1->path,
-                                      o->branch2, ci->ren1_other.path, &mfi_c1) ||
-           merge_file_special_markers(o, b, &ci->ren2_other, c2,
-                                      path_side_2_desc,
-                                      o->branch1, ci->ren2_other.path,
-                                      o->branch2, c2->path, &mfi_c2))
+       if (merge_mode_and_contents(o, a, c1, &ci->ren1_other, path_side_1_desc,
+                                   o->branch1, o->branch2, &mfi_c1) ||
+           merge_mode_and_contents(o, b, &ci->ren2_other, c2, path_side_2_desc,
+                                   o->branch1, o->branch2, &mfi_c2))
                return -1;
        free(path_side_1_desc);
        free(path_side_2_desc);
@@ -2766,12 +2709,23 @@ static int process_renames(struct merge_options *o,
                                       ren1_dst, branch2);
                                if (o->call_depth) {
                                        struct merge_file_info mfi;
-                                       if (merge_file_one(o, ren1_dst, &null_oid, 0,
-                                                          &ren1->pair->two->oid,
-                                                          ren1->pair->two->mode,
-                                                          &dst_other.oid,
-                                                          dst_other.mode,
-                                                          branch1, branch2, &mfi)) {
+                                       struct diff_filespec one, a, b;
+
+                                       oidcpy(&one.oid, &null_oid);
+                                       one.mode = 0;
+                                       one.path = ren1->pair->two->path;
+
+                                       oidcpy(&a.oid, &ren1->pair->two->oid);
+                                       a.mode = ren1->pair->two->mode;
+                                       a.path = one.path;
+
+                                       oidcpy(&b.oid, &dst_other.oid);
+                                       b.mode = dst_other.mode;
+                                       b.path = one.path;
+
+                                       if (merge_mode_and_contents(o, &one, &a, &b, ren1_dst,
+                                                                   branch1, branch2,
+                                                                   &mfi)) {
                                                clean_merge = -1;
                                                goto cleanup_and_return;
                                        }
@@ -3021,13 +2975,13 @@ static int handle_modify_delete(struct merge_options *o,
                                    _("modify"), _("modified"));
 }
 
-static int merge_content(struct merge_options *o,
-                        const char *path,
-                        int is_dirty,
-                        struct object_id *o_oid, int o_mode,
-                        struct object_id *a_oid, int a_mode,
-                        struct object_id *b_oid, int b_mode,
-                        struct rename_conflict_info *rename_conflict_info)
+static int handle_content_merge(struct merge_options *o,
+                               const char *path,
+                               int is_dirty,
+                               struct object_id *o_oid, int o_mode,
+                               struct object_id *a_oid, int a_mode,
+                               struct object_id *b_oid, int b_mode,
+                               struct rename_conflict_info *rename_conflict_info)
 {
        const char *reason = _("content");
        const char *path1 = NULL, *path2 = NULL;
@@ -3059,14 +3013,16 @@ static int merge_content(struct merge_options *o,
                path2 = (rename_conflict_info->pair2 ||
                         o->branch2 == rename_conflict_info->branch1) ?
                        pair1->two->path : pair1->one->path;
+               one.path = pair1->one->path;
+               a.path = (char *)path1;
+               b.path = (char *)path2;
 
                if (dir_in_way(path, !o->call_depth,
                               S_ISGITLINK(pair1->two->mode)))
                        df_conflict_remains = 1;
        }
-       if (merge_file_special_markers(o, &one, &a, &b, path,
-                                      o->branch1, path1,
-                                      o->branch2, path2, &mfi))
+       if (merge_mode_and_contents(o, &one, &a, &b, path,
+                                   o->branch1, o->branch2, &mfi))
                return -1;
 
        /*
@@ -3157,9 +3113,9 @@ static int handle_rename_normal(struct merge_options *o,
                                struct rename_conflict_info *ci)
 {
        /* Merge the content and write it out */
-       return merge_content(o, path, was_dirty(o, path),
-                            o_oid, o_mode, a_oid, a_mode, b_oid, b_mode,
-                            ci);
+       return handle_content_merge(o, path, was_dirty(o, path),
+                                   o_oid, o_mode, a_oid, a_mode, b_oid, b_mode,
+                                   ci);
 }
 
 /* Per entry merge function */
@@ -3283,9 +3239,11 @@ static int process_entry(struct merge_options *o,
                /* Case C: Added in both (check for same permissions) and */
                /* case D: Modified in both, but differently. */
                int is_dirty = 0; /* unpack_trees would have bailed if dirty */
-               clean_merge = merge_content(o, path, is_dirty,
-                                           o_oid, o_mode, a_oid, a_mode, b_oid, b_mode,
-                                           NULL);
+               clean_merge = handle_content_merge(o, path, is_dirty,
+                                                  o_oid, o_mode,
+                                                  a_oid, a_mode,
+                                                  b_oid, b_mode,
+                                                  NULL);
        } else if (!o_oid && !a_oid && !b_oid) {
                /*
                 * this entry was deleted altogether. a_mode == 0 means
diff --git a/midx.c b/midx.c
index f3e8dbc..ea2f3ff 100644 (file)
--- a/midx.c
+++ b/midx.c
@@ -7,6 +7,7 @@
 #include "object-store.h"
 #include "sha1-lookup.h"
 #include "midx.h"
+#include "progress.h"
 
 #define MIDX_SIGNATURE 0x4d494458 /* "MIDX" */
 #define MIDX_VERSION 1
@@ -76,24 +77,18 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
        m->local = local;
 
        m->signature = get_be32(m->data);
-       if (m->signature != MIDX_SIGNATURE) {
-               error(_("multi-pack-index signature 0x%08x does not match signature 0x%08x"),
+       if (m->signature != MIDX_SIGNATURE)
+               die(_("multi-pack-index signature 0x%08x does not match signature 0x%08x"),
                      m->signature, MIDX_SIGNATURE);
-               goto cleanup_fail;
-       }
 
        m->version = m->data[MIDX_BYTE_FILE_VERSION];
-       if (m->version != MIDX_VERSION) {
-               error(_("multi-pack-index version %d not recognized"),
+       if (m->version != MIDX_VERSION)
+               die(_("multi-pack-index version %d not recognized"),
                      m->version);
-               goto cleanup_fail;
-       }
 
        hash_version = m->data[MIDX_BYTE_HASH_VERSION];
-       if (hash_version != MIDX_HASH_VERSION) {
-               error(_("hash version %u does not match"), hash_version);
-               goto cleanup_fail;
-       }
+       if (hash_version != MIDX_HASH_VERSION)
+               die(_("hash version %u does not match"), hash_version);
        m->hash_len = MIDX_HASH_LEN;
 
        m->num_chunks = m->data[MIDX_BYTE_NUM_CHUNKS];
@@ -106,6 +101,9 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
                uint64_t chunk_offset = get_be64(m->data + MIDX_HEADER_SIZE + 4 +
                                                 MIDX_CHUNKLOOKUP_WIDTH * i);
 
+               if (chunk_offset >= m->data_len)
+                       die(_("invalid chunk offset (too large)"));
+
                switch (chunk_id) {
                        case MIDX_CHUNKID_PACKNAMES:
                                m->chunk_pack_names = m->data + chunk_offset;
@@ -160,12 +158,10 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
 
                cur_pack_name += strlen(cur_pack_name) + 1;
 
-               if (i && strcmp(m->pack_names[i], m->pack_names[i - 1]) <= 0) {
-                       error(_("multi-pack-index pack names out of order: '%s' before '%s'"),
+               if (i && strcmp(m->pack_names[i], m->pack_names[i - 1]) <= 0)
+                       die(_("multi-pack-index pack names out of order: '%s' before '%s'"),
                              m->pack_names[i - 1],
                              m->pack_names[i]);
-                       goto cleanup_fail;
-               }
        }
 
        return m;
@@ -202,7 +198,8 @@ int prepare_midx_pack(struct multi_pack_index *m, uint32_t pack_int_id)
        struct strbuf pack_name = STRBUF_INIT;
 
        if (pack_int_id >= m->num_packs)
-               BUG("bad pack-int-id");
+               die(_("bad pack-int-id: %u (%u total packs"),
+                   pack_int_id, m->num_packs);
 
        if (m->packs[pack_int_id])
                return 0;
@@ -241,7 +238,7 @@ static off_t nth_midxed_offset(struct multi_pack_index *m, uint32_t pos)
        offset32 = get_be32(offset_data + sizeof(uint32_t));
 
        if (m->chunk_large_offsets && offset32 & MIDX_LARGE_OFFSET_NEEDED) {
-               if (sizeof(offset32) < sizeof(uint64_t))
+               if (sizeof(off_t) < sizeof(uint64_t))
                        die(_("multi-pack-index stores a 64-bit offset, but off_t is too small"));
 
                offset32 ^= MIDX_LARGE_OFFSET_NEEDED;
@@ -285,8 +282,8 @@ static int nth_midxed_pack_entry(struct multi_pack_index *m, struct pack_entry *
                struct object_id oid;
                nth_midxed_object_oid(&oid, m, pos);
                for (i = 0; i < p->num_bad_objects; i++)
-                       if (!hashcmp(oid.hash,
-                                    p->bad_object_sha1 + the_hash_algo->rawsz * i))
+                       if (hasheq(oid.hash,
+                                  p->bad_object_sha1 + the_hash_algo->rawsz * i))
                                return 0;
        }
 
@@ -583,8 +580,8 @@ static struct pack_midx_entry *get_sorted_entries(struct multi_pack_index *m,
                 * Take only the first duplicate.
                 */
                for (cur_object = 0; cur_object < nr_fanout; cur_object++) {
-                       if (cur_object && !oidcmp(&entries_by_fanout[cur_object - 1].oid,
-                                                 &entries_by_fanout[cur_object].oid))
+                       if (cur_object && oideq(&entries_by_fanout[cur_object - 1].oid,
+                                               &entries_by_fanout[cur_object].oid))
                                continue;
 
                        ALLOC_GROW(deduplicated_entries, *nr_objects + 1, alloc_objects);
@@ -928,3 +925,83 @@ void clear_midx_file(const char *object_dir)
 
        free(midx);
 }
+
+static int verify_midx_error;
+
+static void midx_report(const char *fmt, ...)
+{
+       va_list ap;
+       verify_midx_error = 1;
+       va_start(ap, fmt);
+       vfprintf(stderr, fmt, ap);
+       fprintf(stderr, "\n");
+       va_end(ap);
+}
+
+int verify_midx_file(const char *object_dir)
+{
+       uint32_t i;
+       struct progress *progress = NULL;
+       struct multi_pack_index *m = load_multi_pack_index(object_dir, 1);
+       verify_midx_error = 0;
+
+       if (!m)
+               return 0;
+
+       for (i = 0; i < m->num_packs; i++) {
+               if (prepare_midx_pack(m, i))
+                       midx_report("failed to load pack in position %d", i);
+       }
+
+       for (i = 0; i < 255; i++) {
+               uint32_t oid_fanout1 = ntohl(m->chunk_oid_fanout[i]);
+               uint32_t oid_fanout2 = ntohl(m->chunk_oid_fanout[i + 1]);
+
+               if (oid_fanout1 > oid_fanout2)
+                       midx_report(_("oid fanout out of order: fanout[%d] = %"PRIx32" > %"PRIx32" = fanout[%d]"),
+                                   i, oid_fanout1, oid_fanout2, i + 1);
+       }
+
+       for (i = 0; i < m->num_objects - 1; i++) {
+               struct object_id oid1, oid2;
+
+               nth_midxed_object_oid(&oid1, m, i);
+               nth_midxed_object_oid(&oid2, m, i + 1);
+
+               if (oidcmp(&oid1, &oid2) >= 0)
+                       midx_report(_("oid lookup out of order: oid[%d] = %s >= %s = oid[%d]"),
+                                   i, oid_to_hex(&oid1), oid_to_hex(&oid2), i + 1);
+       }
+
+       progress = start_progress(_("Verifying object offsets"), m->num_objects);
+       for (i = 0; i < m->num_objects; i++) {
+               struct object_id oid;
+               struct pack_entry e;
+               off_t m_offset, p_offset;
+
+               nth_midxed_object_oid(&oid, m, i);
+               if (!fill_midx_entry(&oid, &e, m)) {
+                       midx_report(_("failed to load pack entry for oid[%d] = %s"),
+                                   i, oid_to_hex(&oid));
+                       continue;
+               }
+
+               if (open_pack_index(e.p)) {
+                       midx_report(_("failed to load pack-index for packfile %s"),
+                                   e.p->pack_name);
+                       break;
+               }
+
+               m_offset = e.offset;
+               p_offset = find_pack_entry_one(oid.hash, e.p);
+
+               if (m_offset != p_offset)
+                       midx_report(_("incorrect object offset for oid[%d] = %s: %"PRIx64" != %"PRIx64),
+                                   i, oid_to_hex(&oid), m_offset, p_offset);
+
+               display_progress(progress, i + 1);
+       }
+       stop_progress(&progress);
+
+       return verify_midx_error;
+}
diff --git a/midx.h b/midx.h
index a210f1a..2d7c9c6 100644 (file)
--- a/midx.h
+++ b/midx.h
@@ -3,6 +3,9 @@
 
 #include "repository.h"
 
+struct object_id;
+struct pack_entry;
+
 struct multi_pack_index {
        struct multi_pack_index *next;
 
@@ -43,5 +46,6 @@ int prepare_multi_pack_index_one(struct repository *r, const char *object_dir, i
 
 int write_midx_file(const char *object_dir);
 void clear_midx_file(const char *object_dir);
+int verify_midx_file(const char *object_dir);
 
 #endif
diff --git a/refs.c b/refs.c
index a7a75b4..bbcac92 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1394,17 +1394,50 @@ struct ref_iterator *refs_ref_iterator_begin(
  * non-zero value, stop the iteration and return that value;
  * otherwise, return 0.
  */
+static int do_for_each_repo_ref(struct repository *r, const char *prefix,
+                               each_repo_ref_fn fn, int trim, int flags,
+                               void *cb_data)
+{
+       struct ref_iterator *iter;
+       struct ref_store *refs = get_main_ref_store(r);
+
+       if (!refs)
+               return 0;
+
+       iter = refs_ref_iterator_begin(refs, prefix, trim, flags);
+
+       return do_for_each_repo_ref_iterator(r, iter, fn, cb_data);
+}
+
+struct do_for_each_ref_help {
+       each_ref_fn *fn;
+       void *cb_data;
+};
+
+static int do_for_each_ref_helper(struct repository *r,
+                                 const char *refname,
+                                 const struct object_id *oid,
+                                 int flags,
+                                 void *cb_data)
+{
+       struct do_for_each_ref_help *hp = cb_data;
+
+       return hp->fn(refname, oid, flags, hp->cb_data);
+}
+
 static int do_for_each_ref(struct ref_store *refs, const char *prefix,
                           each_ref_fn fn, int trim, int flags, void *cb_data)
 {
        struct ref_iterator *iter;
+       struct do_for_each_ref_help hp = { fn, cb_data };
 
        if (!refs)
                return 0;
 
        iter = refs_ref_iterator_begin(refs, prefix, trim, flags);
 
-       return do_for_each_ref_iterator(iter, fn, cb_data);
+       return do_for_each_repo_ref_iterator(the_repository, iter,
+                                       do_for_each_ref_helper, &hp);
 }
 
 int refs_for_each_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
@@ -1449,12 +1482,11 @@ int refs_for_each_fullref_in(struct ref_store *refs, const char *prefix,
        return do_for_each_ref(refs, prefix, fn, 0, flag, cb_data);
 }
 
-int for_each_replace_ref(struct repository *r, each_ref_fn fn, void *cb_data)
+int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data)
 {
-       return do_for_each_ref(get_main_ref_store(r),
-                              git_replace_ref_base, fn,
-                              strlen(git_replace_ref_base),
-                              DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
+       return do_for_each_repo_ref(r, git_replace_ref_base, fn,
+                                   strlen(git_replace_ref_base),
+                                   DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
 }
 
 int for_each_namespaced_ref(each_ref_fn fn, void *cb_data)
@@ -2033,10 +2065,12 @@ cleanup:
 int refs_for_each_reflog(struct ref_store *refs, each_ref_fn fn, void *cb_data)
 {
        struct ref_iterator *iter;
+       struct do_for_each_ref_help hp = { fn, cb_data };
 
        iter = refs->be->reflog_iterator_begin(refs);
 
-       return do_for_each_ref_iterator(iter, fn, cb_data);
+       return do_for_each_repo_ref_iterator(the_repository, iter,
+                                            do_for_each_ref_helper, &hp);
 }
 
 int for_each_reflog(each_ref_fn fn, void *cb_data)
diff --git a/refs.h b/refs.h
index bd52c1b..6cc0397 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -276,6 +276,16 @@ struct ref_transaction;
 typedef int each_ref_fn(const char *refname,
                        const struct object_id *oid, int flags, void *cb_data);
 
+/*
+ * The same as each_ref_fn, but also with a repository argument that
+ * contains the repository associated with the callback.
+ */
+typedef int each_repo_ref_fn(struct repository *r,
+                            const char *refname,
+                            const struct object_id *oid,
+                            int flags,
+                            void *cb_data);
+
 /*
  * The following functions invoke the specified callback function for
  * each reference indicated.  If the function ever returns a nonzero
@@ -309,7 +319,7 @@ int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data,
 int for_each_tag_ref(each_ref_fn fn, void *cb_data);
 int for_each_branch_ref(each_ref_fn fn, void *cb_data);
 int for_each_remote_ref(each_ref_fn fn, void *cb_data);
-int for_each_replace_ref(struct repository *r, each_ref_fn fn, void *cb_data);
+int for_each_replace_ref(struct repository *r, each_repo_ref_fn fn, void *cb_data);
 int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data);
 int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
                         const char *prefix, void *cb_data);
index 2ac91ac..629e00a 100644 (file)
@@ -407,15 +407,15 @@ struct ref_iterator *prefix_ref_iterator_begin(struct ref_iterator *iter0,
 
 struct ref_iterator *current_ref_iter = NULL;
 
-int do_for_each_ref_iterator(struct ref_iterator *iter,
-                            each_ref_fn fn, void *cb_data)
+int do_for_each_repo_ref_iterator(struct repository *r, struct ref_iterator *iter,
+                                 each_repo_ref_fn fn, void *cb_data)
 {
        int retval = 0, ok;
        struct ref_iterator *old_ref_iter = current_ref_iter;
 
        current_ref_iter = iter;
        while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
-               retval = fn(iter->refname, iter->oid, iter->flags, cb_data);
+               retval = fn(r, iter->refname, iter->oid, iter->flags, cb_data);
                if (retval) {
                        /*
                         * If ref_iterator_abort() returns ITER_ERROR,
index 640245d..a01a0af 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef REFS_PACKED_BACKEND_H
 #define REFS_PACKED_BACKEND_H
 
+struct ref_transaction;
+
 /*
  * Support for storing references in a `packed-refs` file.
  *
index eda65e7..3bfb89d 100644 (file)
@@ -1,7 +1,10 @@
 #ifndef REFS_REF_CACHE_H
 #define REFS_REF_CACHE_H
 
+#include "cache.h"
+
 struct ref_dir;
+struct ref_store;
 
 /*
  * If this ref_cache is filled lazily, this function is used to load
index 04425d6..f2d8c01 100644 (file)
@@ -1,8 +1,12 @@
 #ifndef REFS_REFS_INTERNAL_H
 #define REFS_REFS_INTERNAL_H
 
+#include "cache.h"
+#include "refs.h"
 #include "iterator.h"
 
+struct ref_transaction;
+
 /*
  * Data structures and functions for the internal use of the refs
  * module. Code outside of the refs module should use only the public
@@ -282,7 +286,7 @@ int refs_rename_ref_available(struct ref_store *refs,
  *
  *             // Access information about the current reference:
  *             if (!(iter->flags & REF_ISSYMREF))
- *                     printf("%s is %s\n", iter->refname, oid_to_hex(&iter->oid));
+ *                     printf("%s is %s\n", iter->refname, oid_to_hex(iter->oid));
  *
  *             // If you need to peel the reference:
  *             ref_iterator_peel(iter, &oid);
@@ -474,8 +478,9 @@ extern struct ref_iterator *current_ref_iter;
  * adapter between the callback style of reference iteration and the
  * iterator style.
  */
-int do_for_each_ref_iterator(struct ref_iterator *iter,
-                            each_ref_fn fn, void *cb_data);
+int do_for_each_repo_ref_iterator(struct repository *r,
+                                 struct ref_iterator *iter,
+                                 each_repo_ref_fn fn, void *cb_data);
 
 /*
  * Only include per-worktree refs in a do_for_each_ref*() iteration.
index 4ec77ce..e295e87 100644 (file)
@@ -6,7 +6,8 @@
 #include "repository.h"
 #include "commit.h"
 
-static int register_replace_ref(const char *refname,
+static int register_replace_ref(struct repository *r,
+                               const char *refname,
                                const struct object_id *oid,
                                int flag, void *cb_data)
 {
@@ -25,13 +26,13 @@ static int register_replace_ref(const char *refname,
        oidcpy(&repl_obj->replacement, oid);
 
        /* Register new object */
-       if (oidmap_put(the_repository->objects->replace_map, repl_obj))
+       if (oidmap_put(r->objects->replace_map, repl_obj))
                die(_("duplicate replace ref: %s"), refname);
 
        return 0;
 }
 
-static void prepare_replace_object(struct repository *r)
+void prepare_replace_object(struct repository *r)
 {
        if (r->objects->replace_map)
                return;
index 9345e10..16528df 100644 (file)
@@ -10,6 +10,8 @@ struct replace_object {
        struct object_id replacement;
 };
 
+void prepare_replace_object(struct repository *r);
+
 /*
  * This internal function is only declared here for the benefit of
  * lookup_replace_object().  Please do not call it directly.
index ddb41a6..6387c9e 100644 (file)
@@ -4146,9 +4146,7 @@ static int make_script_with_merges(struct pretty_print_context *pp,
                        struct object_id *oid = &parent->item->object.oid;
                        if (!oidset_contains(&interesting, oid))
                                continue;
-                       if (!oidset_contains(&child_seen, oid))
-                               oidset_insert(&child_seen, oid);
-                       else
+                       if (oidset_insert(&child_seen, oid))
                                label_oid(oid, "branch-point", &state);
                }
 
index 3ea6c85..4d8dbc7 100644 (file)
--- a/t/README
+++ b/t/README
@@ -401,13 +401,13 @@ This test harness library does the following things:
    consistently when command line arguments --verbose (or -v),
    --debug (or -d), and --immediate (or -i) is given.
 
-Do's, don'ts & things to keep in mind
--------------------------------------
+Do's & don'ts
+-------------
 
 Here are a few examples of things you probably should and shouldn't do
 when writing tests.
 
-Do:
+Here are the "do's:"
 
  - Put all code inside test_expect_success and other assertions.
 
@@ -452,16 +452,21 @@ Do:
    Windows, where the shell (MSYS bash) mangles absolute path names.
    For details, see the commit message of 4114156ae9.
 
-Don't:
+ - Remember that inside the <script> part, the standard output and
+   standard error streams are discarded, and the test harness only
+   reports "ok" or "not ok" to the end user running the tests. Under
+   --verbose, they are shown to help debug the tests.
+
+And here are the "don'ts:"
 
- - exit() within a <script> part.
+ - Don't exit() within a <script> part.
 
    The harness will catch this as a programming error of the test.
    Use test_done instead if you need to stop the tests early (see
    "Skipping tests" below).
 
- - use '! git cmd' when you want to make sure the git command exits
-   with failure in a controlled way by calling "die()".  Instead,
+ - Don't use '! git cmd' when you want to make sure the git command
+   exits with failure in a controlled way by calling "die()".  Instead,
    use 'test_must_fail git cmd'.  This will signal a failure if git
    dies in an unexpected way (e.g. segfault).
 
@@ -469,8 +474,35 @@ Don't:
    platform commands; just use '! cmd'.  We are not in the business
    of verifying that the world given to us sanely works.
 
- - use perl without spelling it as "$PERL_PATH". This is to help our
-   friends on Windows where the platform Perl often adds CR before
+ - Don't feed the output of a git command to a pipe, as in:
+
+     git -C repo ls-files |
+     xargs -n 1 basename |
+     grep foo
+
+   which will discard git's exit code and may mask a crash. In the
+   above example, all exit codes are ignored except grep's.
+
+   Instead, write the output of that command to a temporary
+   file with ">" or assign it to a variable with "x=$(git ...)" rather
+   than pipe it.
+
+ - Don't use command substitution in a way that discards git's exit
+   code. When assigning to a variable, the exit code is not discarded,
+   e.g.:
+
+     x=$(git cat-file -p $sha) &&
+     ...
+
+   is OK because a crash in "git cat-file" will cause the "&&" chain
+   to fail, but:
+
+     test "refs/heads/foo" = "$(git symbolic-ref HEAD)"
+
+   is not OK and a crash in git could go undetected.
+
+ - Don't use perl without spelling it as "$PERL_PATH". This is to help
+   our friends on Windows where the platform Perl often adds CR before
    the end of line, and they bundle Git with a version of Perl that
    does not do so, whose path is specified with $PERL_PATH. Note that we
    provide a "perl" function which uses $PERL_PATH under the hood, so
@@ -478,17 +510,17 @@ Don't:
    (but you do, for example, on a shebang line or in a sub script
    created via "write_script").
 
- - use sh without spelling it as "$SHELL_PATH", when the script can
-   be misinterpreted by broken platform shell (e.g. Solaris).
+ - Don't use sh without spelling it as "$SHELL_PATH", when the script
+   can be misinterpreted by broken platform shell (e.g. Solaris).
 
- - chdir around in tests.  It is not sufficient to chdir to
+ - Don't chdir around in tests.  It is not sufficient to chdir to
    somewhere and then chdir back to the original location later in
    the test, as any intermediate step can fail and abort the test,
    causing the next test to start in an unexpected directory.  Do so
    inside a subshell if necessary.
 
- - save and verify the standard error of compound commands, i.e. group
-   commands, subshells, and shell functions (except test helper
+ - Don't save and verify the standard error of compound commands, i.e.
+   group commands, subshells, and shell functions (except test helper
    functions like 'test_must_fail') like this:
 
      ( cd dir && git cmd ) 2>error &&
@@ -503,7 +535,7 @@ Don't:
      ( cd dir && git cmd 2>../error ) &&
      test_cmp expect error
 
- - Break the TAP output
+ - Don't break the TAP output
 
    The raw output from your test may be interpreted by a TAP harness. TAP
    harnesses will ignore everything they don't know about, but don't step
@@ -523,13 +555,6 @@ Don't:
    but the best indication is to just run the tests with prove(1),
    it'll complain if anything is amiss.
 
-Keep in mind:
-
- - Inside the <script> part, the standard output and standard error
-   streams are discarded, and the test harness only reports "ok" or
-   "not ok" to the end user running the tests. Under --verbose, they
-   are shown to help debugging the tests.
-
 
 Skipping tests
 --------------
@@ -814,6 +839,28 @@ library for your script to use.
    the symbolic link in the file system and a part that does; then only
    the latter part need be protected by a SYMLINKS prerequisite (see below).
 
+ - test_oid_init
+
+   This function loads facts and useful object IDs related to the hash
+   algorithm(s) in use from the files in t/oid-info.
+
+ - test_oid_cache
+
+   This function reads per-hash algorithm information from standard
+   input (usually a heredoc) in the format described in
+   t/oid-info/README.  This is useful for test-specific values, such as
+   object IDs, which must vary based on the hash algorithm.
+
+   Certain fixed values, such as hash sizes and common placeholder
+   object IDs, can be loaded with test_oid_init (described above).
+
+ - test_oid <key>
+
+   This function looks up a value for the hash algorithm in use, based
+   on the key given.  The value must have been loaded using
+   test_oid_init or test_oid_cache.  Providing an unknown key is an
+   error.
+
 Prerequisites
 -------------
 
index ad45270..08e3684 100644 (file)
@@ -1,6 +1,7 @@
+#include "test-tool.h"
 #include "cache.h"
 
-int cmd_main(int ac, const char **av)
+int cmd__dump_fsmonitor(int ac, const char **av)
 {
        struct index_state *istate = &the_index;
        int i;
index bd92fb3..52870eb 100644 (file)
@@ -1,3 +1,4 @@
+#include "test-tool.h"
 #include "cache.h"
 #include "dir.h"
 
@@ -38,7 +39,7 @@ static void dump(struct untracked_cache_dir *ucd, struct strbuf *base)
        strbuf_setlen(base, len);
 }
 
-int cmd_main(int ac, const char **av)
+int cmd__dump_untracked_cache(int ac, const char **av)
 {
        struct untracked_cache *uc;
        struct strbuf base = STRBUF_INIT;
index 630c76d..9cb8a0e 100644 (file)
@@ -1,3 +1,4 @@
+#include "test-tool.h"
 #include "cache.h"
 #include "parse-options.h"
 #include "string-list.h"
@@ -94,11 +95,11 @@ static void show(struct string_list *expect, int *status, const char *fmt, ...)
        strbuf_release(&buf);
 }
 
-int cmd_main(int argc, const char **argv)
+int cmd__parse_options(int argc, const char **argv)
 {
        const char *prefix = "prefix/";
        const char *usage[] = {
-               "test-parse-options <options>",
+               "test-tool parse-options <options>",
                "",
                "A helper function for the parse-options API.",
                NULL
index 30775f9..282d536 100644 (file)
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "test-tool.h"
 #include "pkt-line.h"
 
 static void pack_line(const char *line)
@@ -79,7 +80,7 @@ static void unpack_sideband(void)
        }
 }
 
-int cmd_main(int argc, const char **argv)
+int cmd__pkt_line(int argc, const char **argv)
 {
        if (argc < 2)
                die("too few arguments");
index 2762ca6..6a84a53 100644 (file)
@@ -15,7 +15,10 @@ static void test_parse_commit_in_graph(const char *gitdir, const char *worktree,
        struct commit *c;
        struct commit_list *parent;
 
-       repo_init(&r, gitdir, worktree);
+       setup_git_env(gitdir);
+
+       if (repo_init(&r, gitdir, worktree))
+               die("Couldn't init repo");
 
        c = lookup_commit(&r, commit_oid);
 
@@ -38,7 +41,10 @@ static void test_get_commit_tree_in_graph(const char *gitdir,
        struct commit *c;
        struct tree *tree;
 
-       repo_init(&r, gitdir, worktree);
+       setup_git_env(gitdir);
+
+       if (repo_init(&r, gitdir, worktree))
+               die("Couldn't init repo");
 
        c = lookup_commit(&r, commit_oid);
 
index b87a8c1..6b5836d 100644 (file)
@@ -14,7 +14,9 @@ static struct test_cmd cmds[] = {
        { "delta", cmd__delta },
        { "drop-caches", cmd__drop_caches },
        { "dump-cache-tree", cmd__dump_cache_tree },
+       { "dump-fsmonitor", cmd__dump_fsmonitor },
        { "dump-split-index", cmd__dump_split_index },
+       { "dump-untracked-cache", cmd__dump_untracked_cache },
        { "example-decorate", cmd__example_decorate },
        { "genrandom", cmd__genrandom },
        { "hashmap", cmd__hashmap },
@@ -25,7 +27,9 @@ static struct test_cmd cmds[] = {
        { "mergesort", cmd__mergesort },
        { "mktemp", cmd__mktemp },
        { "online-cpus", cmd__online_cpus },
+       { "parse-options", cmd__parse_options },
        { "path-utils", cmd__path_utils },
+       { "pkt-line", cmd__pkt_line },
        { "prio-queue", cmd__prio_queue },
        { "reach", cmd__reach },
        { "read-cache", cmd__read_cache },
@@ -36,8 +40,8 @@ static struct test_cmd cmds[] = {
        { "revision-walking", cmd__revision_walking },
        { "run-command", cmd__run_command },
        { "scrap-cache-tree", cmd__scrap_cache_tree },
-       { "sha1-array", cmd__sha1_array },
        { "sha1", cmd__sha1 },
+       { "sha1-array", cmd__sha1_array },
        { "sigchain", cmd__sigchain },
        { "strcmp-offset", cmd__strcmp_offset },
        { "string-list", cmd__string_list },
index e074957..e489056 100644 (file)
@@ -10,7 +10,9 @@ int cmd__date(int argc, const char **argv);
 int cmd__delta(int argc, const char **argv);
 int cmd__drop_caches(int argc, const char **argv);
 int cmd__dump_cache_tree(int argc, const char **argv);
+int cmd__dump_fsmonitor(int argc, const char **argv);
 int cmd__dump_split_index(int argc, const char **argv);
+int cmd__dump_untracked_cache(int argc, const char **argv);
 int cmd__example_decorate(int argc, const char **argv);
 int cmd__genrandom(int argc, const char **argv);
 int cmd__hashmap(int argc, const char **argv);
@@ -21,7 +23,9 @@ int cmd__match_trees(int argc, const char **argv);
 int cmd__mergesort(int argc, const char **argv);
 int cmd__mktemp(int argc, const char **argv);
 int cmd__online_cpus(int argc, const char **argv);
+int cmd__parse_options(int argc, const char **argv);
 int cmd__path_utils(int argc, const char **argv);
+int cmd__pkt_line(int argc, const char **argv);
 int cmd__prio_queue(int argc, const char **argv);
 int cmd__reach(int argc, const char **argv);
 int cmd__read_cache(int argc, const char **argv);
@@ -32,8 +36,8 @@ int cmd__repository(int argc, const char **argv);
 int cmd__revision_walking(int argc, const char **argv);
 int cmd__run_command(int argc, const char **argv);
 int cmd__scrap_cache_tree(int argc, const char **argv);
-int cmd__sha1_array(int argc, const char **argv);
 int cmd__sha1(int argc, const char **argv);
+int cmd__sha1_array(int argc, const char **argv);
 int cmd__sigchain(int argc, const char **argv);
 int cmd__strcmp_offset(int argc, const char **argv);
 int cmd__string_list(int argc, const char **argv);
index 3fe0287..f1277be 100755 (executable)
@@ -57,9 +57,12 @@ then
                echo | gpgsm --homedir "${GNUPGHOME}" 2>/dev/null \
                        --passphrase-fd 0 --pinentry-mode loopback \
                        --import "$TEST_DIRECTORY"/lib-gpg/gpgsm_cert.p12 &&
-               gpgsm --homedir "${GNUPGHOME}" 2>/dev/null -K \
-                       | grep fingerprint: | cut -d" " -f4 | tr -d '\n' > \
-                       ${GNUPGHOME}/trustlist.txt &&
+
+               gpgsm --homedir "${GNUPGHOME}" 2>/dev/null -K |
+               grep fingerprint: |
+               cut -d" " -f4 |
+               tr -d '\n' >"${GNUPGHOME}/trustlist.txt" &&
+
                echo " S relax" >> ${GNUPGHOME}/trustlist.txt &&
                (gpgconf --kill gpg-agent >/dev/null 2>&1 || : ) &&
                echo hello | gpgsm --homedir "${GNUPGHOME}" >/dev/null \
diff --git a/t/oid-info/README b/t/oid-info/README
new file mode 100644 (file)
index 0000000..27f843f
--- /dev/null
@@ -0,0 +1,19 @@
+This directory contains various per-hash values that are used in the testsuite.
+
+Each file contains lines containing a key-value pair; blank lines and lines
+starting with `#` are ignored.  The key and value are separated by whitespace
+(specifically, those whitespace in the default `$IFS`).  The key consists only
+of shell identifier characters, and the value consists of a hash algorithm,
+colon, and value.  The hash algorithm also consists only of shell identifier
+characters; it should match the value in sha1-file.c.
+
+For example, the following lines map the key "rawsz" to "20" if SHA-1 is in use
+and to "32" if SHA-256 is in use:
+
+----
+rawsz sha1:20
+rawsz sha256:32
+----
+
+The keys and values used here are loaded by `test_oid_init` (see the README file
+in the "t" directory) and are used by calling `test_oid`.
diff --git a/t/oid-info/hash-info b/t/oid-info/hash-info
new file mode 100644 (file)
index 0000000..ccdbfdf
--- /dev/null
@@ -0,0 +1,8 @@
+rawsz sha1:20
+rawsz sha256:32
+
+hexsz sha1:40
+hexsz sha256:64
+
+zero sha1:0000000000000000000000000000000000000000
+zero sha256:0000000000000000000000000000000000000000000000000000000000000000
diff --git a/t/oid-info/oid b/t/oid-info/oid
new file mode 100644 (file)
index 0000000..a754970
--- /dev/null
@@ -0,0 +1,29 @@
+# These are some common invalid and partial object IDs used in tests.
+001    sha1:0000000000000000000000000000000000000001
+001    sha256:0000000000000000000000000000000000000000000000000000000000000001
+002    sha1:0000000000000000000000000000000000000002
+002    sha256:0000000000000000000000000000000000000000000000000000000000000002
+003    sha1:0000000000000000000000000000000000000003
+003    sha256:0000000000000000000000000000000000000000000000000000000000000003
+004    sha1:0000000000000000000000000000000000000004
+004    sha256:0000000000000000000000000000000000000000000000000000000000000004
+005    sha1:0000000000000000000000000000000000000005
+005    sha256:0000000000000000000000000000000000000000000000000000000000000005
+006    sha1:0000000000000000000000000000000000000006
+006    sha256:0000000000000000000000000000000000000000000000000000000000000006
+007    sha1:0000000000000000000000000000000000000007
+007    sha256:0000000000000000000000000000000000000000000000000000000000000007
+# All zeros or Fs missing one or two hex segments.
+zero_1         sha1:000000000000000000000000000000000000000
+zero_1         sha256:000000000000000000000000000000000000000000000000000000000000000
+zero_2         sha1:00000000000000000000000000000000000000
+zero_2         sha256:00000000000000000000000000000000000000000000000000000000000000
+ff_1           sha1:fffffffffffffffffffffffffffffffffffffff
+ff_1           sha256:fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ff_2           sha1:ffffffffffffffffffffffffffffffffffffff
+ff_2           sha256:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+# More various invalid OIDs.
+numeric                sha1:0123456789012345678901234567890123456789
+numeric                sha256:0123456789012345678901234567890123456789012345678901234567890123
+deadbeef       sha1:deadbeefdeadbeefdeadbeefdeadbeefdeadbeef
+deadbeef       sha256:deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef
diff --git a/t/perf/p1450-fsck.sh b/t/perf/p1450-fsck.sh
new file mode 100755 (executable)
index 0000000..ae1b841
--- /dev/null
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+test_description='Test fsck performance'
+
+. ./perf-lib.sh
+
+test_perf_large_repo
+
+test_perf 'fsck' '
+       git fsck
+'
+
+test_done
diff --git a/t/perf/p1451-fsck-skip-list.sh b/t/perf/p1451-fsck-skip-list.sh
new file mode 100755 (executable)
index 0000000..c2b97d2
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+test_description='Test fsck skipList performance'
+
+. ./perf-lib.sh
+
+test_perf_fresh_repo
+
+n=1000000
+
+test_expect_success "setup $n bad commits" '
+       for i in $(test_seq 1 $n)
+       do
+               echo "commit refs/heads/master" &&
+               echo "committer C <c@example.com> 1234567890 +0000" &&
+               echo "data <<EOF" &&
+               echo "$i.Q." &&
+               echo "EOF"
+       done | q_to_nul | git fast-import
+'
+
+skip=0
+while test $skip -le $n
+do
+       test_expect_success "create skipList for $skip bad commits" '
+               git log --format=%H --max-count=$skip |
+               sort >skiplist
+       '
+
+       test_perf "fsck with $skip skipped bad commits" '
+               git -c fsck.skipList=skiplist fsck
+       '
+
+       case $skip in
+       0) skip=1 ;;
+       *) skip=${skip}0 ;;
+       esac
+done
+
+test_done
index 850f651..26601e6 100755 (executable)
@@ -821,9 +821,87 @@ test_expect_success 'tests clean up even on failures' "
        EOF
 "
 
+test_expect_success 'test_oid setup' '
+       test_oid_init
+'
+
+test_expect_success 'test_oid provides sane info by default' '
+       test_oid zero >actual &&
+       grep "^00*\$" actual &&
+       rawsz="$(test_oid rawsz)" &&
+       hexsz="$(test_oid hexsz)" &&
+       test "$hexsz" -eq $(wc -c <actual) &&
+       test $(( $rawsz * 2)) -eq "$hexsz"
+'
+
+test_expect_success 'test_oid can look up data for SHA-1' '
+       test_when_finished "test_detect_hash" &&
+       test_set_hash sha1 &&
+       test_oid zero >actual &&
+       grep "^00*\$" actual &&
+       rawsz="$(test_oid rawsz)" &&
+       hexsz="$(test_oid hexsz)" &&
+       test $(wc -c <actual) -eq 40 &&
+       test "$rawsz" -eq 20 &&
+       test "$hexsz" -eq 40
+'
+
+test_expect_success 'test_oid can look up data for SHA-256' '
+       test_when_finished "test_detect_hash" &&
+       test_set_hash sha256 &&
+       test_oid zero >actual &&
+       grep "^00*\$" actual &&
+       rawsz="$(test_oid rawsz)" &&
+       hexsz="$(test_oid hexsz)" &&
+       test $(wc -c <actual) -eq 64 &&
+       test "$rawsz" -eq 32 &&
+       test "$hexsz" -eq 64
+'
+
 ################################################################
 # Basics of the basics
 
+test_oid_cache <<\EOF
+path0f sha1:f87290f8eb2cbbea7857214459a0739927eab154
+path0f sha256:638106af7c38be056f3212cbd7ac65bc1bac74f420ca5a436ff006a9d025d17d
+
+path0s sha1:15a98433ae33114b085f3eb3bb03b832b3180a01
+path0s sha256:3a24cc53cf68edddac490bbf94a418a52932130541361f685df685e41dd6c363
+
+path2f sha1:3feff949ed00a62d9f7af97c15cd8a30595e7ac7
+path2f sha256:2a7f36571c6fdbaf0e3f62751a0b25a3f4c54d2d1137b3f4af9cb794bb498e5f
+
+path2s sha1:d8ce161addc5173867a3c3c730924388daedbc38
+path2s sha256:18fd611b787c2e938ddcc248fabe4d66a150f9364763e9ec133dd01d5bb7c65a
+
+path2d sha1:58a09c23e2ca152193f2786e06986b7b6712bdbe
+path2d sha256:00e4b32b96e7e3d65d79112dcbea53238a22715f896933a62b811377e2650c17
+
+path3f sha1:0aa34cae68d0878578ad119c86ca2b5ed5b28376
+path3f sha256:09f58616b951bd571b8cb9dc76d372fbb09ab99db2393f5ab3189d26c45099ad
+
+path3s sha1:8599103969b43aff7e430efea79ca4636466794f
+path3s sha256:fce1aed087c053306f3f74c32c1a838c662bbc4551a7ac2420f5d6eb061374d0
+
+path3d sha1:21ae8269cacbe57ae09138dcc3a2887f904d02b3
+path3d sha256:9b60497be959cb830bf3f0dc82bcc9ad9e925a24e480837ade46b2295e47efe1
+
+subp3f sha1:00fb5908cb97c2564a9783c0c64087333b3b464f
+subp3f sha256:a1a9e16998c988453f18313d10375ee1d0ddefe757e710dcae0d66aa1e0c58b3
+
+subp3s sha1:6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c
+subp3s sha256:81759d9f5e93c6546ecfcadb560c1ff057314b09f93fe8ec06e2d8610d34ef10
+
+subp3d sha1:3c5e5399f3a333eddecce7a9b9465b63f65f51e2
+subp3d sha256:76b4ef482d4fa1c754390344cf3851c7f883b27cf9bc999c6547928c46aeafb7
+
+root sha1:087704a96baf1c2d1c869a8b084481e121c88b5b
+root sha256:9481b52abab1b2ffeedbf9de63ce422b929f179c1b98ff7bee5f8f1bc0710751
+
+simpletree sha1:7bb943559a305bdd6bdee2cef6e5df2413c3d30a
+simpletree sha256:1710c07a6c86f9a3c7376364df04c47ee39e5a5e221fcdd84b743bc9bb7e2bc5
+EOF
+
 # updating a new file without --add should fail.
 test_expect_success 'git update-index without --add should fail adding' '
        test_must_fail git update-index should-be-empty
@@ -839,8 +917,8 @@ test_expect_success 'writing tree out with git write-tree' '
 '
 
 # we know the shape and contents of the tree and know the object ID for it.
-test_expect_success SHA1 'validate object ID of a known tree' '
-       test "$tree" = 7bb943559a305bdd6bdee2cef6e5df2413c3d30a
+test_expect_success 'validate object ID of a known tree' '
+       test "$tree" = "$(test_oid simpletree)"
     '
 
 # Removing paths.
@@ -882,16 +960,16 @@ test_expect_success 'showing stage with git ls-files --stage' '
        git ls-files --stage >current
 '
 
-test_expect_success SHA1 'validate git ls-files output for a known tree' '
-       cat >expected <<-\EOF &&
-       100644 f87290f8eb2cbbea7857214459a0739927eab154 0       path0
-       120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0       path0sym
-       100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0       path2/file2
-       120000 d8ce161addc5173867a3c3c730924388daedbc38 0       path2/file2sym
-       100644 0aa34cae68d0878578ad119c86ca2b5ed5b28376 0       path3/file3
-       120000 8599103969b43aff7e430efea79ca4636466794f 0       path3/file3sym
-       100644 00fb5908cb97c2564a9783c0c64087333b3b464f 0       path3/subp3/file3
-       120000 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c 0       path3/subp3/file3sym
+test_expect_success 'validate git ls-files output for a known tree' '
+       cat >expected <<-EOF &&
+       100644 $(test_oid path0f) 0     path0
+       120000 $(test_oid path0s) 0     path0sym
+       100644 $(test_oid path2f) 0     path2/file2
+       120000 $(test_oid path2s) 0     path2/file2sym
+       100644 $(test_oid path3f) 0     path3/file3
+       120000 $(test_oid path3s) 0     path3/file3sym
+       100644 $(test_oid subp3f) 0     path3/subp3/file3
+       120000 $(test_oid subp3s) 0     path3/subp3/file3sym
        EOF
        test_cmp expected current
 '
@@ -900,20 +978,20 @@ test_expect_success 'writing tree out with git write-tree' '
        tree=$(git write-tree)
 '
 
-test_expect_success SHA1 'validate object ID for a known tree' '
-       test "$tree" = 087704a96baf1c2d1c869a8b084481e121c88b5b
+test_expect_success 'validate object ID for a known tree' '
+       test "$tree" = "$(test_oid root)"
 '
 
 test_expect_success 'showing tree with git ls-tree' '
     git ls-tree $tree >current
 '
 
-test_expect_success SHA1 'git ls-tree output for a known tree' '
-       cat >expected <<-\EOF &&
-       100644 blob f87290f8eb2cbbea7857214459a0739927eab154    path0
-       120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01    path0sym
-       040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe    path2
-       040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3    path3
+test_expect_success 'git ls-tree output for a known tree' '
+       cat >expected <<-EOF &&
+       100644 blob $(test_oid path0f)  path0
+       120000 blob $(test_oid path0s)  path0sym
+       040000 tree $(test_oid path2d)  path2
+       040000 tree $(test_oid path3d)  path3
        EOF
        test_cmp expected current
 '
@@ -924,16 +1002,16 @@ test_expect_success 'showing tree with git ls-tree -r' '
        git ls-tree -r $tree >current
 '
 
-test_expect_success SHA1 'git ls-tree -r output for a known tree' '
-       cat >expected <<-\EOF &&
-       100644 blob f87290f8eb2cbbea7857214459a0739927eab154    path0
-       120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01    path0sym
-       100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7    path2/file2
-       120000 blob d8ce161addc5173867a3c3c730924388daedbc38    path2/file2sym
-       100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376    path3/file3
-       120000 blob 8599103969b43aff7e430efea79ca4636466794f    path3/file3sym
-       100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f    path3/subp3/file3
-       120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c    path3/subp3/file3sym
+test_expect_success 'git ls-tree -r output for a known tree' '
+       cat >expected <<-EOF &&
+       100644 blob $(test_oid path0f)  path0
+       120000 blob $(test_oid path0s)  path0sym
+       100644 blob $(test_oid path2f)  path2/file2
+       120000 blob $(test_oid path2s)  path2/file2sym
+       100644 blob $(test_oid path3f)  path3/file3
+       120000 blob $(test_oid path3s)  path3/file3sym
+       100644 blob $(test_oid subp3f)  path3/subp3/file3
+       120000 blob $(test_oid subp3s)  path3/subp3/file3sym
        EOF
        test_cmp expected current
 '
@@ -943,19 +1021,19 @@ test_expect_success 'showing tree with git ls-tree -r -t' '
        git ls-tree -r -t $tree >current
 '
 
-test_expect_success SHA1 'git ls-tree -r output for a known tree' '
-       cat >expected <<-\EOF &&
-       100644 blob f87290f8eb2cbbea7857214459a0739927eab154    path0
-       120000 blob 15a98433ae33114b085f3eb3bb03b832b3180a01    path0sym
-       040000 tree 58a09c23e2ca152193f2786e06986b7b6712bdbe    path2
-       100644 blob 3feff949ed00a62d9f7af97c15cd8a30595e7ac7    path2/file2
-       120000 blob d8ce161addc5173867a3c3c730924388daedbc38    path2/file2sym
-       040000 tree 21ae8269cacbe57ae09138dcc3a2887f904d02b3    path3
-       100644 blob 0aa34cae68d0878578ad119c86ca2b5ed5b28376    path3/file3
-       120000 blob 8599103969b43aff7e430efea79ca4636466794f    path3/file3sym
-       040000 tree 3c5e5399f3a333eddecce7a9b9465b63f65f51e2    path3/subp3
-       100644 blob 00fb5908cb97c2564a9783c0c64087333b3b464f    path3/subp3/file3
-       120000 blob 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c    path3/subp3/file3sym
+test_expect_success 'git ls-tree -r output for a known tree' '
+       cat >expected <<-EOF &&
+       100644 blob $(test_oid path0f)  path0
+       120000 blob $(test_oid path0s)  path0sym
+       040000 tree $(test_oid path2d)  path2
+       100644 blob $(test_oid path2f)  path2/file2
+       120000 blob $(test_oid path2s)  path2/file2sym
+       040000 tree $(test_oid path3d)  path3
+       100644 blob $(test_oid path3f)  path3/file3
+       120000 blob $(test_oid path3s)  path3/file3sym
+       040000 tree $(test_oid subp3d)  path3/subp3
+       100644 blob $(test_oid subp3f)  path3/subp3/file3
+       120000 blob $(test_oid subp3s)  path3/subp3/file3sym
        EOF
        test_cmp expected current
 '
@@ -964,26 +1042,27 @@ test_expect_success 'writing partial tree out with git write-tree --prefix' '
        ptree=$(git write-tree --prefix=path3)
 '
 
-test_expect_success SHA1 'validate object ID for a known tree' '
-       test "$ptree" = 21ae8269cacbe57ae09138dcc3a2887f904d02b3
+test_expect_success 'validate object ID for a known tree' '
+       test "$ptree" = $(test_oid path3d)
 '
 
 test_expect_success 'writing partial tree out with git write-tree --prefix' '
        ptree=$(git write-tree --prefix=path3/subp3)
 '
 
-test_expect_success SHA1 'validate object ID for a known tree' '
-       test "$ptree" = 3c5e5399f3a333eddecce7a9b9465b63f65f51e2
+test_expect_success 'validate object ID for a known tree' '
+       test "$ptree" = $(test_oid subp3d)
 '
 
 test_expect_success 'put invalid objects into the index' '
        rm -f .git/index &&
-       cat >badobjects <<-\EOF &&
-       100644 blob 1000000000000000000000000000000000000000    dir/file1
-       100644 blob 2000000000000000000000000000000000000000    dir/file2
-       100644 blob 3000000000000000000000000000000000000000    dir/file3
-       100644 blob 4000000000000000000000000000000000000000    dir/file4
-       100644 blob 5000000000000000000000000000000000000000    dir/file5
+       suffix=$(echo $ZERO_OID | sed -e "s/^.//") &&
+       cat >badobjects <<-EOF &&
+       100644 blob $(test_oid 001)     dir/file1
+       100644 blob $(test_oid 002)     dir/file2
+       100644 blob $(test_oid 003)     dir/file3
+       100644 blob $(test_oid 004)     dir/file4
+       100644 blob $(test_oid 005)     dir/file5
        EOF
        git update-index --index-info <badobjects
 '
@@ -1006,19 +1085,19 @@ test_expect_success 'git read-tree followed by write-tree should be idempotent'
        test "$newtree" = "$tree"
 '
 
-test_expect_success SHA1 'validate git diff-files output for a know cache/work tree state' '
-       cat >expected <<\EOF &&
-:100644 100644 f87290f8eb2cbbea7857214459a0739927eab154 0000000000000000000000000000000000000000 M     path0
-:120000 120000 15a98433ae33114b085f3eb3bb03b832b3180a01 0000000000000000000000000000000000000000 M     path0sym
-:100644 100644 3feff949ed00a62d9f7af97c15cd8a30595e7ac7 0000000000000000000000000000000000000000 M     path2/file2
-:120000 120000 d8ce161addc5173867a3c3c730924388daedbc38 0000000000000000000000000000000000000000 M     path2/file2sym
-:100644 100644 0aa34cae68d0878578ad119c86ca2b5ed5b28376 0000000000000000000000000000000000000000 M     path3/file3
-:120000 120000 8599103969b43aff7e430efea79ca4636466794f 0000000000000000000000000000000000000000 M     path3/file3sym
-:100644 100644 00fb5908cb97c2564a9783c0c64087333b3b464f 0000000000000000000000000000000000000000 M     path3/subp3/file3
-:120000 120000 6649a1ebe9e9f1c553b66f5a6e74136a07ccc57c 0000000000000000000000000000000000000000 M     path3/subp3/file3sym
+test_expect_success 'validate git diff-files output for a know cache/work tree state' '
+       cat >expected <<EOF &&
+:100644 100644 $(test_oid path0f) $ZERO_OID M  path0
+:120000 120000 $(test_oid path0s) $ZERO_OID M  path0sym
+:100644 100644 $(test_oid path2f) $ZERO_OID M  path2/file2
+:120000 120000 $(test_oid path2s) $ZERO_OID M  path2/file2sym
+:100644 100644 $(test_oid path3f) $ZERO_OID M  path3/file3
+:120000 120000 $(test_oid path3s) $ZERO_OID M  path3/file3sym
+:100644 100644 $(test_oid subp3f) $ZERO_OID M  path3/subp3/file3
+:120000 120000 $(test_oid subp3s) $ZERO_OID M  path3/subp3/file3sym
 EOF
        git diff-files >current &&
-       test_cmp current expected
+       test_cmp expected current
 '
 
 test_expect_success 'git update-index --refresh should succeed' '
@@ -1031,23 +1110,23 @@ test_expect_success 'no diff after checkout and git update-index --refresh' '
 '
 
 ################################################################
-P=087704a96baf1c2d1c869a8b084481e121c88b5b
+P=$(test_oid root)
 
-test_expect_success SHA1 'git commit-tree records the correct tree in a commit' '
+test_expect_success 'git commit-tree records the correct tree in a commit' '
        commit0=$(echo NO | git commit-tree $P) &&
        tree=$(git show --pretty=raw $commit0 |
                 sed -n -e "s/^tree //p" -e "/^author /q") &&
        test "z$tree" = "z$P"
 '
 
-test_expect_success SHA1 'git commit-tree records the correct parent in a commit' '
+test_expect_success 'git commit-tree records the correct parent in a commit' '
        commit1=$(echo NO | git commit-tree $P -p $commit0) &&
        parent=$(git show --pretty=raw $commit1 |
                sed -n -e "s/^parent //p" -e "/^author /q") &&
        test "z$commit0" = "z$parent"
 '
 
-test_expect_success SHA1 'git commit-tree omits duplicated parent in a commit' '
+test_expect_success 'git commit-tree omits duplicated parent in a commit' '
        commit2=$(echo NO | git commit-tree $P -p $commit0 -p $commit0) &&
             parent=$(git show --pretty=raw $commit2 |
                sed -n -e "s/^parent //p" -e "/^author /q" |
index 3691023..0aa9908 100755 (executable)
@@ -92,11 +92,12 @@ test_expect_success 'enter_repo non-strict mode' '
                mv .git .realgit &&
                echo "gitdir: .realgit" >.git
        ) &&
+       head=$(git -C enter_repo rev-parse HEAD) &&
        git ls-remote enter_repo >actual &&
-       cat >expected <<-\EOF &&
-       946e985ab20de757ca5b872b16d64e92ff3803a9        HEAD
-       946e985ab20de757ca5b872b16d64e92ff3803a9        refs/heads/master
-       946e985ab20de757ca5b872b16d64e92ff3803a9        refs/tags/foo
+       cat >expected <<-EOF &&
+       $head   HEAD
+       $head   refs/heads/master
+       $head   refs/tags/foo
        EOF
        test_cmp expected actual
 '
@@ -106,21 +107,23 @@ test_expect_success 'enter_repo linked checkout' '
                cd enter_repo &&
                git worktree add  ../foo refs/tags/foo
        ) &&
+       head=$(git -C enter_repo rev-parse HEAD) &&
        git ls-remote foo >actual &&
-       cat >expected <<-\EOF &&
-       946e985ab20de757ca5b872b16d64e92ff3803a9        HEAD
-       946e985ab20de757ca5b872b16d64e92ff3803a9        refs/heads/master
-       946e985ab20de757ca5b872b16d64e92ff3803a9        refs/tags/foo
+       cat >expected <<-EOF &&
+       $head   HEAD
+       $head   refs/heads/master
+       $head   refs/tags/foo
        EOF
        test_cmp expected actual
 '
 
 test_expect_success 'enter_repo strict mode' '
+       head=$(git -C enter_repo rev-parse HEAD) &&
        git ls-remote --upload-pack="git upload-pack --strict" foo/.git >actual &&
-       cat >expected <<-\EOF &&
-       946e985ab20de757ca5b872b16d64e92ff3803a9        HEAD
-       946e985ab20de757ca5b872b16d64e92ff3803a9        refs/heads/master
-       946e985ab20de757ca5b872b16d64e92ff3803a9        refs/tags/foo
+       cat >expected <<-EOF &&
+       $head   HEAD
+       $head   refs/heads/master
+       $head   refs/tags/foo
        EOF
        test_cmp expected actual
 '
diff --git a/t/t0014-alias.sh b/t/t0014-alias.sh
new file mode 100755 (executable)
index 0000000..a070e64
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+test_description='git command aliasing'
+
+. ./test-lib.sh
+
+test_expect_success 'nested aliases - internal execution' '
+       git config alias.nested-internal-1 nested-internal-2 &&
+       git config alias.nested-internal-2 status &&
+       git nested-internal-1 >output &&
+       test_i18ngrep "^On branch " output
+'
+
+test_expect_success 'nested aliases - mixed execution' '
+       git config alias.nested-external-1 nested-external-2 &&
+       git config alias.nested-external-2 "!git nested-external-3" &&
+       git config alias.nested-external-3 status &&
+       git nested-external-1 >output &&
+       test_i18ngrep "^On branch " output
+'
+
+test_expect_success 'looping aliases - internal execution' '
+       git config alias.loop-internal-1 loop-internal-2 &&
+       git config alias.loop-internal-2 loop-internal-3 &&
+       git config alias.loop-internal-3 loop-internal-2 &&
+       test_must_fail git loop-internal-1 2>output &&
+       test_i18ngrep "^fatal: alias loop detected: expansion of" output
+'
+
+# This test is disabled until external loops are fixed, because would block
+# the test suite for a full minute.
+#
+#test_expect_failure 'looping aliases - mixed execution' '
+#      git config alias.loop-mixed-1 loop-mixed-2 &&
+#      git config alias.loop-mixed-2 "!git loop-mixed-1" &&
+#      test_must_fail git loop-mixed-1 2>output &&
+#      test_i18ngrep "^fatal: alias loop detected: expansion of" output
+#'
+
+test_done
index 308cd28..fd5f1ac 100755 (executable)
@@ -166,10 +166,10 @@ test_expect_success expanded_in_repo '
        rm -f expanded-keywords expanded-keywords-crlf &&
 
        git checkout -- expanded-keywords &&
-       test_cmp expanded-keywords expected-output &&
+       test_cmp expected-output expanded-keywords &&
 
        git checkout -- expanded-keywords-crlf &&
-       test_cmp expanded-keywords-crlf expected-output-crlf
+       test_cmp expected-output-crlf expanded-keywords-crlf
 '
 
 # The use of %f in a filter definition is expanded to the path to
index 5b0560f..17d0c18 100755 (executable)
@@ -8,7 +8,7 @@ test_description='our own option parser'
 . ./test-lib.sh
 
 cat >expect <<\EOF
-usage: test-parse-options <options>
+usage: test-tool parse-options <options>
 
     A helper function for the parse-options API.
 
@@ -52,7 +52,7 @@ Standard options
 EOF
 
 test_expect_success 'test help' '
-       test_must_fail test-parse-options -h >output 2>output.err &&
+       test_must_fail test-tool parse-options -h >output 2>output.err &&
        test_must_be_empty output.err &&
        test_i18ncmp expect output
 '
@@ -64,7 +64,7 @@ check () {
        shift &&
        expect="$1" &&
        shift &&
-       test-parse-options --expect="$what $expect" "$@"
+       test-tool parse-options --expect="$what $expect" "$@"
 }
 
 check_unknown_i18n() {
@@ -75,7 +75,7 @@ check_unknown_i18n() {
                echo error: unknown switch \`${1#-}\' >expect ;;
        esac &&
        cat expect.err >>expect &&
-       test_must_fail test-parse-options $* >output 2>output.err &&
+       test_must_fail test-tool parse-options $* >output 2>output.err &&
        test_must_be_empty output &&
        test_i18ncmp expect output.err
 }
@@ -133,7 +133,7 @@ file: prefix/my.file
 EOF
 
 test_expect_success 'short options' '
-       test-parse-options -s123 -b -i 1729 -m 16k -b -vv -n -F my.file \
+       test-tool parse-options -s123 -b -i 1729 -m 16k -b -vv -n -F my.file \
        >output 2>output.err &&
        test_cmp expect output &&
        test_must_be_empty output.err
@@ -153,7 +153,7 @@ file: prefix/fi.le
 EOF
 
 test_expect_success 'long options' '
-       test-parse-options --boolean --integer 1729 --magnitude 16k \
+       test-tool parse-options --boolean --integer 1729 --magnitude 16k \
                --boolean --string2=321 --verbose --verbose --no-dry-run \
                --abbrev=10 --file fi.le --obsolete \
                >output 2>output.err &&
@@ -162,9 +162,9 @@ test_expect_success 'long options' '
 '
 
 test_expect_success 'missing required value' '
-       test_expect_code 129 test-parse-options -s &&
-       test_expect_code 129 test-parse-options --string &&
-       test_expect_code 129 test-parse-options --file
+       test_expect_code 129 test-tool parse-options -s &&
+       test_expect_code 129 test-tool parse-options --string &&
+       test_expect_code 129 test-tool parse-options --file
 '
 
 cat >expect <<\EOF
@@ -184,7 +184,7 @@ arg 02: --boolean
 EOF
 
 test_expect_success 'intermingled arguments' '
-       test-parse-options a1 --string 123 b1 --boolean -j 13 -- --boolean \
+       test-tool parse-options a1 --string 123 b1 --boolean -j 13 -- --boolean \
                >output 2>output.err &&
        test_must_be_empty output.err &&
        test_cmp expect output
@@ -204,21 +204,21 @@ file: (not set)
 EOF
 
 test_expect_success 'unambiguously abbreviated option' '
-       test-parse-options --int 2 --boolean --no-bo >output 2>output.err &&
+       test-tool parse-options --int 2 --boolean --no-bo >output 2>output.err &&
        test_must_be_empty output.err &&
        test_cmp expect output
 '
 
 test_expect_success 'unambiguously abbreviated option with "="' '
-       test-parse-options --expect="integer: 2" --int=2
+       test-tool parse-options --expect="integer: 2" --int=2
 '
 
 test_expect_success 'ambiguously abbreviated option' '
-       test_expect_code 129 test-parse-options --strin 123
+       test_expect_code 129 test-tool parse-options --strin 123
 '
 
 test_expect_success 'non ambiguous option (after two options it abbreviates)' '
-       test-parse-options --expect="string: 123" --st 123
+       test-tool parse-options --expect="string: 123" --st 123
 '
 
 cat >typo.err <<\EOF
@@ -226,7 +226,7 @@ error: did you mean `--boolean` (with two dashes ?)
 EOF
 
 test_expect_success 'detect possible typos' '
-       test_must_fail test-parse-options -boolean >output 2>output.err &&
+       test_must_fail test-tool parse-options -boolean >output 2>output.err &&
        test_must_be_empty output &&
        test_cmp typo.err output.err
 '
@@ -236,13 +236,13 @@ error: did you mean `--ambiguous` (with two dashes ?)
 EOF
 
 test_expect_success 'detect possible typos' '
-       test_must_fail test-parse-options -ambiguous >output 2>output.err &&
+       test_must_fail test-tool parse-options -ambiguous >output 2>output.err &&
        test_must_be_empty output &&
        test_cmp typo.err output.err
 '
 
 test_expect_success 'keep some options as arguments' '
-       test-parse-options --expect="arg 00: --quux" --quux
+       test-tool parse-options --expect="arg 00: --quux" --quux
 '
 
 cat >expect <<\EOF
@@ -260,7 +260,7 @@ arg 00: foo
 EOF
 
 test_expect_success 'OPT_DATE() works' '
-       test-parse-options -t "1970-01-01 00:00:01 +0000" \
+       test-tool parse-options -t "1970-01-01 00:00:01 +0000" \
                foo -q >output 2>output.err &&
        test_must_be_empty output.err &&
        test_cmp expect output
@@ -281,13 +281,13 @@ file: (not set)
 EOF
 
 test_expect_success 'OPT_CALLBACK() and OPT_BIT() work' '
-       test-parse-options --length=four -b -4 >output 2>output.err &&
+       test-tool parse-options --length=four -b -4 >output 2>output.err &&
        test_must_be_empty output.err &&
        test_cmp expect output
 '
 
 test_expect_success 'OPT_CALLBACK() and callback errors work' '
-       test_must_fail test-parse-options --no-length >output 2>output.err &&
+       test_must_fail test-tool parse-options --no-length >output 2>output.err &&
        test_must_be_empty output &&
        test_must_be_empty output.err
 '
@@ -306,31 +306,31 @@ file: (not set)
 EOF
 
 test_expect_success 'OPT_BIT() and OPT_SET_INT() work' '
-       test-parse-options --set23 -bbbbb --no-or4 >output 2>output.err &&
+       test-tool parse-options --set23 -bbbbb --no-or4 >output 2>output.err &&
        test_must_be_empty output.err &&
        test_cmp expect output
 '
 
 test_expect_success 'OPT_NEGBIT() and OPT_SET_INT() work' '
-       test-parse-options --set23 -bbbbb --neg-or4 >output 2>output.err &&
+       test-tool parse-options --set23 -bbbbb --neg-or4 >output 2>output.err &&
        test_must_be_empty output.err &&
        test_cmp expect output
 '
 
 test_expect_success 'OPT_BIT() works' '
-       test-parse-options --expect="boolean: 6" -bb --or4
+       test-tool parse-options --expect="boolean: 6" -bb --or4
 '
 
 test_expect_success 'OPT_NEGBIT() works' '
-       test-parse-options --expect="boolean: 6" -bb --no-neg-or4
+       test-tool parse-options --expect="boolean: 6" -bb --no-neg-or4
 '
 
 test_expect_success 'OPT_COUNTUP() with PARSE_OPT_NODASH works' '
-       test-parse-options --expect="boolean: 6" + + + + + +
+       test-tool parse-options --expect="boolean: 6" + + + + + +
 '
 
 test_expect_success 'OPT_NUMBER_CALLBACK() works' '
-       test-parse-options --expect="integer: 12345" -12345
+       test-tool parse-options --expect="integer: 12345" -12345
 '
 
 cat >expect <<\EOF
@@ -347,7 +347,7 @@ file: (not set)
 EOF
 
 test_expect_success 'negation of OPT_NONEG flags is not ambiguous' '
-       test-parse-options --no-ambig >output 2>output.err &&
+       test-tool parse-options --no-ambig >output 2>output.err &&
        test_must_be_empty output.err &&
        test_cmp expect output
 '
@@ -358,38 +358,38 @@ list: bar
 list: baz
 EOF
 test_expect_success '--list keeps list of strings' '
-       test-parse-options --list foo --list=bar --list=baz >output &&
+       test-tool parse-options --list foo --list=bar --list=baz >output &&
        test_cmp expect output
 '
 
 test_expect_success '--no-list resets list' '
-       test-parse-options --list=other --list=irrelevant --list=options \
+       test-tool parse-options --list=other --list=irrelevant --list=options \
                --no-list --list=foo --list=bar --list=baz >output &&
        test_cmp expect output
 '
 
 test_expect_success 'multiple quiet levels' '
-       test-parse-options --expect="quiet: 3" -q -q -q
+       test-tool parse-options --expect="quiet: 3" -q -q -q
 '
 
 test_expect_success 'multiple verbose levels' '
-       test-parse-options --expect="verbose: 3" -v -v -v
+       test-tool parse-options --expect="verbose: 3" -v -v -v
 '
 
 test_expect_success '--no-quiet sets --quiet to 0' '
-       test-parse-options --expect="quiet: 0" --no-quiet
+       test-tool parse-options --expect="quiet: 0" --no-quiet
 '
 
 test_expect_success '--no-quiet resets multiple -q to 0' '
-       test-parse-options --expect="quiet: 0" -q -q -q --no-quiet
+       test-tool parse-options --expect="quiet: 0" -q -q -q --no-quiet
 '
 
 test_expect_success '--no-verbose sets verbose to 0' '
-       test-parse-options --expect="verbose: 0" --no-verbose
+       test-tool parse-options --expect="verbose: 0" --no-verbose
 '
 
 test_expect_success '--no-verbose resets multiple verbose to 0' '
-       test-parse-options --expect="verbose: 0" -v -v -v --no-verbose
+       test-tool parse-options --expect="verbose: 0" -v -v -v --no-verbose
 '
 
 test_done
index 6748450..5dda570 100755 (executable)
@@ -3,30 +3,30 @@
 test_description='basic tests for the SHA1 array implementation'
 . ./test-lib.sh
 
-echo20 () {
+echoid () {
        prefix="${1:+$1 }"
        shift
        while test $# -gt 0
        do
-               echo "$prefix$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1$1"
+               echo "$prefix$ZERO_OID" | sed -e "s/00/$1/g"
                shift
        done
 }
 
 test_expect_success 'ordered enumeration' '
-       echo20 "" 44 55 88 aa >expect &&
+       echoid "" 44 55 88 aa >expect &&
        {
-               echo20 append 88 44 aa 55 &&
+               echoid append 88 44 aa 55 &&
                echo for_each_unique
        } | test-tool sha1-array >actual &&
        test_cmp expect actual
 '
 
 test_expect_success 'ordered enumeration with duplicate suppression' '
-       echo20 "" 44 55 88 aa >expect &&
+       echoid "" 44 55 88 aa >expect &&
        {
-               echo20 append 88 44 aa 55 &&
-               echo20 append 88 44 aa 55 &&
+               echoid append 88 44 aa 55 &&
+               echoid append 88 44 aa 55 &&
                echo for_each_unique
        } | test-tool sha1-array >actual &&
        test_cmp expect actual
@@ -34,8 +34,8 @@ test_expect_success 'ordered enumeration with duplicate suppression' '
 
 test_expect_success 'lookup' '
        {
-               echo20 append 88 44 aa 55 &&
-               echo20 lookup 55
+               echoid append 88 44 aa 55 &&
+               echoid lookup 55
        } | test-tool sha1-array >actual &&
        n=$(cat actual) &&
        test "$n" -eq 1
@@ -43,8 +43,8 @@ test_expect_success 'lookup' '
 
 test_expect_success 'lookup non-existing entry' '
        {
-               echo20 append 88 44 aa 55 &&
-               echo20 lookup 33
+               echoid append 88 44 aa 55 &&
+               echoid lookup 33
        } | test-tool sha1-array >actual &&
        n=$(cat actual) &&
        test "$n" -lt 0
@@ -52,9 +52,9 @@ test_expect_success 'lookup non-existing entry' '
 
 test_expect_success 'lookup with duplicates' '
        {
-               echo20 append 88 44 aa 55 &&
-               echo20 append 88 44 aa 55 &&
-               echo20 lookup 55
+               echoid append 88 44 aa 55 &&
+               echoid append 88 44 aa 55 &&
+               echoid lookup 55
        } | test-tool sha1-array >actual &&
        n=$(cat actual) &&
        test "$n" -ge 2 &&
@@ -63,19 +63,24 @@ test_expect_success 'lookup with duplicates' '
 
 test_expect_success 'lookup non-existing entry with duplicates' '
        {
-               echo20 append 88 44 aa 55 &&
-               echo20 append 88 44 aa 55 &&
-               echo20 lookup 66
+               echoid append 88 44 aa 55 &&
+               echoid append 88 44 aa 55 &&
+               echoid lookup 66
        } | test-tool sha1-array >actual &&
        n=$(cat actual) &&
        test "$n" -lt 0
 '
 
 test_expect_success 'lookup with almost duplicate values' '
+       # n-1 5s
+       root=$(echoid "" 55) &&
+       root=${root%5} &&
        {
-               echo "append 5555555555555555555555555555555555555555" &&
-               echo "append 555555555555555555555555555555555555555f" &&
-               echo20 lookup 55
+               id1="${root}5" &&
+               id2="${root}f" &&
+               echo "append $id1" &&
+               echo "append $id2" &&
+               echoid lookup 55
        } | test-tool sha1-array >actual &&
        n=$(cat actual) &&
        test "$n" -eq 0
@@ -83,8 +88,8 @@ test_expect_success 'lookup with almost duplicate values' '
 
 test_expect_success 'lookup with single duplicate value' '
        {
-               echo20 append 55 55 &&
-               echo20 lookup 55
+               echoid append 55 55 &&
+               echoid lookup 55
        } | test-tool sha1-array >actual &&
        n=$(cat actual) &&
        test "$n" -ge 0 &&
index 7f19d59..43c4be1 100755 (executable)
@@ -140,15 +140,17 @@ test_expect_success '--batch-check without %(rest) considers whole line' '
        test_cmp expect actual
 '
 
+test_oid_init
+
 tree_sha1=$(git write-tree)
-tree_size=33
+tree_size=$(($(test_oid rawsz) + 13))
 tree_pretty_content="100644 blob $hello_sha1   hello"
 
 run_tests 'tree' $tree_sha1 $tree_size "" "$tree_pretty_content"
 
 commit_message="Initial commit"
 commit_sha1=$(echo_without_newline "$commit_message" | git commit-tree $tree_sha1)
-commit_size=177
+commit_size=$(($(test_oid hexsz) + 137))
 commit_content="tree $tree_sha1
 author $GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> 0000000000 +0000
 committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 0000000000 +0000
@@ -218,8 +220,8 @@ test_expect_success "--batch-check for a non-existent hash" '
     test "0000000000000000000000000000000000000042 missing
 0000000000000000000000000000000000000084 missing" = \
     "$( ( echo 0000000000000000000000000000000000000042;
-         echo_without_newline 0000000000000000000000000000000000000084; ) \
-       git cat-file --batch-check)"
+        echo_without_newline 0000000000000000000000000000000000000084; ) |
+       git cat-file --batch-check)"
 '
 
 test_expect_success "--batch for an existent and a non-existent hash" '
@@ -227,8 +229,8 @@ test_expect_success "--batch for an existent and a non-existent hash" '
 $tag_content
 0000000000000000000000000000000000000000 missing" = \
     "$( ( echo $tag_sha1;
-         echo_without_newline 0000000000000000000000000000000000000000; ) \
-       git cat-file --batch)"
+        echo_without_newline 0000000000000000000000000000000000000000; ) |
+       git cat-file --batch)"
 '
 
 test_expect_success "--batch-check for an empty line" '
index cdf1fed..e2cd50e 100755 (executable)
@@ -1001,7 +1001,7 @@ EOF
 
 test_expect_success 'value continued on next line' '
        git config --list > result &&
-       test_cmp result expect
+       test_cmp expect result
 '
 
 cat > .git/config <<\EOF
@@ -1770,8 +1770,9 @@ test_expect_success '--show-origin stdin with file include' '
        cat >expect <<-EOF &&
                file:$INCLUDE_DIR/stdin.include include
        EOF
-       echo "[include]path=\"$INCLUDE_DIR\"/stdin.include" \
-               | git config --show-origin --includes --file - user.stdin >output &&
+       echo "[include]path=\"$INCLUDE_DIR\"/stdin.include" |
+       git config --show-origin --includes --file - user.stdin >output &&
+
        test_cmp expect output
 '
 
@@ -1881,7 +1882,7 @@ test_expect_success '--replace-all does not invent newlines' '
        Qkey = b
        EOF
        git config --replace-all abc.key b &&
-       test_cmp .git/config expect
+       test_cmp expect .git/config
 '
 
 test_done
index 3b92083..0000e66 100755 (executable)
@@ -14,7 +14,7 @@ setup() {
 check() {
        echo "$2" >expected
        git config --get "$1" >actual 2>&1
-       test_cmp actual expected
+       test_cmp expected actual
 }
 
 # 'check section.key regex value' verifies that the entry for
@@ -22,7 +22,7 @@ check() {
 check_regex() {
        echo "$3" >expected
        git config --get "$1" "$2" >actual 2>&1
-       test_cmp actual expected
+       test_cmp expected actual
 }
 
 test_expect_success 'modify same key' '
index 02493f1..1fbd940 100755 (executable)
@@ -346,7 +346,7 @@ test_expect_success "verifying $m's log (logged by config)" '
 
 git update-ref $m $D
 cat >.git/logs/$m <<EOF
-0000000000000000000000000000000000000000 $C $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150320 -0500
+$Z $C $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150320 -0500
 $C $A $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150350 -0500
 $A $B $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150380 -0500
 $F $Z $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> 1117150680 -0500
@@ -366,7 +366,7 @@ test_expect_success 'Query master@{2005-05-25} (before history)' '
        test_when_finished "rm -f o e" &&
        git rev-parse --verify master@{2005-05-25} >o 2>e &&
        test $C = $(cat o) &&
-       echo test "warning: Log for '\''master'\'' only goes back to $ed." = "$(cat e)"
+       test "warning: Log for '\''master'\'' only goes back to $ed." = "$(cat e)"
 '
 test_expect_success 'Query "master@{May 26 2005 23:31:59}" (1 second before history)' '
        test_when_finished "rm -f o e" &&
index a74c38b..331899d 100755 (executable)
@@ -54,7 +54,7 @@ test_expect_success 'for_each_ref(refs/heads/)' '
 '
 
 test_expect_success 'for_each_ref() is sorted' '
-       $RUN for-each-ref refs/heads/ | cut -c 42- >actual &&
+       $RUN for-each-ref refs/heads/ | cut -d" " -f 2- >actual &&
        sort actual > expected &&
        test_cmp expected actual
 '
@@ -71,7 +71,7 @@ test_expect_success 'verify_ref(new-master)' '
 '
 
 test_expect_success 'for_each_reflog()' '
-       $RUN for-each-reflog | sort -k2 | cut -c 42- >actual &&
+       $RUN for-each-reflog | sort -k2 | cut -d" " -f 2- >actual &&
        cat >expected <<-\EOF &&
        HEAD 0x1
        refs/heads/master 0x0
index e093782..d199d87 100755 (executable)
@@ -39,7 +39,7 @@ test_expect_success 'rename_refs() not allowed' '
 '
 
 test_expect_success 'for_each_ref(refs/heads/)' '
-       $RUN for-each-ref refs/heads/ | cut -c 42- >actual &&
+       $RUN for-each-ref refs/heads/ | cut -d" " -f 2- >actual &&
        cat >expected <<-\EOF &&
        master 0x0
        new-master 0x0
@@ -48,7 +48,7 @@ test_expect_success 'for_each_ref(refs/heads/)' '
 '
 
 test_expect_success 'for_each_ref() is sorted' '
-       $RUN for-each-ref refs/heads/ | cut -c 42- >actual &&
+       $RUN for-each-ref refs/heads/ | cut -d" " -f 2- >actual &&
        sort actual > expected &&
        test_cmp expected actual
 '
@@ -65,7 +65,7 @@ test_expect_success 'verify_ref(new-master)' '
 '
 
 test_expect_success 'for_each_reflog()' '
-       $RUN for-each-reflog | sort | cut -c 42- >actual &&
+       $RUN for-each-reflog | sort | cut -d" " -f 2- >actual &&
        cat >expected <<-\EOF &&
        HEAD 0x1
        refs/heads/master 0x0
index 4623ae1..9a84858 100755 (executable)
@@ -58,7 +58,7 @@ test_expect_success 'for_each_reflog()' '
        mkdir -p     .git/worktrees/wt/logs/refs/bisect &&
        echo $ZERO_OID > .git/worktrees/wt/logs/refs/bisect/wt-random &&
 
-       $RWT for-each-reflog | cut -c 42- | sort >actual &&
+       $RWT for-each-reflog | cut -d" " -f 2- | sort >actual &&
        cat >expected <<-\EOF &&
        HEAD 0x1
        PSEUDO-WT 0x0
@@ -68,7 +68,7 @@ test_expect_success 'for_each_reflog()' '
        EOF
        test_cmp expected actual &&
 
-       $RMAIN for-each-reflog | cut -c 42- | sort >actual &&
+       $RMAIN for-each-reflog | cut -d" " -f 2- | sort >actual &&
        cat >expected <<-\EOF &&
        HEAD 0x1
        PSEUDO-MAIN 0x0
index 685ec45..6c32d42 100755 (executable)
@@ -73,7 +73,7 @@ test_expect_success 'update-index --update from subdir' '
        100644 $(git hash-object dir1/file3) 0  dir1/file3
        100644 $file2 0 file2
        EOF
-       test_cmp current expected
+       test_cmp expected current
 '
 
 test_expect_success 'update-index --update with pathspec' '
index 93f21ab..478b82c 100755 (executable)
@@ -1221,7 +1221,7 @@ test_expect_success 'use --edit-description' '
        EOF
        EDITOR=./editor git branch --edit-description &&
        echo "New contents" >expect &&
-       test_cmp EDITOR_OUTPUT expect
+       test_cmp expect EDITOR_OUTPUT
 '
 
 test_expect_success 'detect typo in branch name when using --edit-description' '
index 10bfc8b..823fdbd 100755 (executable)
@@ -44,7 +44,7 @@ test_expect_success 'merge z into y fails and sets NOTES_MERGE_REF' '
        git config core.notesRef refs/notes/y &&
        test_must_fail git notes merge z &&
        echo "ref: refs/notes/y" >expect &&
-       test_cmp .git/NOTES_MERGE_REF expect
+       test_cmp expect .git/NOTES_MERGE_REF
 '
 
 test_expect_success 'merge z into y while mid-merge in another workdir fails' '
@@ -66,7 +66,7 @@ test_expect_success 'merge z into x while mid-merge on y succeeds' '
                grep -v "A notes merge into refs/notes/x is already in-progress in" out
        ) &&
        echo "ref: refs/notes/x" >expect &&
-       test_cmp .git/worktrees/worktree2/NOTES_MERGE_REF expect
+       test_cmp expect .git/worktrees/worktree2/NOTES_MERGE_REF
 '
 
 test_done
index 3996ee0..3e73f75 100755 (executable)
@@ -183,13 +183,13 @@ test_expect_success 'cherry-picked commits and fork-point work together' '
        test_commit final_B B "Final B" &&
        git rebase &&
        echo Amended >expect &&
-       test_cmp A expect &&
+       test_cmp expect A &&
        echo "Final B" >expect &&
-       test_cmp B expect &&
+       test_cmp expect B &&
        echo C >expect &&
-       test_cmp C expect &&
+       test_cmp expect C &&
        echo D >expect &&
-       test_cmp D expect
+       test_cmp expect D
 '
 
 test_expect_success 'rebase -q is quiet' '
index 1fb3e49..e85cdc7 100755 (executable)
@@ -55,7 +55,7 @@ test_expect_success 'blank line at end of file; extend at end of file' '
        git add file && git commit -m second &&
        git rebase --whitespace=fix HEAD^^ &&
        git diff --exit-code HEAD^:file expect-first &&
-       test_cmp file expect-second
+       test_cmp expect-second file
 '
 
 # prepare third revision of "file"
@@ -82,7 +82,7 @@ test_expect_success 'two blanks line at end of file; extend at end of file' '
        cp third file && git add file && git commit -m third &&
        git rebase --whitespace=fix HEAD^^ &&
        git diff --exit-code HEAD^:file expect-second &&
-       test_cmp file expect-third
+       test_cmp expect-third file
 '
 
 test_expect_success 'same, but do not remove trailing spaces' '
@@ -120,7 +120,7 @@ test_expect_success 'at beginning of file' '
        done >> file &&
        git commit -m more file &&
        git rebase --whitespace=fix HEAD^^ &&
-       test_cmp file expect-beginning
+       test_cmp expect-beginning file
 '
 
 test_done
index c6af7f8..6c67664 100755 (executable)
@@ -110,10 +110,10 @@ test_expect_success 'add -e' '
        cp second-part file &&
        git add -e &&
        test_cmp second-part file &&
-       test_cmp orig-patch expected-patch &&
+       test_cmp expected-patch orig-patch &&
        git diff --cached >actual &&
        grep -v index actual >out &&
-       test_cmp out expected
+       test_cmp expected out
 
 '
 
index 6450bc6..cd21665 100755 (executable)
@@ -36,7 +36,7 @@ EOF
 test_expect_success 'parents of stash' '
        test $(git rev-parse stash^) = $(git rev-parse HEAD) &&
        git diff stash^2..stash > output &&
-       test_cmp output expect
+       test_cmp expect output
 '
 
 test_expect_success 'applying bogus stash does nothing' '
@@ -210,9 +210,9 @@ test_expect_success 'stash branch' '
        test refs/heads/stashbranch = $(git symbolic-ref HEAD) &&
        test $(git rev-parse HEAD) = $(git rev-parse master^) &&
        git diff --cached > output &&
-       test_cmp output expect &&
+       test_cmp expect output &&
        git diff > output &&
-       test_cmp output expect1 &&
+       test_cmp expect1 output &&
        git add file &&
        git commit -m alternate\ second &&
        git diff master..stashbranch > output &&
@@ -710,7 +710,7 @@ test_expect_success 'stash where working directory contains "HEAD" file' '
        git diff-index --cached --quiet HEAD &&
        test "$(git rev-parse stash^)" = "$(git rev-parse HEAD)" &&
        git diff stash^..stash > output &&
-       test_cmp output expect
+       test_cmp expect output
 '
 
 test_expect_success 'store called with invalid commit' '
index 597b063..cc1c8a7 100755 (executable)
@@ -142,7 +142,7 @@ test_expect_success 'stash save --include-untracked removed files' '
        rm -f file &&
        git stash save --include-untracked &&
        echo 1 > expect &&
-       test_cmp file expect
+       test_cmp expect file
 '
 
 rm -f expect
index fa44e78..35578f2 100755 (executable)
@@ -37,7 +37,7 @@ test_expect_success 'hunk header truncation with an overly long line' '
                echo " A $N$N$N$N$N$N$N$N$N2" &&
                echo " L  $N$N$N$N$N$N$N$N$N1"
        ) >expected &&
-       test_cmp actual expected
+       test_cmp expected actual
 
 '
 
index d80187d..f7de6f0 100755 (executable)
@@ -72,7 +72,7 @@ test_expect_success 'apply with --reject should fail but update the file' '
        rm -f file1.rej file2.rej &&
 
        test_must_fail git apply --reject patch.1 &&
-       test_cmp file1 expected &&
+       test_cmp expected file1 &&
 
        cat file1.rej &&
        test_path_is_missing file2.rej
@@ -85,7 +85,7 @@ test_expect_success 'apply with --reject should fail but update the file' '
 
        test_must_fail git apply --reject patch.2 >rejects &&
        test_path_is_missing file1 &&
-       test_cmp file2 expected &&
+       test_cmp expected file2 &&
 
        cat file2.rej &&
        test_path_is_missing file1.rej
@@ -99,7 +99,7 @@ test_expect_success 'the same test with --verbose' '
 
        test_must_fail git apply --reject --verbose patch.2 >rejects &&
        test_path_is_missing file1 &&
-       test_cmp file2 expected &&
+       test_cmp expected file2 &&
 
        cat file2.rej &&
        test_path_is_missing file1.rej
index 7e32237..ff51e9e 100755 (executable)
@@ -313,9 +313,9 @@ test_expect_success 'applying beyond EOF requires one non-blank context line' '
        { echo a; echo; } >one &&
        cp one expect &&
        test_must_fail git apply --whitespace=fix patch &&
-       test_cmp one expect &&
+       test_cmp expect one &&
        test_must_fail git apply --ignore-space-change --whitespace=fix patch &&
-       test_cmp one expect
+       test_cmp expect one
 '
 
 test_expect_success 'tons of blanks at EOF should not apply' '
@@ -342,10 +342,10 @@ test_expect_success 'missing blank line at end with --whitespace=fix' '
        cp one saved-one &&
        test_must_fail git apply patch &&
        git apply --whitespace=fix patch &&
-       test_cmp one expect &&
+       test_cmp expect one &&
        mv saved-one one &&
        git apply --ignore-space-change --whitespace=fix patch &&
-       test_cmp one expect
+       test_cmp expect one
 '
 
 test_expect_success 'two missing blank lines at end with --whitespace=fix' '
@@ -360,11 +360,11 @@ test_expect_success 'two missing blank lines at end with --whitespace=fix' '
        cp no-blank-lines one &&
        test_must_fail git apply patch &&
        git apply --whitespace=fix patch &&
-       test_cmp one expect &&
+       test_cmp expect one &&
        mv no-blank-lines one &&
        test_must_fail git apply patch &&
        git apply --ignore-space-change --whitespace=fix patch &&
-       test_cmp one expect
+       test_cmp expect one
 '
 
 test_expect_success 'missing blank line at end, insert before end, --whitespace=fix' '
@@ -376,7 +376,7 @@ test_expect_success 'missing blank line at end, insert before end, --whitespace=
        echo a >one &&
        test_must_fail git apply patch &&
        git apply --whitespace=fix patch &&
-       test_cmp one expect
+       test_cmp expect one
 '
 
 test_expect_success 'shrink file with tons of missing blanks at end of file' '
@@ -392,10 +392,10 @@ test_expect_success 'shrink file with tons of missing blanks at end of file' '
        cp no-blank-lines one &&
        test_must_fail git apply patch &&
        git apply --whitespace=fix patch &&
-       test_cmp one expect &&
+       test_cmp expect one &&
        mv no-blank-lines one &&
        git apply --ignore-space-change --whitespace=fix patch &&
-       test_cmp one expect
+       test_cmp expect one
 '
 
 test_expect_success 'missing blanks at EOF must only match blank lines' '
@@ -427,7 +427,7 @@ test_expect_success 'missing blank line should match context line with spaces' '
        git add one &&
 
        git apply --whitespace=fix patch &&
-       test_cmp one expect
+       test_cmp expect one
 '
 
 sed -e's/Z//' >one <<EOF
@@ -447,7 +447,7 @@ test_expect_success 'same, but with the --ignore-space-option' '
 
        git checkout-index -f one &&
        git apply --ignore-space-change --whitespace=fix patch &&
-       test_cmp one expect
+       test_cmp expect one
 '
 
 test_expect_success 'same, but with CR-LF line endings && cr-at-eol set' '
@@ -464,7 +464,7 @@ test_expect_success 'same, but with CR-LF line endings && cr-at-eol set' '
        mv save-one one &&
 
        git apply --ignore-space-change --whitespace=fix patch &&
-       test_cmp one expect
+       test_cmp expect one
 '
 
 test_expect_success 'CR-LF line endings && add line && text=auto' '
@@ -478,7 +478,7 @@ test_expect_success 'CR-LF line endings && add line && text=auto' '
        mv save-one one &&
        echo "one text=auto" >.gitattributes &&
        git apply patch &&
-       test_cmp one expect
+       test_cmp expect one
 '
 
 test_expect_success 'CR-LF line endings && change line && text=auto' '
@@ -491,7 +491,7 @@ test_expect_success 'CR-LF line endings && change line && text=auto' '
        mv save-one one &&
        echo "one text=auto" >.gitattributes &&
        git apply patch &&
-       test_cmp one expect
+       test_cmp expect one
 '
 
 test_expect_success 'LF in repo, CRLF in worktree && change line && text=auto' '
@@ -503,7 +503,7 @@ test_expect_success 'LF in repo, CRLF in worktree && change line && text=auto' '
        echo "one text=auto" >.gitattributes &&
        git -c core.eol=CRLF apply patch &&
        printf "b\r\n" >expect &&
-       test_cmp one expect
+       test_cmp expect one
 '
 
 test_expect_success 'whitespace=fix to expand' '
index 0ffe33f..3b636a6 100755 (executable)
@@ -114,7 +114,7 @@ for t in 1 2 3 4
 do
        test_expect_success 'apply with ws expansion (t=$t)' '
                git apply patch$t.patch &&
-               test_cmp test-$t expect-$t
+               test_cmp expect-$t test-$t
        '
 done
 
index 6710c8b..2e718f0 100755 (executable)
@@ -21,17 +21,21 @@ test_expect_success 'setup r1' '
 
 test_expect_success 'verify blob count in normal packfile' '
        git -C r1 ls-files -s file.1 file.2 file.3 file.4 file.5 \
-               | awk -f print_2.awk \
-               | sort >expected &&
+               >ls_files_result &&
+       awk -f print_2.awk ls_files_result |
+       sort >expected &&
+
        git -C r1 pack-objects --rev --stdout >all.pack <<-EOF &&
        HEAD
        EOF
        git -C r1 index-pack ../all.pack &&
-       git -C r1 verify-pack -v ../all.pack \
-               | grep blob \
-               | awk -f print_1.awk \
-               | sort >observed &&
-       test_cmp observed expected
+
+       git -C r1 verify-pack -v ../all.pack >verify_result &&
+       grep blob verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
+       test_cmp expected observed
 '
 
 test_expect_success 'verify blob:none packfile has no blobs' '
@@ -39,24 +43,28 @@ test_expect_success 'verify blob:none packfile has no blobs' '
        HEAD
        EOF
        git -C r1 index-pack ../filter.pack &&
-       git -C r1 verify-pack -v ../filter.pack \
-               | grep blob \
-               | awk -f print_1.awk \
-               | sort >observed &&
+
+       git -C r1 verify-pack -v ../filter.pack >verify_result &&
+       grep blob verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
        nr=$(wc -l <observed) &&
        test 0 -eq $nr
 '
 
 test_expect_success 'verify normal and blob:none packfiles have same commits/trees' '
-       git -C r1 verify-pack -v ../all.pack \
-               | grep -E "commit|tree" \
-               | awk -f print_1.awk \
-               | sort >expected &&
-       git -C r1 verify-pack -v ../filter.pack \
-               | grep -E "commit|tree" \
-               | awk -f print_1.awk \
-               | sort >observed &&
-       test_cmp observed expected
+       git -C r1 verify-pack -v ../all.pack >verify_result &&
+       grep -E "commit|tree" verify_result |
+       awk -f print_1.awk |
+       sort >expected &&
+
+       git -C r1 verify-pack -v ../filter.pack >verify_result &&
+       grep -E "commit|tree" verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
+       test_cmp expected observed
 '
 
 # Test blob:limit=<n>[kmg] filter.
@@ -75,18 +83,21 @@ test_expect_success 'setup r2' '
 '
 
 test_expect_success 'verify blob count in normal packfile' '
-       git -C r2 ls-files -s large.1000 large.10000 \
-               | awk -f print_2.awk \
-               | sort >expected &&
+       git -C r2 ls-files -s large.1000 large.10000 >ls_files_result &&
+       awk -f print_2.awk ls_files_result |
+       sort >expected &&
+
        git -C r2 pack-objects --rev --stdout >all.pack <<-EOF &&
        HEAD
        EOF
        git -C r2 index-pack ../all.pack &&
-       git -C r2 verify-pack -v ../all.pack \
-               | grep blob \
-               | awk -f print_1.awk \
-               | sort >observed &&
-       test_cmp observed expected
+
+       git -C r2 verify-pack -v ../all.pack >verify_result &&
+       grep blob verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
+       test_cmp expected observed
 '
 
 test_expect_success 'verify blob:limit=500 omits all blobs' '
@@ -94,10 +105,12 @@ test_expect_success 'verify blob:limit=500 omits all blobs' '
        HEAD
        EOF
        git -C r2 index-pack ../filter.pack &&
-       git -C r2 verify-pack -v ../filter.pack \
-               | grep blob \
-               | awk -f print_1.awk \
-               | sort >observed &&
+
+       git -C r2 verify-pack -v ../filter.pack >verify_result &&
+       grep blob verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
        nr=$(wc -l <observed) &&
        test 0 -eq $nr
 '
@@ -107,100 +120,119 @@ test_expect_success 'verify blob:limit=1000' '
        HEAD
        EOF
        git -C r2 index-pack ../filter.pack &&
-       git -C r2 verify-pack -v ../filter.pack \
-               | grep blob \
-               | awk -f print_1.awk \
-               | sort >observed &&
+
+       git -C r2 verify-pack -v ../filter.pack >verify_result &&
+       grep blob verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
        nr=$(wc -l <observed) &&
        test 0 -eq $nr
 '
 
 test_expect_success 'verify blob:limit=1001' '
-       git -C r2 ls-files -s large.1000 \
-               | awk -f print_2.awk \
-               | sort >expected &&
+       git -C r2 ls-files -s large.1000 >ls_files_result &&
+       awk -f print_2.awk ls_files_result |
+       sort >expected &&
+
        git -C r2 pack-objects --rev --stdout --filter=blob:limit=1001 >filter.pack <<-EOF &&
        HEAD
        EOF
        git -C r2 index-pack ../filter.pack &&
-       git -C r2 verify-pack -v ../filter.pack \
-               | grep blob \
-               | awk -f print_1.awk \
-               | sort >observed &&
-       test_cmp observed expected
+
+       git -C r2 verify-pack -v ../filter.pack >verify_result &&
+       grep blob verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
+       test_cmp expected observed
 '
 
 test_expect_success 'verify blob:limit=10001' '
-       git -C r2 ls-files -s large.1000 large.10000 \
-               | awk -f print_2.awk \
-               | sort >expected &&
+       git -C r2 ls-files -s large.1000 large.10000 >ls_files_result &&
+       awk -f print_2.awk ls_files_result |
+       sort >expected &&
+
        git -C r2 pack-objects --rev --stdout --filter=blob:limit=10001 >filter.pack <<-EOF &&
        HEAD
        EOF
        git -C r2 index-pack ../filter.pack &&
-       git -C r2 verify-pack -v ../filter.pack \
-               | grep blob \
-               | awk -f print_1.awk \
-               | sort >observed &&
-       test_cmp observed expected
+
+       git -C r2 verify-pack -v ../filter.pack >verify_result &&
+       grep blob verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
+       test_cmp expected observed
 '
 
 test_expect_success 'verify blob:limit=1k' '
-       git -C r2 ls-files -s large.1000 \
-               | awk -f print_2.awk \
-               | sort >expected &&
+       git -C r2 ls-files -s large.1000 >ls_files_result &&
+       awk -f print_2.awk ls_files_result |
+       sort >expected &&
+
        git -C r2 pack-objects --rev --stdout --filter=blob:limit=1k >filter.pack <<-EOF &&
        HEAD
        EOF
        git -C r2 index-pack ../filter.pack &&
-       git -C r2 verify-pack -v ../filter.pack \
-               | grep blob \
-               | awk -f print_1.awk \
-               | sort >observed &&
-       test_cmp observed expected
+
+       git -C r2 verify-pack -v ../filter.pack >verify_result &&
+       grep blob verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
+       test_cmp expected observed
 '
 
 test_expect_success 'verify explicitly specifying oversized blob in input' '
-       git -C r2 ls-files -s large.1000 large.10000 \
-               | awk -f print_2.awk \
-               | sort >expected &&
+       git -C r2 ls-files -s large.1000 large.10000 >ls_files_result &&
+       awk -f print_2.awk ls_files_result |
+       sort >expected &&
+
        git -C r2 pack-objects --rev --stdout --filter=blob:limit=1k >filter.pack <<-EOF &&
        HEAD
        $(git -C r2 rev-parse HEAD:large.10000)
        EOF
        git -C r2 index-pack ../filter.pack &&
-       git -C r2 verify-pack -v ../filter.pack \
-               | grep blob \
-               | awk -f print_1.awk \
-               | sort >observed &&
-       test_cmp observed expected
+
+       git -C r2 verify-pack -v ../filter.pack >verify_result &&
+       grep blob verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
+       test_cmp expected observed
 '
 
 test_expect_success 'verify blob:limit=1m' '
-       git -C r2 ls-files -s large.1000 large.10000 \
-               | awk -f print_2.awk \
-               | sort >expected &&
+       git -C r2 ls-files -s large.1000 large.10000 >ls_files_result &&
+       awk -f print_2.awk ls_files_result |
+       sort >expected &&
+
        git -C r2 pack-objects --rev --stdout --filter=blob:limit=1m >filter.pack <<-EOF &&
        HEAD
        EOF
        git -C r2 index-pack ../filter.pack &&
-       git -C r2 verify-pack -v ../filter.pack \
-               | grep blob \
-               | awk -f print_1.awk \
-               | sort >observed &&
-       test_cmp observed expected
+
+       git -C r2 verify-pack -v ../filter.pack >verify_result &&
+       grep blob verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
+       test_cmp expected observed
 '
 
 test_expect_success 'verify normal and blob:limit packfiles have same commits/trees' '
-       git -C r2 verify-pack -v ../all.pack \
-               | grep -E "commit|tree" \
-               | awk -f print_1.awk \
-               | sort >expected &&
-       git -C r2 verify-pack -v ../filter.pack \
-               | grep -E "commit|tree" \
-               | awk -f print_1.awk \
-               | sort >observed &&
-       test_cmp observed expected
+       git -C r2 verify-pack -v ../all.pack >verify_result &&
+       grep -E "commit|tree" verify_result |
+       awk -f print_1.awk |
+       sort >expected &&
+
+       git -C r2 verify-pack -v ../filter.pack >verify_result &&
+       grep -E "commit|tree" verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
+       test_cmp expected observed
 '
 
 # Test sparse:path=<path> filter.
@@ -225,71 +257,85 @@ test_expect_success 'setup r3' '
 
 test_expect_success 'verify blob count in normal packfile' '
        git -C r3 ls-files -s sparse1 sparse2 dir1/sparse1 dir1/sparse2 \
-               | awk -f print_2.awk \
-               | sort >expected &&
+               >ls_files_result &&
+       awk -f print_2.awk ls_files_result |
+       sort >expected &&
+
        git -C r3 pack-objects --rev --stdout >all.pack <<-EOF &&
        HEAD
        EOF
        git -C r3 index-pack ../all.pack &&
-       git -C r3 verify-pack -v ../all.pack \
-               | grep blob \
-               | awk -f print_1.awk \
-               | sort >observed &&
-       test_cmp observed expected
+
+       git -C r3 verify-pack -v ../all.pack >verify_result &&
+       grep blob verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
+       test_cmp expected observed
 '
 
 test_expect_success 'verify sparse:path=pattern1' '
-       git -C r3 ls-files -s dir1/sparse1 dir1/sparse2 \
-               | awk -f print_2.awk \
-               | sort >expected &&
+       git -C r3 ls-files -s dir1/sparse1 dir1/sparse2 >ls_files_result &&
+       awk -f print_2.awk ls_files_result |
+       sort >expected &&
+
        git -C r3 pack-objects --rev --stdout --filter=sparse:path=../pattern1 >filter.pack <<-EOF &&
        HEAD
        EOF
        git -C r3 index-pack ../filter.pack &&
-       git -C r3 verify-pack -v ../filter.pack \
-               | grep blob \
-               | awk -f print_1.awk \
-               | sort >observed &&
-       test_cmp observed expected
+
+       git -C r3 verify-pack -v ../filter.pack >verify_result &&
+       grep blob verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
+       test_cmp expected observed
 '
 
 test_expect_success 'verify normal and sparse:path=pattern1 packfiles have same commits/trees' '
-       git -C r3 verify-pack -v ../all.pack \
-               | grep -E "commit|tree" \
-               | awk -f print_1.awk \
-               | sort >expected &&
-       git -C r3 verify-pack -v ../filter.pack \
-               | grep -E "commit|tree" \
-               | awk -f print_1.awk \
-               | sort >observed &&
-       test_cmp observed expected
+       git -C r3 verify-pack -v ../all.pack >verify_result &&
+       grep -E "commit|tree" verify_result |
+       awk -f print_1.awk |
+       sort >expected &&
+
+       git -C r3 verify-pack -v ../filter.pack >verify_result &&
+       grep -E "commit|tree" verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
+       test_cmp expected observed
 '
 
 test_expect_success 'verify sparse:path=pattern2' '
-       git -C r3 ls-files -s sparse1 dir1/sparse1 \
-               | awk -f print_2.awk \
-               | sort >expected &&
+       git -C r3 ls-files -s sparse1 dir1/sparse1 >ls_files_result &&
+       awk -f print_2.awk ls_files_result |
+       sort >expected &&
+
        git -C r3 pack-objects --rev --stdout --filter=sparse:path=../pattern2 >filter.pack <<-EOF &&
        HEAD
        EOF
        git -C r3 index-pack ../filter.pack &&
-       git -C r3 verify-pack -v ../filter.pack \
-               | grep blob \
-               | awk -f print_1.awk \
-               | sort >observed &&
-       test_cmp observed expected
+
+       git -C r3 verify-pack -v ../filter.pack >verify_result &&
+       grep blob verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
+       test_cmp expected observed
 '
 
 test_expect_success 'verify normal and sparse:path=pattern2 packfiles have same commits/trees' '
-       git -C r3 verify-pack -v ../all.pack \
-               | grep -E "commit|tree" \
-               | awk -f print_1.awk \
-               | sort >expected &&
-       git -C r3 verify-pack -v ../filter.pack \
-               | grep -E "commit|tree" \
-               | awk -f print_1.awk \
-               | sort >observed &&
-       test_cmp observed expected
+       git -C r3 verify-pack -v ../all.pack >verify_result &&
+       grep -E "commit|tree" verify_result |
+       awk -f print_1.awk |
+       sort >expected &&
+
+       git -C r3 verify-pack -v ../filter.pack >verify_result &&
+       grep -E "commit|tree" verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
+       test_cmp expected observed
 '
 
 # Test sparse:oid=<oid-ish> filter.
@@ -313,48 +359,58 @@ test_expect_success 'setup r4' '
 
 test_expect_success 'verify blob count in normal packfile' '
        git -C r4 ls-files -s pattern sparse1 sparse2 dir1/sparse1 dir1/sparse2 \
-               | awk -f print_2.awk \
-               | sort >expected &&
+               >ls_files_result &&
+       awk -f print_2.awk ls_files_result |
+       sort >expected &&
+
        git -C r4 pack-objects --rev --stdout >all.pack <<-EOF &&
        HEAD
        EOF
        git -C r4 index-pack ../all.pack &&
-       git -C r4 verify-pack -v ../all.pack \
-               | grep blob \
-               | awk -f print_1.awk \
-               | sort >observed &&
-       test_cmp observed expected
+
+       git -C r4 verify-pack -v ../all.pack >verify_result &&
+       grep blob verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
+       test_cmp expected observed
 '
 
 test_expect_success 'verify sparse:oid=OID' '
-       git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 \
-               | awk -f print_2.awk \
-               | sort >expected &&
+       git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 >ls_files_result &&
+       awk -f print_2.awk ls_files_result |
+       sort >expected &&
+
        oid=$(git -C r4 ls-files -s pattern | awk -f print_2.awk) &&
        git -C r4 pack-objects --rev --stdout --filter=sparse:oid=$oid >filter.pack <<-EOF &&
        HEAD
        EOF
        git -C r4 index-pack ../filter.pack &&
-       git -C r4 verify-pack -v ../filter.pack \
-               | grep blob \
-               | awk -f print_1.awk \
-               | sort >observed &&
-       test_cmp observed expected
+
+       git -C r4 verify-pack -v ../filter.pack >verify_result &&
+       grep blob verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
+       test_cmp expected observed
 '
 
 test_expect_success 'verify sparse:oid=oid-ish' '
-       git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 \
-               | awk -f print_2.awk \
-               | sort >expected &&
+       git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 >ls_files_result &&
+       awk -f print_2.awk ls_files_result |
+       sort >expected &&
+
        git -C r4 pack-objects --rev --stdout --filter=sparse:oid=master:pattern >filter.pack <<-EOF &&
        HEAD
        EOF
        git -C r4 index-pack ../filter.pack &&
-       git -C r4 verify-pack -v ../filter.pack \
-               | grep blob \
-               | awk -f print_1.awk \
-               | sort >observed &&
-       test_cmp observed expected
+
+       git -C r4 verify-pack -v ../filter.pack >verify_result &&
+       grep blob verify_result |
+       awk -f print_1.awk |
+       sort >observed &&
+
+       test_cmp expected observed
 '
 
 # Delete some loose objects and use pack-objects, but WITHOUT any filtering.
@@ -362,8 +418,10 @@ test_expect_success 'verify sparse:oid=oid-ish' '
 
 test_expect_success 'setup r1 - delete loose blobs' '
        git -C r1 ls-files -s file.1 file.2 file.3 file.4 file.5 \
-               | awk -f print_2.awk \
-               | sort >expected &&
+               >ls_files_result &&
+       awk -f print_2.awk ls_files_result |
+       sort >expected &&
+
        for id in `cat expected | sed "s|..|&/|"`
        do
                rm r1/.git/objects/$id
index 0c500f7..5fe21db 100755 (executable)
@@ -8,7 +8,8 @@ test_expect_success 'setup full repo' '
        cd "$TRASH_DIRECTORY/full" &&
        git init &&
        git config core.commitGraph true &&
-       objdir=".git/objects"
+       objdir=".git/objects" &&
+       test_oid_init
 '
 
 test_expect_success 'verify graph with no graph file' '
@@ -35,7 +36,7 @@ test_expect_success 'create commits and repack' '
 graph_git_two_modes() {
        git -c core.commitGraph=true $1 >output
        git -c core.commitGraph=false $1 >expect
-       test_cmp output expect
+       test_cmp expect output
 }
 
 graph_git_behavior() {
@@ -259,6 +260,66 @@ test_expect_success 'check that gc computes commit-graph' '
        test_cmp_bin commit-graph-after-gc $objdir/info/commit-graph
 '
 
+test_expect_success 'replace-objects invalidates commit-graph' '
+       cd "$TRASH_DIRECTORY" &&
+       test_when_finished rm -rf replace &&
+       git clone full replace &&
+       (
+               cd replace &&
+               git commit-graph write --reachable &&
+               test_path_is_file .git/objects/info/commit-graph &&
+               git replace HEAD~1 HEAD~2 &&
+               git -c core.commitGraph=false log >expect &&
+               git -c core.commitGraph=true log >actual &&
+               test_cmp expect actual &&
+               git commit-graph write --reachable &&
+               git -c core.commitGraph=false --no-replace-objects log >expect &&
+               git -c core.commitGraph=true --no-replace-objects log >actual &&
+               test_cmp expect actual &&
+               rm -rf .git/objects/info/commit-graph &&
+               git commit-graph write --reachable &&
+               test_path_is_file .git/objects/info/commit-graph
+       )
+'
+
+test_expect_success 'commit grafts invalidate commit-graph' '
+       cd "$TRASH_DIRECTORY" &&
+       test_when_finished rm -rf graft &&
+       git clone full graft &&
+       (
+               cd graft &&
+               git commit-graph write --reachable &&
+               test_path_is_file .git/objects/info/commit-graph &&
+               H1=$(git rev-parse --verify HEAD~1) &&
+               H3=$(git rev-parse --verify HEAD~3) &&
+               echo "$H1 $H3" >.git/info/grafts &&
+               git -c core.commitGraph=false log >expect &&
+               git -c core.commitGraph=true log >actual &&
+               test_cmp expect actual &&
+               git commit-graph write --reachable &&
+               git -c core.commitGraph=false --no-replace-objects log >expect &&
+               git -c core.commitGraph=true --no-replace-objects log >actual &&
+               test_cmp expect actual &&
+               rm -rf .git/objects/info/commit-graph &&
+               git commit-graph write --reachable &&
+               test_path_is_missing .git/objects/info/commit-graph
+       )
+'
+
+test_expect_success 'replace-objects invalidates commit-graph' '
+       cd "$TRASH_DIRECTORY" &&
+       test_when_finished rm -rf shallow &&
+       git clone --depth 2 "file://$TRASH_DIRECTORY/full" shallow &&
+       (
+               cd shallow &&
+               git commit-graph write --reachable &&
+               test_path_is_missing .git/objects/info/commit-graph &&
+               git fetch origin --unshallow &&
+               git commit-graph write --reachable &&
+               test_path_is_file .git/objects/info/commit-graph
+       )
+'
+
 # the verify tests below expect the commit-graph to contain
 # exactly the commits reachable from the commits/8 branch.
 # If the file changes the set of commits in the list, then the
@@ -273,7 +334,7 @@ test_expect_success 'git commit-graph verify' '
 
 NUM_COMMITS=9
 NUM_OCTOPUS_EDGES=2
-HASH_LEN=20
+HASH_LEN="$(test_oid rawsz)"
 GRAPH_BYTE_VERSION=4
 GRAPH_BYTE_HASH=5
 GRAPH_BYTE_CHUNK_COUNT=6
index 6f56b38..bd8e841 100755 (executable)
@@ -150,6 +150,125 @@ test_expect_success 'write midx with twelve packs' '
 
 compare_results_with_midx "twelve packs"
 
+test_expect_success 'verify multi-pack-index success' '
+       git multi-pack-index verify --object-dir=$objdir
+'
+
+# usage: corrupt_midx_and_verify <pos> <data> <objdir> <string>
+corrupt_midx_and_verify() {
+       POS=$1 &&
+       DATA="${2:-\0}" &&
+       OBJDIR=$3 &&
+       GREPSTR="$4" &&
+       COMMAND="$5" &&
+       if test -z "$COMMAND"
+       then
+               COMMAND="git multi-pack-index verify --object-dir=$OBJDIR"
+       fi &&
+       FILE=$OBJDIR/pack/multi-pack-index &&
+       chmod a+w $FILE &&
+       test_when_f