]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'sg/test-oid-wo-incomplete-line'
authorJunio C Hamano <gitster@pobox.com>
Thu, 5 Jan 2023 06:07:18 +0000 (15:07 +0900)
committerJunio C Hamano <gitster@pobox.com>
Thu, 5 Jan 2023 06:07:19 +0000 (15:07 +0900)
Test helper updates.

* sg/test-oid-wo-incomplete-line:
  tests: make 'test_oid' print trailing newline

107 files changed:
Documentation/RelNotes/2.40.0.txt
Documentation/config/format.txt
Documentation/config/transfer.txt
Documentation/git-cat-file.txt
Documentation/git-status.txt
Documentation/git-var.txt
Documentation/gitprotocol-v2.txt
Makefile
add-interactive.c
apply.c
blob.c
blob.h
builtin/add.c
builtin/am.c
builtin/branch.c
builtin/cat-file.c
builtin/clone.c
builtin/fast-export.c
builtin/fsmonitor--daemon.c
builtin/log.c
builtin/merge-tree.c
builtin/merge.c
builtin/range-diff.c
builtin/rerere.c
builtin/reset.c
builtin/submodule--helper.c
builtin/var.c
bundle-uri.c
bundle-uri.h
cache.h
ci/lib.sh
combine-diff.c
commit.c
compat/fsmonitor/fsm-darwin-gcc.h
compat/fsmonitor/fsm-listen-darwin.c
compat/mingw.c
compat/win32/pthread.h
connect.c
connect.h
contrib/completion/git-completion.bash
diff-lib.c
diff-no-index.c
diff.c
diff.h
fetch-pack.c
git-compat-util.h
git-submodule.sh
help.c
http-fetch.c
line-range.c
list-objects-filter.c
list-objects.c
ls-refs.c
object-file.c
object-store.h
object.c
pack-write.c
range-diff.c
ref-filter.c
reflog.c
refs.c
refs.h
refs/packed-backend.c
remote.h
revision.c
run-command.c
sequencer.c
serve.c
strbuf.c
strbuf.h
submodule.c
t/helper/test-bundle-uri.c
t/lib-bundle-uri-protocol.sh [new file with mode: 0644]
t/t0007-git-var.sh
t/t3204-branch-name-interpretation.sh
t/t3920-crlf-messages.sh
t/t4014-format-patch.sh
t/t4023-diff-rename-typechange.sh
t/t4046-diff-unmerged.sh
t/t4150-am.sh
t/t4203-mailmap.sh
t/t4205-log-pretty-formats.sh
t/t4211-line-log.sh
t/t5314-pack-cycle-detection.sh
t/t5601-clone.sh
t/t5701-git-serve.sh
t/t5730-protocol-v2-bundle-uri-file.sh [new file with mode: 0755]
t/t5731-protocol-v2-bundle-uri-git.sh [new file with mode: 0755]
t/t5732-protocol-v2-bundle-uri-http.sh [new file with mode: 0755]
t/t5750-bundle-uri-parse.sh
t/t6300-for-each-ref.sh
t/t7508-status.sh
t/t7600-merge.sh
t/t9003-help-autocorrect.sh
t/t9119-git-svn-info.sh
t/t9902-completion.sh
t/test-lib-functions.sh
transport-helper.c
transport-internal.h
transport.c
transport.h
unpack-trees.c
userdiff.c
ws.c
wt-status.c
xdiff/xdiffi.c
xdiff/xemit.c

index 669a03518be3e936947b2e7a46bad820fce944e4..80b3b504021df7e3fd6f7b47cb7afbb80d6966c9 100644 (file)
@@ -14,6 +14,18 @@ UI, Workflows & Features
    just gives an empty output, while the former still gives an error
    message.
 
+ * Introduce a case insensitive mode to the Bash completion helpers.
+
+ * The advice message given by "git status" when it takes long time to
+   enumerate untracked paths has been updated.
+
+ * Just like "git var GIT_EDITOR" abstracts the complex logic to
+   choose which editor gets used behind it, "git var" now give support
+   to GIT_SEQUENCE_EDITOR.
+
+ * "git format-patch" learned to honor format.mboxrd even when sending
+   patches to the standard output stream,
+
 
 Performance, Internal Implementation, Development Support etc.
 
@@ -22,6 +34,8 @@ Performance, Internal Implementation, Development Support etc.
  * The pack-bitmap machinery is taught to log the paths of redundant
    bitmap(s) to trace2 instead of stderr.
 
+ * Use the SHA1DC implementation on macOS, just like other platforms,
+   by default.
 
 
 Fixes since v2.39
@@ -34,4 +48,65 @@ Fixes since v2.39
    arguments when invoked directly.
    (merge d4f7036887 rs/multi-filter-args later to maint).
 
+ * Make fsmonitor more robust to avoid the flakiness seen in t7527.
+   (merge 6692d45477 jh/t7527-unflake-by-forcing-cookie later to maint).
+
+ * Stop using deprecated macOS API in fsmonitor.
+   (merge b0226007f0 jh/fsmonitor-darwin-modernize later to maint).
+
+ * Redefining system functions for a few functions did not follow our
+   usual "implement git_foo() and #define foo(args) git_foo(args)"
+   pattern, which has broken build for some folks.
+   (merge e1a95b78d8 jk/avoid-redef-system-functions-2.30 later to maint).
+   (merge 395bec6b39 jk/avoid-redef-system-functions later to maint).
+
+ * The way the diff machinery prepares the options array for the
+   parse_options API has been refactored to avoid resource leaks.
+   (merge 189e97bc4b rs/diff-parseopts later to maint).
+
+ * Correct pthread API usage.
+   (merge 786e67611d sx/pthread-error-check-fix later to maint).
+
+ * The code to auto-correct a misspelt subcommand unnecessarily called
+   into git_default_config() from the early config codepath, which was
+   a no-no.  This has bee corrected.
+   (merge 0918d08887 sg/help-autocorrect-config-fix later to maint).
+
+ * "git http-fetch" (which is rarely used) forgot to identify itself
+   in the trace2 output.
+   (merge 7abb43cbc8 jt/http-fetch-trace2-report-name later to maint).
+
+ * The output from "git diff --stat" on an unmerged path lost the
+   terminating LF in Git 2.39, which has been corrected.
+   (merge 209d9cb011 pg/diff-stat-unmerged-regression-fix later to maint).
+
+ * "git pull -v --recurse-submodules" attempted to pass "-v" down to
+   underlying "git submodule update", which did not understand the
+   request and barfed, which has been corrected.
+   (merge 6f65f84766 ss/pull-v-recurse-fix later to maint).
+
+ * When given a pattern that matches an empty string at the end of a
+   line, the code to parse the "git diff" line-ranges fell into an
+   infinite loop, which has been corrected.
+   (merge 4e57c88e02 lk/line-range-parsing-fix later to maint).
+
+ * Fix the sequence to fsync $GIT_DIR/packed-refs file that forgot to
+   flush its output to the disk..
+   (merge ce54672f9b ps/fsync-refs-fix later to maint).
+
  * Other code cleanup, docfix, build fix, etc.
+   (merge 77e04b2ed4 rs/t4205-do-not-exit-in-test-script later to maint).
+   (merge faebba436e rs/plug-pattern-list-leak-in-lof later to maint).
+   (merge 243caa8982 ab/t5314-avoid-losing-exit-status later to maint).
+   (merge 4d81ce1b99 ab/t7600-avoid-losing-exit-status-of-git later to maint).
+   (merge 5f3bfdc4f3 ab/t4023-avoid-losing-exit-status-of-diff later to maint).
+   (merge 500317ae03 js/t3920-shell-and-or-fix later to maint).
+   (merge 86325d36e6 rs/t3920-crlf-eating-grep-fix later to maint).
+   (merge cfbd173ccb rj/branch-copy-and-rename later to maint).
+   (merge c25d9e529d jk/unused-post-2.39 later to maint).
+   (merge a31cfe3283 jk/server-supports-v2-cleanup later to maint).
+   (merge a658e881c1 rs/am-parse-options-cleanup later to maint).
+   (merge 4cb39fcf19 rs/clear-commit-marks-cleanup later to maint).
+   (merge b07a819c05 rs/reflog-expiry-cleanup later to maint).
+   (merge d422d06167 rs/clarify-error-in-write-loose-object later to maint).
+   (merge 92cb135855 sk/remove-duplicate-includes later to maint).
index c7303d8d9f004b5e413c4e5fe0dbb2f0df0c9171..3bd78269e29a544fa13369f9e5169b403be294ac 100644 (file)
@@ -139,3 +139,7 @@ For example,
 ------------
 +
 will only show notes from `refs/notes/bar`.
+
+format.mboxrd::
+       A boolean value which enables the robust "mboxrd" format when
+       `--stdout` is in use to escape "^>+From " lines.
index 264812cca4db9a0a7b70be3eed7703d3439c9f46..c3ac767d1e4de152865ec82de6a995a9b4934834 100644 (file)
@@ -115,3 +115,9 @@ transfer.unpackLimit::
 transfer.advertiseSID::
        Boolean. When true, client and server processes will advertise their
        unique session IDs to their remote counterpart. Defaults to false.
+
+transfer.bundleURI::
+       When `true`, local `git clone` commands will request bundle
+       information from the remote server (if advertised) and download
+       bundles before continuing the clone through the Git protocol.
+       Defaults to `false`.
index ec30b5c5743fd64ea9d42f4f451dc6ce0627d80a..830f0a2efff95bc1b48bf9b1cbec7b6f481be2f2 100644 (file)
@@ -45,7 +45,9 @@ OPTIONS
 
 -s::
        Instead of the content, show the object size identified by
-       `<object>`.
+       `<object>`. If used with `--use-mailmap` option, will show
+       the size of updated object after replacing idents using the
+       mailmap mechanism.
 
 -e::
        Exit with zero status if `<object>` exists and is a valid
@@ -89,26 +91,49 @@ OPTIONS
 --batch::
 --batch=<format>::
        Print object information and contents for each object provided
-       on stdin.  May not be combined with any other options or arguments
-       except `--textconv` or `--filters`, in which case the input lines
-       also need to specify the path, separated by whitespace.  See the
-       section `BATCH OUTPUT` below for details.
+       on stdin. May not be combined with any other options or arguments
+       except `--textconv`, `--filters`, or `--use-mailmap`.
+       +
+       * When used with `--textconv` or `--filters`, the input lines
+         must specify the path, separated by whitespace. See the section
+         `BATCH OUTPUT` below for details.
+       +
+       * When used with `--use-mailmap`, for commit and tag objects, the
+         contents part of the output shows the identities replaced using the
+         mailmap mechanism, while the information part of the output shows
+         the size of the object as if it actually recorded the replacement
+         identities.
 
 --batch-check::
 --batch-check=<format>::
-       Print object information for each object provided on stdin.  May
-       not be combined with any other options or arguments except
-       `--textconv` or `--filters`, in which case the input lines also
-       need to specify the path, separated by whitespace.  See the
-       section `BATCH OUTPUT` below for details.
+       Print object information for each object provided on stdin. May not be
+       combined with any other options or arguments except `--textconv`, `--filters`
+       or `--use-mailmap`.
+       +
+       * When used with `--textconv` or `--filters`, the input lines must
+        specify the path, separated by whitespace. See the section
+        `BATCH OUTPUT` below for details.
+       +
+       * When used with `--use-mailmap`, for commit and tag objects, the
+         printed object information shows the size of the object as if the
+         identities recorded in it were replaced by the mailmap mechanism.
 
 --batch-command::
 --batch-command=<format>::
        Enter a command mode that reads commands and arguments from stdin. May
-       only be combined with `--buffer`, `--textconv` or `--filters`. In the
-       case of `--textconv` or `--filters`, the input lines also need to specify
-       the path, separated by whitespace. See the section `BATCH OUTPUT` below
-       for details.
+       only be combined with `--buffer`, `--textconv`, `--use-mailmap` or
+       `--filters`.
+       +
+       * When used with `--textconv` or `--filters`, the input lines must
+         specify the path, separated by whitespace. See the section
+         `BATCH OUTPUT` below for details.
+       +
+       * When used with `--use-mailmap`, for commit and tag objects, the
+         `contents` command shows the identities replaced using the
+         mailmap mechanism, while the `info` command shows the size
+         of the object as if it actually recorded the replacement
+         identities.
+
 +
 `--batch-command` recognizes the following commands:
 +
index 5e438a7fdc1ca4e8684c52c3773a6f722b26c287..a051b1e8f383abc618397ea7e2ac2f173d30a111 100644 (file)
@@ -457,6 +457,66 @@ during the write may conflict with other simultaneous processes, causing
 them to fail. Scripts running `status` in the background should consider
 using `git --no-optional-locks status` (see linkgit:git[1] for details).
 
+UNTRACKED FILES AND PERFORMANCE
+-------------------------------
+
+`git status` can be very slow in large worktrees if/when it
+needs to search for untracked files and directories. There are
+many configuration options available to speed this up by either
+avoiding the work or making use of cached results from previous
+Git commands. There is no single optimum set of settings right
+for everyone. We'll list a summary of the relevant options to help
+you, but before going into the list, you may want to run `git status`
+again, because your configuration may already be caching `git status`
+results, so it could be faster on subsequent runs.
+
+* The `--untracked-files=no` flag or the
+       `status.showUntrackedfiles=false` config (see above for both):
+       indicate that `git status` should not report untracked
+       files. This is the fastest option. `git status` will not list
+       the untracked files, so you need to be careful to remember if
+       you create any new files and manually `git add` them.
+
+* `advice.statusUoption=false` (see linkgit:git-config[1]):
+       setting this variable to `false` disables the warning message
+       given when enumerating untracked files takes more than 2
+       seconds.  In a large project, it may take longer and the user
+       may have already accepted the trade off (e.g. using "-uno" may
+       not be an acceptable option for the user), in which case, there
+       is no point issuing the warning message, and in such a case,
+       disabling the warning may be the best.
+
+* `core.untrackedCache=true` (see linkgit:git-update-index[1]):
+       enable the untracked cache feature and only search directories
+       that have been modified since the previous `git status` command.
+       Git remembers the set of untracked files within each directory
+       and assumes that if a directory has not been modified, then
+       the set of untracked files within has not changed.  This is much
+       faster than enumerating the contents of every directory, but still
+       not without cost, because Git still has to search for the set of
+       modified directories. The untracked cache is stored in the
+       `.git/index` file. The reduced cost of searching for untracked
+       files is offset slightly by the increased size of the index and
+       the cost of keeping it up-to-date. That reduced search time is
+       usually worth the additional size.
+
+* `core.untrackedCache=true` and `core.fsmonitor=true` or
+       `core.fsmonitor=<hook_command_pathname>` (see
+       linkgit:git-update-index[1]): enable both the untracked cache
+       and FSMonitor features and only search directories that have
+       been modified since the previous `git status` command.  This
+       is faster than using just the untracked cache alone because
+       Git can also avoid searching for modified directories.  Git
+       only has to enumerate the exact set of directories that have
+       changed recently. While the FSMonitor feature can be enabled
+       without the untracked cache, the benefits are greatly reduced
+       in that case.
+
+Note that after you turn on the untracked cache and/or FSMonitor
+features it may take a few `git status` commands for the various
+caches to warm up before you see improved command times.  This is
+normal.
+
 SEE ALSO
 --------
 linkgit:gitignore[5]
index 0ab5bfa7d725749543b61568966762a37bce4535..f40202b8e3ab521ea22c78986d3bf5bb44a67f09 100644 (file)
@@ -50,6 +50,14 @@ ifdef::git-default-editor[]
     The build you are using chose '{git-default-editor}' as the default.
 endif::git-default-editor[]
 
+GIT_SEQUENCE_EDITOR::
+    Text editor used to edit the 'todo' file while running `git rebase
+    -i`. Like `GIT_EDITOR`, the value is meant to be interpreted by
+    the shell when it is used. The order of preference is the
+    `$GIT_SEQUENCE_EDITOR` environment variable, then
+    `sequence.editor` configuration, and then the value of `git var
+    GIT_EDITOR`.
+
 GIT_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
index 59bf41cefb9b958f57e6e95201784ec8cec56fb0..10bd2d40cecc48975bceedb258b9ed3f2fc0a896 100644 (file)
@@ -578,6 +578,207 @@ and associated requested information, each separated by a single space.
 
        obj-info = obj-id SP obj-size
 
+bundle-uri
+~~~~~~~~~~
+
+If the 'bundle-uri' capability is advertised, the server supports the
+`bundle-uri' command.
+
+The capability is currently advertised with no value (i.e. not
+"bundle-uri=somevalue"), a value may be added in the future for
+supporting command-wide extensions. Clients MUST ignore any unknown
+capability values and proceed with the 'bundle-uri` dialog they
+support.
+
+The 'bundle-uri' command is intended to be issued before `fetch` to
+get URIs to bundle files (see linkgit:git-bundle[1]) to "seed" and
+inform the subsequent `fetch` command.
+
+The client CAN issue `bundle-uri` before or after any other valid
+command. To be useful to clients it's expected that it'll be issued
+after an `ls-refs` and before `fetch`, but CAN be issued at any time
+in the dialog.
+
+DISCUSSION of bundle-uri
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+The intent of the feature is optimize for server resource consumption
+in the common case by changing the common case of fetching a very
+large PACK during linkgit:git-clone[1] into a smaller incremental
+fetch.
+
+It also allows servers to achieve better caching in combination with
+an `uploadpack.packObjectsHook` (see linkgit:git-config[1]).
+
+By having new clones or fetches be a more predictable and common
+negotiation against the tips of recently produces *.bundle file(s).
+Servers might even pre-generate the results of such negotiations for
+the `uploadpack.packObjectsHook` as new pushes come in.
+
+One way that servers could take advantage of these bundles is that the
+server would anticipate that fresh clones will download a known bundle,
+followed by catching up to the current state of the repository using ref
+tips found in that bundle (or bundles).
+
+PROTOCOL for bundle-uri
+^^^^^^^^^^^^^^^^^^^^^^^
+
+A `bundle-uri` request takes no arguments, and as noted above does not
+currently advertise a capability value. Both may be added in the
+future.
+
+When the client issues a `command=bundle-uri` request, the response is a
+list of key-value pairs provided as packet lines with value
+`<key>=<value>`. Each `<key>` should be interpreted as a config key from
+the `bundle.*` namespace to construct a list of bundles. These keys are
+grouped by a `bundle.<id>.` subsection, where each key corresponding to a
+given `<id>` contributes attributes to the bundle defined by that `<id>`.
+See linkgit:git-config[1] for the specific details of these keys and how
+the Git client will interpret their values.
+
+Clients MUST parse the line according to the above format, lines that do
+not conform to the format SHOULD be discarded. The user MAY be warned in
+such a case.
+
+bundle-uri CLIENT AND SERVER EXPECTATIONS
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+URI CONTENTS::
+The content at the advertised URIs MUST be one of two types.
++
+The advertised URI may contain a bundle file that `git bundle verify`
+would accept. I.e. they MUST contain one or more reference tips for
+use by the client, MUST indicate prerequisites (in any) with standard
+"-" prefixes, and MUST indicate their "object-format", if
+applicable.
++
+The advertised URI may alternatively contain a plaintext file that `git
+config --list` would accept (with the `--file` option). The key-value
+pairs in this list are in the `bundle.*` namespace (see
+linkgit:git-config[1]).
+
+bundle-uri CLIENT ERROR RECOVERY::
+A client MUST above all gracefully degrade on errors, whether that
+error is because of bad missing/data in the bundle URI(s), because
+that client is too dumb to e.g. understand and fully parse out bundle
+headers and their prerequisite relationships, or something else.
++
+Server operators should feel confident in turning on "bundle-uri" and
+not worry if e.g. their CDN goes down that clones or fetches will run
+into hard failures. Even if the server bundle bundle(s) are
+incomplete, or bad in some way the client should still end up with a
+functioning repository, just as if it had chosen not to use this
+protocol extension.
++
+All subsequent discussion on client and server interaction MUST keep
+this in mind.
+
+bundle-uri SERVER TO CLIENT::
+The ordering of the returned bundle uris is not significant. Clients
+MUST parse their headers to discover their contained OIDS and
+prerequisites. A client MUST consider the content of the bundle(s)
+themselves and their header as the ultimate source of truth.
++
+A server MAY even return bundle(s) that don't have any direct
+relationship to the repository being cloned (either through accident,
+or intentional "clever" configuration), and expect a client to sort
+out what data they'd like from the bundle(s), if any.
+
+bundle-uri CLIENT TO SERVER::
+The client SHOULD provide reference tips found in the bundle header(s)
+as 'have' lines in any subsequent `fetch` request. A client MAY also
+ignore the bundle(s) entirely if doing so is deemed worse for some
+reason, e.g. if the bundles can't be downloaded, it doesn't like the
+tips it finds etc.
+
+WHEN ADVERTISED BUNDLE(S) REQUIRE NO FURTHER NEGOTIATION::
+If after issuing `bundle-uri` and `ls-refs`, and getting the header(s)
+of the bundle(s) the client finds that the ref tips it wants can be
+retrieved entirely from advertised bundle(s), the client MAY disconnect
+from the Git server. The results of such a 'clone' or 'fetch' should be
+indistinguishable from the state attained without using bundle-uri.
+
+EARLY CLIENT DISCONNECTIONS AND ERROR RECOVERY::
+A client MAY perform an early disconnect while still downloading the
+bundle(s) (having streamed and parsed their headers). In such a case
+the client MUST gracefully recover from any errors related to
+finishing the download and validation of the bundle(s).
++
+I.e. a client might need to re-connect and issue a 'fetch' command,
+and possibly fall back to not making use of 'bundle-uri' at all.
++
+This "MAY" behavior is specified as such (and not a "SHOULD") on the
+assumption that a server advertising bundle uris is more likely than
+not to be serving up a relatively large repository, and to be pointing
+to URIs that have a good chance of being in working order. A client
+MAY e.g. look at the payload size of the bundles as a heuristic to see
+if an early disconnect is worth it, should falling back on a full
+"fetch" dialog be necessary.
+
+WHEN ADVERTISED BUNDLE(S) REQUIRE FURTHER NEGOTIATION::
+A client SHOULD commence a negotiation of a PACK from the server via
+the "fetch" command using the OID tips found in advertised bundles,
+even if's still in the process of downloading those bundle(s).
++
+This allows for aggressive early disconnects from any interactive
+server dialog. The client blindly trusts that the advertised OID tips
+are relevant, and issues them as 'have' lines, it then requests any
+tips it would like (usually from the "ls-refs" advertisement) via
+'want' lines. The server will then compute a (hopefully small) PACK
+with the expected difference between the tips from the bundle(s) and
+the data requested.
++
+The only connection the client then needs to keep active is to the
+concurrently downloading static bundle(s), when those and the
+incremental PACK are retrieved they should be inflated and
+validated. Any errors at this point should be gracefully recovered
+from, see above.
+
+bundle-uri PROTOCOL FEATURES
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The client constructs a bundle list from the `<key>=<value>` pairs
+provided by the server. These pairs are part of the `bundle.*` namespace
+as documented in linkgit:git-config[1]. In this section, we discuss some
+of these keys and describe the actions the client will do in response to
+this information.
+
+In particular, the `bundle.version` key specifies an integer value. The
+only accepted value at the moment is `1`, but if the client sees an
+unexpected value here then the client MUST ignore the bundle list.
+
+As long as `bundle.version` is understood, all other unknown keys MAY be
+ignored by the client. The server will guarantee compatibility with older
+clients, though newer clients may be better able to use the extra keys to
+minimize downloads.
+
+Any backwards-incompatible addition of pre-URI key-value will be
+guarded by a new `bundle.version` value or values in 'bundle-uri'
+capability advertisement itself, and/or by new future `bundle-uri`
+request arguments.
+
+Some example key-value pairs that are not currently implemented but could
+be implemented in the future include:
+
+ * Add a "hash=<val>" or "size=<bytes>" advertise the expected hash or
+   size of the bundle file.
+
+ * Advertise that one or more bundle files are the same (to e.g. have
+   clients round-robin or otherwise choose one of N possible files).
+
+ * A "oid=<OID>" shortcut and "prerequisite=<OID>" shortcut. For
+   expressing the common case of a bundle with one tip and no
+   prerequisites, or one tip and one prerequisite.
++
+This would allow for optimizing the common case of servers who'd like
+to provide one "big bundle" containing only their "main" branch,
+and/or incremental updates thereof.
++
+A client receiving such a a response MAY assume that they can skip
+retrieving the header from a bundle at the indicated URI, and thus
+save themselves and the server(s) the request(s) needed to inspect the
+headers of that bundle or bundles.
+
 GIT
 ---
 Part of the linkgit:git[1] suite
index 0f7d7ab1fd29f99010da56d982d026401cb78d59..db447d073839458b97ffe47a64b1a21a82c752d9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -511,10 +511,8 @@ include shared.mak
 # Define BLK_SHA1 to make use of optimized C SHA-1 routines bundled
 # with git (in the block-sha1/ directory).
 #
-# Define NO_APPLE_COMMON_CRYPTO on OSX to opt-out of using the
-# "APPLE_COMMON_CRYPTO" backend for SHA-1, which is currently the
-# default on that OS. On macOS 01.4 (Tiger) or older,
-# NO_APPLE_COMMON_CRYPTO is defined by default.
+# Define APPLE_COMMON_CRYPTO_SHA1 to use Apple's CommonCrypto for
+# SHA-1.
 #
 # If don't enable any of the *_SHA1 settings in this section, Git will
 # default to its built-in sha1collisiondetection library, which is a
@@ -1911,7 +1909,7 @@ ifdef NO_POSIX_GOODIES
        BASIC_CFLAGS += -DNO_POSIX_GOODIES
 endif
 
-ifdef APPLE_COMMON_CRYPTO
+ifdef APPLE_COMMON_CRYPTO_SHA1
        # Apple CommonCrypto requires chunking
        SHA1_MAX_BLOCK_SIZE = 1024L*1024L*1024L
 endif
@@ -1928,7 +1926,7 @@ ifdef BLK_SHA1
        LIB_OBJS += block-sha1/sha1.o
        BASIC_CFLAGS += -DSHA1_BLK
 else
-ifdef APPLE_COMMON_CRYPTO
+ifdef APPLE_COMMON_CRYPTO_SHA1
        COMPAT_CFLAGS += -DCOMMON_DIGEST_FOR_OPENSSL
        BASIC_CFLAGS += -DSHA1_APPLE
 else
index ae1839c04a7fa27125e4a2308c971e63da18492a..00a0f6f96f3f5ebc54bbfb841921c5ceff88c1c3 100644 (file)
@@ -724,7 +724,7 @@ static int run_update(struct add_i_state *s, const struct pathspec *ps,
 }
 
 static void revert_from_diff(struct diff_queue_struct *q,
-                            struct diff_options *opt, void *data)
+                            struct diff_options *opt, void *data UNUSED)
 {
        int i, add_flags = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE;
 
diff --git a/apply.c b/apply.c
index bc338143134528bcb5e8e7ab56494ad1bfe04a7c..85822280476dc9b729943119802c60d76fd74134 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -2913,7 +2913,7 @@ static int apply_one_fragment(struct apply_state *state,
                        break;
                case ' ':
                        if (plen && (ws_rule & WS_BLANK_AT_EOF) &&
-                           ws_blank_line(patch + 1, plen, ws_rule))
+                           ws_blank_line(patch + 1, plen))
                                is_blank_context = 1;
                        /* fallthrough */
                case '-':
@@ -2942,7 +2942,7 @@ static int apply_one_fragment(struct apply_state *state,
                                      (first == '+' ? 0 : LINE_COMMON));
                        if (first == '+' &&
                            (ws_rule & WS_BLANK_AT_EOF) &&
-                           ws_blank_line(patch + 1, plen, ws_rule))
+                           ws_blank_line(patch + 1, plen))
                                added_blank_line = 1;
                        break;
                case '@': case '\\':
diff --git a/blob.c b/blob.c
index 182718aba9fe320f1064a12fb5baf1969f563b29..8f83523b0cde6dbf1b808b3dcf8ab1c1c23085f3 100644 (file)
--- a/blob.c
+++ b/blob.c
@@ -13,8 +13,7 @@ struct blob *lookup_blob(struct repository *r, const struct object_id *oid)
        return object_as_type(obj, OBJ_BLOB, 0);
 }
 
-int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size)
+void parse_blob_buffer(struct blob *item)
 {
        item->object.parsed = 1;
-       return 0;
 }
diff --git a/blob.h b/blob.h
index 1664872055783557e1836dcc64bc2f51c20c5b4f..74555c90c449ffa89226d264f46c433580707f61 100644 (file)
--- a/blob.h
+++ b/blob.h
@@ -11,8 +11,6 @@ struct blob {
 
 struct blob *lookup_blob(struct repository *r, const struct object_id *oid);
 
-int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size);
-
 /**
  * Blobs do not contain references to other objects and do not have
  * structured data that needs parsing. However, code may use the
@@ -21,5 +19,6 @@ int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size);
  * parse_blob_buffer() is used (by object.c) to flag that the object
  * has been read successfully from the database.
  **/
+void parse_blob_buffer(struct blob *item);
 
 #endif /* BLOB_H */
index 2c154cc347965bbc82804ed30b87d7fea4db9c01..0c60402267653c5aff56c8b2bd1702793e4170be 100644 (file)
@@ -88,7 +88,7 @@ static int fix_unmerged_status(struct diff_filepair *p,
 }
 
 static void update_callback(struct diff_queue_struct *q,
-                           struct diff_options *opt, void *cbdata)
+                           struct diff_options *opt UNUSED, void *cbdata)
 {
        int i;
        struct update_callback_data *data = cbdata;
index 30c9b3a9cd72588fc2fb4495faedcc7cf3eda258..dddf1b9af0144429c067fc8c1fc6587dc14f7502 100644 (file)
@@ -1476,6 +1476,7 @@ static int run_apply(const struct am_state *state, const char *index_file)
        int res, opts_left;
        int force_apply = 0;
        int options = 0;
+       const char **apply_argv;
 
        if (init_apply_state(&apply_state, the_repository, NULL))
                BUG("init_apply_state() failed");
@@ -1483,7 +1484,15 @@ static int run_apply(const struct am_state *state, const char *index_file)
        strvec_push(&apply_opts, "apply");
        strvec_pushv(&apply_opts, state->git_apply_opts.v);
 
-       opts_left = apply_parse_options(apply_opts.nr, apply_opts.v,
+       /*
+        * Build a copy that apply_parse_options() can rearrange.
+        * apply_opts.v keeps referencing the allocated strings for
+        * strvec_clear() to release.
+        */
+       ALLOC_ARRAY(apply_argv, apply_opts.nr);
+       COPY_ARRAY(apply_argv, apply_opts.v, apply_opts.nr);
+
+       opts_left = apply_parse_options(apply_opts.nr, apply_argv,
                                        &apply_state, &force_apply, &options,
                                        NULL);
 
@@ -1513,6 +1522,7 @@ static int run_apply(const struct am_state *state, const char *index_file)
        strvec_clear(&apply_paths);
        strvec_clear(&apply_opts);
        clear_apply_state(&apply_state);
+       free(apply_argv);
 
        if (res)
                return res;
index 9470c980c15dca8a96c264772991b51813f1b355..f63fd45edb96b513c24e1a9cd7c8a55e5a5f7b13 100644 (file)
@@ -581,13 +581,13 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
        strbuf_release(&logmsg);
 
        strbuf_addf(&oldsection, "branch.%s", interpreted_oldname);
-       strbuf_release(&oldref);
        strbuf_addf(&newsection, "branch.%s", interpreted_newname);
-       strbuf_release(&newref);
        if (!copy && git_config_rename_section(oldsection.buf, newsection.buf) < 0)
                die(_("Branch is renamed, but update of config-file failed"));
-       if (copy && strcmp(oldname, newname) && git_config_copy_section(oldsection.buf, newsection.buf) < 0)
+       if (copy && strcmp(interpreted_oldname, interpreted_newname) && git_config_copy_section(oldsection.buf, newsection.buf) < 0)
                die(_("Branch is copied, but update of config-file failed"));
+       strbuf_release(&oldref);
+       strbuf_release(&newref);
        strbuf_release(&oldsection);
        strbuf_release(&newsection);
 }
index b3be58b1fb06678376568753f9fc221d8cfb3750..cc17635e76536471a0a756903a8187eaa01d5733 100644 (file)
@@ -132,8 +132,21 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
 
        case 's':
                oi.sizep = &size;
+
+               if (use_mailmap) {
+                       oi.typep = &type;
+                       oi.contentp = (void**)&buf;
+               }
+
                if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0)
                        die("git cat-file: could not get object info");
+
+               if (use_mailmap && (type == OBJ_COMMIT || type == OBJ_TAG)) {
+                       size_t s = size;
+                       buf = replace_idents_using_mailmap(buf, &s);
+                       size = cast_size_t_to_ulong(s);
+               }
+
                printf("%"PRIuMAX"\n", (uintmax_t)size);
                ret = 0;
                goto cleanup;
@@ -431,6 +444,9 @@ static void batch_object_write(const char *obj_name,
        if (!data->skip_object_info) {
                int ret;
 
+               if (use_mailmap)
+                       data->info.typep = &data->type;
+
                if (pack)
                        ret = packed_object_info(the_repository, pack, offset,
                                                 &data->info);
@@ -444,6 +460,18 @@ static void batch_object_write(const char *obj_name,
                        fflush(stdout);
                        return;
                }
+
+               if (use_mailmap && (data->type == OBJ_COMMIT || data->type == OBJ_TAG)) {
+                       size_t s = data->size;
+                       char *buf = NULL;
+
+                       buf = repo_read_object_file(the_repository, &data->oid, &data->type,
+                                                   &data->size);
+                       buf = replace_idents_using_mailmap(buf, &s);
+                       data->size = cast_size_t_to_ulong(s);
+
+                       free(buf);
+               }
        }
 
        strbuf_reset(scratch);
index f518bb2dc1fbad357e93511d8deee851ef56b812..5453ba5277f968cbac419b7aee9911182beb41e6 100644 (file)
@@ -1271,6 +1271,27 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
        if (refs)
                mapped_refs = wanted_peer_refs(refs, &remote->fetch);
 
+       if (!bundle_uri) {
+               /*
+               * Populate transport->got_remote_bundle_uri and
+               * transport->bundle_uri. We might get nothing.
+               */
+               transport_get_remote_bundle_uri(transport);
+
+               if (transport->bundles &&
+                   hashmap_get_size(&transport->bundles->bundles)) {
+                       /* At this point, we need the_repository to match the cloned repo. */
+                       if (repo_init(the_repository, git_dir, work_tree))
+                               warning(_("failed to initialize the repo, skipping bundle URI"));
+                       else if (fetch_bundle_list(the_repository,
+                                                  transport->bundles))
+                               warning(_("failed to fetch advertised bundles"));
+               } else {
+                       clear_bundle_list(transport->bundles);
+                       FREE_AND_NULL(transport->bundles);
+               }
+       }
+
        if (mapped_refs) {
                int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
 
index 3b3314e7b2a3343b78d14ee3bc9d4a92fb578fd6..39a890fc005192a5082a1c170550f4be102efbc1 100644 (file)
@@ -409,7 +409,7 @@ static const char *anonymize_oid(const char *oid_hex)
 }
 
 static void show_filemodify(struct diff_queue_struct *q,
-                           struct diff_options *options, void *data)
+                           struct diff_options *options UNUSED, void *data)
 {
        int i;
        struct string_list *changed = data;
index 6f30a4f93a7fa93873e40312a0fcb569056daf88..0feef8caf6d5e27d508b3d4ea3e2679cd50a9966 100644 (file)
@@ -710,6 +710,7 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
                                  "fsmonitor: unsupported V1 protocol '%s'"),
                                 command);
                do_trivial = 1;
+               do_cookie = 1;
 
        } else {
                /* We have "builtin:*" */
@@ -719,6 +720,7 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
                                         "fsmonitor: invalid V2 protocol token '%s'",
                                         command);
                        do_trivial = 1;
+                       do_cookie = 1;
 
                } else {
                        /*
@@ -1209,7 +1211,7 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
         * events.
         */
        if (pthread_create(&state->listener_thread, NULL,
-                          fsm_listen__thread_proc, state) < 0) {
+                          fsm_listen__thread_proc, state)) {
                ipc_server_stop_async(state->ipc_server_data);
                err = error(_("could not start fsmonitor listener thread"));
                goto cleanup;
@@ -1220,7 +1222,7 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
         * Start the health thread to watch over our process.
         */
        if (pthread_create(&state->health_thread, NULL,
-                          fsm_health__thread_proc, state) < 0) {
+                          fsm_health__thread_proc, state)) {
                ipc_server_stop_async(state->ipc_server_data);
                err = error(_("could not start fsmonitor health thread"));
                goto cleanup;
index 89447a50838562795bb80172db8102ff7a42e91b..057e299c245c7d4a043fb37ff0e6d6e5a8a6e6d9 100644 (file)
@@ -52,6 +52,7 @@ static int decoration_style;
 static int decoration_given;
 static int use_mailmap_config = 1;
 static unsigned int force_in_body_from;
+static int stdout_mboxrd;
 static const char *fmt_patch_subject_prefix = "PATCH";
 static int fmt_patch_name_max = FORMAT_PATCH_NAME_MAX_DEFAULT;
 static const char *fmt_pretty;
@@ -1077,6 +1078,10 @@ static int git_format_config(const char *var, const char *value, void *cb)
                cover_from_description_mode = parse_cover_from_description(value);
                return 0;
        }
+       if (!strcmp(var, "format.mboxrd")) {
+               stdout_mboxrd = git_config_bool(var, value);
+               return 0;
+       }
 
        return git_log_config(var, value, cb);
 }
@@ -2105,6 +2110,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
                                  rev.diffopt.close_file, "--output",
                                  !!output_directory, "--output-directory");
 
+       if (use_stdout && stdout_mboxrd)
+               rev.commit_format = CMIT_FMT_MBOXRD;
+
        if (use_stdout) {
                setup_pager();
        } else if (!rev.diffopt.close_file) {
index c8265e0aec7f902b173f75f4df3f072bddfbd6b3..828dc81c426514d822e6bbce172495373f9a92c5 100644 (file)
@@ -99,7 +99,7 @@ static void *origin(struct merge_list *entry, unsigned long *size)
        return NULL;
 }
 
-static int show_outf(void *priv_, mmbuffer_t *mb, int nbuf)
+static int show_outf(void *priv UNUSED, mmbuffer_t *mb, int nbuf)
 {
        int i;
        for (i = 0; i < nbuf; i++)
index ecccd5e91196abcc3211dc255e84fd74ad024b51..0f093f2a4f221c2ee22e629cd9e069ee201f268a 100644 (file)
@@ -776,7 +776,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
 }
 
 static void count_diff_files(struct diff_queue_struct *q,
-                            struct diff_options *opt, void *data)
+                            struct diff_options *opt UNUSED, void *data)
 {
        int *count = data;
 
index e2a74efb42a795a5139932bd052999d050cab420..aecfae12d3ae0777a57bec2c02dffa7cffde3d8f 100644 (file)
@@ -47,7 +47,7 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix)
 
        repo_diff_setup(the_repository, &diffopt);
 
-       options = parse_options_concat(range_diff_options, diffopt.parseopts);
+       options = add_diff_options(range_diff_options, &diffopt);
        argc = parse_options(argc, argv, prefix, options,
                             builtin_range_diff_usage, PARSE_OPT_KEEP_DASHDASH);
 
index 8b7392d5b4483ff961e14fc7ae5194d97d188d8b..94ffb8c21ab1e08f1775ad15315dd689723a2db8 100644 (file)
@@ -14,7 +14,7 @@ static const char * const rerere_usage[] = {
        NULL,
 };
 
-static int outf(void *dummy, mmbuffer_t *ptr, int nbuf)
+static int outf(void *dummy UNUSED, mmbuffer_t *ptr, int nbuf)
 {
        int i;
        for (i = 0; i < nbuf; i++)
index dbf6fdfaf0edd43f9e1d46718c1ebb5db55630f3..fea20a9ba0b99bc730f7c7fc7c1000fa57febf3e 100644 (file)
@@ -133,7 +133,8 @@ static void print_new_head_line(struct commit *commit)
 }
 
 static void update_index_from_diff(struct diff_queue_struct *q,
-               struct diff_options *opt, void *data)
+                                  struct diff_options *opt UNUSED,
+                                  void *data)
 {
        int i;
        int intent_to_add = *(int *)data;
index 05f2c9bc9858d98ae855b566d6128030e002fa18..6743fb27bd55aed6c143666818022076948415dd 100644 (file)
@@ -1043,7 +1043,7 @@ static void prepare_submodule_summary(struct summary_cb *info,
 }
 
 static void submodule_summary_callback(struct diff_queue_struct *q,
-                                      struct diff_options *options,
+                                      struct diff_options *options UNUSED,
                                       void *data)
 {
        int i;
index a1a2522126f31c2d14e4c5dc96098e8516fdb781..a80c1df86fd532bb6353b990381bfb050ac5e688 100644 (file)
@@ -14,6 +14,11 @@ static const char *editor(int flag)
        return git_editor();
 }
 
+static const char *sequence_editor(int flag)
+{
+       return git_sequence_editor();
+}
+
 static const char *pager(int flag)
 {
        const char *pgm = git_pager(1);
@@ -36,6 +41,7 @@ static struct git_var git_vars[] = {
        { "GIT_COMMITTER_IDENT", git_committer_info },
        { "GIT_AUTHOR_IDENT",   git_author_info },
        { "GIT_EDITOR", editor },
+       { "GIT_SEQUENCE_EDITOR", sequence_editor },
        { "GIT_PAGER", pager },
        { "GIT_DEFAULT_BRANCH", default_branch },
        { "", NULL },
index 79a914f961b134cccc6029aa403d7a626841c81b..36268dda172511250cdda7a24db8cfdb00548f6f 100644 (file)
@@ -7,6 +7,7 @@
 #include "hashmap.h"
 #include "pkt-line.h"
 #include "config.h"
+#include "remote.h"
 
 static int compare_bundles(const void *hashmap_cmp_fn_data,
                           const struct hashmap_entry *he1,
@@ -49,6 +50,7 @@ void clear_bundle_list(struct bundle_list *list)
 
        for_all_bundles_in_list(list, clear_remote_bundle_info, NULL);
        hashmap_clear_and_free(&list->bundles, struct remote_bundle_info, ent);
+       free(list->baseURI);
 }
 
 int for_all_bundles_in_list(struct bundle_list *list,
@@ -163,7 +165,7 @@ static int bundle_list_update(const char *key, const char *value,
        if (!strcmp(subkey, "uri")) {
                if (bundle->uri)
                        return -1;
-               bundle->uri = xstrdup(value);
+               bundle->uri = relative_url(list->baseURI, value, NULL);
                return 0;
        }
 
@@ -190,6 +192,18 @@ int bundle_uri_parse_config_format(const char *uri,
                .error_action = CONFIG_ERROR_ERROR,
        };
 
+       if (!list->baseURI) {
+               struct strbuf baseURI = STRBUF_INIT;
+               strbuf_addstr(&baseURI, uri);
+
+               /*
+                * If the URI does not end with a trailing slash, then
+                * remove the filename portion of the path. This is
+                * important for relative URIs.
+                */
+               strbuf_strip_file_from_path(&baseURI);
+               list->baseURI = strbuf_detach(&baseURI, NULL);
+       }
        result = git_config_from_file_with_options(config_to_bundle_list,
                                                   filename, list,
                                                   &opts);
@@ -563,6 +577,77 @@ cleanup:
        return result;
 }
 
+int fetch_bundle_list(struct repository *r, struct bundle_list *list)
+{
+       int result;
+       struct bundle_list global_list;
+
+       init_bundle_list(&global_list);
+
+       /* If a bundle is added to this global list, then it is required. */
+       global_list.mode = BUNDLE_MODE_ALL;
+
+       if ((result = download_bundle_list(r, list, &global_list, 0)))
+               goto cleanup;
+
+       result = unbundle_all_bundles(r, &global_list);
+
+cleanup:
+       for_all_bundles_in_list(&global_list, unlink_bundle, NULL);
+       clear_bundle_list(&global_list);
+       return result;
+}
+
+/**
+ * API for serve.c.
+ */
+
+int bundle_uri_advertise(struct repository *r, struct strbuf *value UNUSED)
+{
+       static int advertise_bundle_uri = -1;
+
+       if (advertise_bundle_uri != -1)
+               goto cached;
+
+       advertise_bundle_uri = 0;
+       repo_config_get_maybe_bool(r, "uploadpack.advertisebundleuris", &advertise_bundle_uri);
+
+cached:
+       return advertise_bundle_uri;
+}
+
+static int config_to_packet_line(const char *key, const char *value, void *data)
+{
+       struct packet_reader *writer = data;
+
+       if (!strncmp(key, "bundle.", 7))
+               packet_write_fmt(writer->fd, "%s=%s", key, value);
+
+       return 0;
+}
+
+int bundle_uri_command(struct repository *r,
+                      struct packet_reader *request)
+{
+       struct packet_writer writer;
+       packet_writer_init(&writer, 1);
+
+       while (packet_reader_read(request) == PACKET_READ_NORMAL)
+               die(_("bundle-uri: unexpected argument: '%s'"), request->line);
+       if (request->status != PACKET_READ_FLUSH)
+               die(_("bundle-uri: expected flush after arguments"));
+
+       /*
+        * Read all "bundle.*" config lines to the client as key=value
+        * packet lines.
+        */
+       git_config(config_to_packet_line, &writer);
+
+       packet_writer_flush(&writer);
+
+       return 0;
+}
+
 /**
  * General API for {transport,connect}.c etc.
  */
index 4dbc269823cc3a6b4a523b199a8a6d8a83219578..d5e89f1671caa3717b35242f20b8993cea32d14f 100644 (file)
@@ -4,6 +4,7 @@
 #include "hashmap.h"
 #include "strbuf.h"
 
+struct packet_reader;
 struct repository;
 struct string_list;
 
@@ -60,6 +61,20 @@ struct bundle_list {
        int version;
        enum bundle_list_mode mode;
        struct hashmap bundles;
+
+       /**
+        * The baseURI of a bundle_list is the URI that provided the list.
+        *
+        * In the case of the 'bundle-uri' protocol v2 command, the base
+        * URI is the URI of the Git remote.
+        *
+        * Otherwise, the bundle list was downloaded over HTTP from some
+        * known URI. 'baseURI' is set to that value.
+        *
+        * The baseURI is used as the base for any relative URIs
+        * advertised by the bundle list at that location.
+        */
+       char *baseURI;
 };
 
 void init_bundle_list(struct bundle_list *list);
@@ -92,6 +107,26 @@ int bundle_uri_parse_config_format(const char *uri,
  */
 int fetch_bundle_uri(struct repository *r, const char *uri);
 
+/**
+ * Given a bundle list that was already advertised (likely by the
+ * bundle-uri protocol v2 verb) at the given uri, fetch and unbundle the
+ * bundles according to the bundle strategy of that list.
+ *
+ * It is expected that the given 'list' is initialized, including its
+ * 'baseURI' value.
+ *
+ * Returns non-zero if there was an error trying to download the list
+ * or any of its advertised bundles.
+ */
+int fetch_bundle_list(struct repository *r,
+                     struct bundle_list *list);
+
+/**
+ * API for serve.c.
+ */
+int bundle_uri_advertise(struct repository *r, struct strbuf *value);
+int bundle_uri_command(struct repository *r, struct packet_reader *request);
+
 /**
  * General API for {transport,connect}.c etc.
  */
diff --git a/cache.h b/cache.h
index 07d40b0964b12b9f4875c20f26540585ffdc792e..fcf49706ad56ad407774405e94058685c59009ef 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -1865,7 +1865,7 @@ unsigned ws_check(const char *line, int len, unsigned ws_rule);
 void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *stream, const char *set, const char *reset, const char *ws);
 char *whitespace_error_string(unsigned ws);
 void ws_fix_copy(struct strbuf *, const char *, int, unsigned, int *);
-int ws_blank_line(const char *line, int len, unsigned ws_rule);
+int ws_blank_line(const char *line, int len);
 #define ws_tab_width(rule)     ((rule) & WS_TAB_WIDTH_MASK)
 
 /* ls-files */
index 706e3ba7e938d83091d1557ed20f7356e557f61d..db7105e8a8dcdff1432d5ec972e3262e4f787c16 100755 (executable)
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -258,8 +258,7 @@ macos-*)
                MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=$(which python3)"
        else
                MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=$(which python2)"
-               MAKEFLAGS="$MAKEFLAGS NO_APPLE_COMMON_CRYPTO=NoThanks"
-               MAKEFLAGS="$MAKEFLAGS NO_OPENSSL=NoThanks"
+               MAKEFLAGS="$MAKEFLAGS APPLE_COMMON_CRYPTO_SHA1=Yes"
        fi
        ;;
 esac
index b0ece9548082c17510b6abd17427434bbf66cae9..1a39b5dde0946df0c1e36c7b1f4c48552885985a 100644 (file)
@@ -372,7 +372,7 @@ struct combine_diff_state {
 static void consume_hunk(void *state_,
                         long ob, long on,
                         long nb, long nn,
-                        const char *funcline, long funclen)
+                        const char *func UNUSED, long funclen UNUSED)
 {
        struct combine_diff_state *state = state_;
 
index 572301b80a2a3723daea5e16bc6d77977c95543c..14538a811ae0e000f140caf2f4738c89116684a5 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -508,6 +508,17 @@ int repo_parse_commit_internal(struct repository *r,
        enum object_type type;
        void *buffer;
        unsigned long size;
+       struct object_info oi = {
+               .typep = &type,
+               .sizep = &size,
+               .contentp = &buffer,
+       };
+       /*
+        * Git does not support partial clones that exclude commits, so set
+        * OBJECT_INFO_SKIP_FETCH_OBJECT to fail fast when an object is missing.
+        */
+       int flags = OBJECT_INFO_LOOKUP_REPLACE | OBJECT_INFO_SKIP_FETCH_OBJECT |
+               OBJECT_INFO_DIE_IF_CORRUPT;
        int ret;
 
        if (!item)
@@ -516,8 +527,8 @@ int repo_parse_commit_internal(struct repository *r,
                return 0;
        if (use_commit_graph && parse_commit_in_graph(r, item))
                return 0;
-       buffer = repo_read_object_file(r, &item->object.oid, &type, &size);
-       if (!buffer)
+
+       if (oid_object_info_extended(r, &item->object.oid, &oi, flags) < 0)
                return quiet_on_missing ? -1 :
                        error("Could not read %s",
                             oid_to_hex(&item->object.oid));
@@ -701,8 +712,10 @@ static void clear_commit_marks_1(struct commit_list **plist,
                if (!parents)
                        return;
 
-               while ((parents = parents->next))
-                       commit_list_insert(parents->item, plist);
+               while ((parents = parents->next)) {
+                       if (parents->item->object.flags & mark)
+                               commit_list_insert(parents->item, plist);
+               }
 
                commit = commit->parents->item;
        }
index 1c75c3d48e7d7c3d960e4cf7ff3bf672f4fe1432..3496e29b3a1f1b8ea04224b63b65539edda602df 100644 (file)
@@ -80,9 +80,7 @@ void CFRunLoopRun(void);
 void CFRunLoopStop(CFRunLoopRef run_loop);
 CFRunLoopRef CFRunLoopGetCurrent(void);
 extern CFStringRef kCFRunLoopDefaultMode;
-void FSEventStreamScheduleWithRunLoop(FSEventStreamRef stream,
-                                     CFRunLoopRef run_loop,
-                                     CFStringRef run_loop_mode);
+void FSEventStreamSetDispatchQueue(FSEventStreamRef stream, dispatch_queue_t q);
 unsigned char FSEventStreamStart(FSEventStreamRef stream);
 void FSEventStreamStop(FSEventStreamRef stream);
 void FSEventStreamInvalidate(FSEventStreamRef stream);
index cc9af1e3cb3b3afca7d519147c4ae252b9f5832a..97a55a6f0a42d8c0ba8b1d14e077e60e7fdd55df 100644 (file)
@@ -1,4 +1,5 @@
 #ifndef __clang__
+#include <dispatch/dispatch.h>
 #include "fsm-darwin-gcc.h"
 #else
 #include <CoreFoundation/CoreFoundation.h>
@@ -38,7 +39,9 @@ struct fsm_listen_data
 
        FSEventStreamRef stream;
 
-       CFRunLoopRef rl;
+       dispatch_queue_t dq;
+       pthread_cond_t dq_finished;
+       pthread_mutex_t dq_lock;
 
        enum shutdown_style {
                SHUTDOWN_EVENT = 0,
@@ -379,8 +382,11 @@ force_shutdown:
        fsmonitor_batch__free_list(batch);
        string_list_clear(&cookie_list, 0);
 
+       pthread_mutex_lock(&data->dq_lock);
        data->shutdown_style = FORCE_SHUTDOWN;
-       CFRunLoopStop(data->rl);
+       pthread_cond_broadcast(&data->dq_finished);
+       pthread_mutex_unlock(&data->dq_lock);
+
        strbuf_release(&tmp);
        return;
 }
@@ -441,10 +447,6 @@ int fsm_listen__ctor(struct fsmonitor_daemon_state *state)
        if (!data->stream)
                goto failed;
 
-       /*
-        * `data->rl` needs to be set inside the listener thread.
-        */
-
        return 0;
 
 failed:
@@ -471,6 +473,11 @@ void fsm_listen__dtor(struct fsmonitor_daemon_state *state)
                FSEventStreamRelease(data->stream);
        }
 
+       if (data->dq)
+               dispatch_release(data->dq);
+       pthread_cond_destroy(&data->dq_finished);
+       pthread_mutex_destroy(&data->dq_lock);
+
        FREE_AND_NULL(state->listen_data);
 }
 
@@ -479,9 +486,11 @@ void fsm_listen__stop_async(struct fsmonitor_daemon_state *state)
        struct fsm_listen_data *data;
 
        data = state->listen_data;
-       data->shutdown_style = SHUTDOWN_EVENT;
 
-       CFRunLoopStop(data->rl);
+       pthread_mutex_lock(&data->dq_lock);
+       data->shutdown_style = SHUTDOWN_EVENT;
+       pthread_cond_broadcast(&data->dq_finished);
+       pthread_mutex_unlock(&data->dq_lock);
 }
 
 void fsm_listen__loop(struct fsmonitor_daemon_state *state)
@@ -490,9 +499,11 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
 
        data = state->listen_data;
 
-       data->rl = CFRunLoopGetCurrent();
+       pthread_mutex_init(&data->dq_lock, NULL);
+       pthread_cond_init(&data->dq_finished, NULL);
+       data->dq = dispatch_queue_create("FSMonitor", NULL);
 
-       FSEventStreamScheduleWithRunLoop(data->stream, data->rl, kCFRunLoopDefaultMode);
+       FSEventStreamSetDispatchQueue(data->stream, data->dq);
        data->stream_scheduled = 1;
 
        if (!FSEventStreamStart(data->stream)) {
@@ -501,7 +512,9 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
        }
        data->stream_started = 1;
 
-       CFRunLoopRun();
+       pthread_mutex_lock(&data->dq_lock);
+       pthread_cond_wait(&data->dq_finished, &data->dq_lock);
+       pthread_mutex_unlock(&data->dq_lock);
 
        switch (data->shutdown_style) {
        case FORCE_ERROR_STOP:
index d614f156df1db31248e3a1de51273ffefdd671ff..af397e68a1dc0de834df7ee6ab98125622c29de3 100644 (file)
@@ -2752,7 +2752,7 @@ int is_path_owned_by_current_sid(const char *path, struct strbuf *report)
                        /*
                         * On FAT32 volumes, ownership is not actually recorded.
                         */
-                       strbuf_addf(report, "'%s' is on a file system that does"
+                       strbuf_addf(report, "'%s' is on a file system that does "
                                    "not record ownership\n", path);
                } else if (report) {
                        LPSTR str1, str2, to_free1 = NULL, to_free2 = NULL;
index 737983d00bae9190e6a328ccf9a2b1a4914fa109..cc3221cb2c8a84a454784c7fa0dc287dbad83983 100644 (file)
@@ -66,7 +66,7 @@ pthread_t pthread_self(void);
 
 static inline void NORETURN pthread_exit(void *ret)
 {
-       ExitThread((DWORD)(intptr_t)ret);
+       _endthreadex((unsigned)(uintptr_t)ret);
 }
 
 typedef DWORD pthread_key_t;
index 5ea53deda23527ded642449fa9d803cc12e34477..63e59641c0d4d5c60fc4bee2761e6acd471535a2 100644 (file)
--- a/connect.c
+++ b/connect.c
@@ -15,6 +15,7 @@
 #include "version.h"
 #include "protocol.h"
 #include "alias.h"
+#include "bundle-uri.h"
 
 static char *server_capabilities_v1;
 static struct strvec server_capabilities_v2 = STRVEC_INIT;
@@ -66,7 +67,7 @@ static NORETURN void die_initial_contact(int unexpected)
 }
 
 /* Checks if the server supports the capability 'c' */
-int server_supports_v2(const char *c, int die_on_error)
+int server_supports_v2(const char *c)
 {
        int i;
 
@@ -76,11 +77,13 @@ int server_supports_v2(const char *c, int die_on_error)
                    (!*out || *out == '='))
                        return 1;
        }
+       return 0;
+}
 
-       if (die_on_error)
+void ensure_server_supports_v2(const char *c)
+{
+       if (!server_supports_v2(c))
                die(_("server doesn't support '%s'"), c);
-
-       return 0;
 }
 
 int server_feature_v2(const char *c, const char **v)
@@ -477,7 +480,7 @@ static void send_capabilities(int fd_out, struct packet_reader *reader)
 {
        const char *hash_name;
 
-       if (server_supports_v2("agent", 0))
+       if (server_supports_v2("agent"))
                packet_write_fmt(fd_out, "agent=%s", git_user_agent_sanitized());
 
        if (server_feature_v2("object-format", &hash_name)) {
@@ -491,6 +494,49 @@ static void send_capabilities(int fd_out, struct packet_reader *reader)
        }
 }
 
+int get_remote_bundle_uri(int fd_out, struct packet_reader *reader,
+                         struct bundle_list *bundles, int stateless_rpc)
+{
+       int line_nr = 1;
+
+       /* Assert bundle-uri support */
+       ensure_server_supports_v2("bundle-uri");
+
+       /* (Re-)send capabilities */
+       send_capabilities(fd_out, reader);
+
+       /* Send command */
+       packet_write_fmt(fd_out, "command=bundle-uri\n");
+       packet_delim(fd_out);
+
+       packet_flush(fd_out);
+
+       /* Process response from server */
+       while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
+               const char *line = reader->line;
+               line_nr++;
+
+               if (!bundle_uri_parse_line(bundles, line))
+                       continue;
+
+               return error(_("error on bundle-uri response line %d: %s"),
+                            line_nr, line);
+       }
+
+       if (reader->status != PACKET_READ_FLUSH)
+               return error(_("expected flush after bundle-uri listing"));
+
+       /*
+        * Might die(), but obscure enough that that's OK, e.g. in
+        * serve.c we'll call BUG() on its equivalent (the
+        * PACKET_READ_RESPONSE_END check).
+        */
+       check_stateless_delimiter(stateless_rpc, reader,
+                                 _("expected response end packet after ref listing"));
+
+       return 0;
+}
+
 struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
                             struct ref **list, int for_push,
                             struct transport_ls_refs_options *transport_options,
@@ -504,17 +550,18 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
                &transport_options->unborn_head_target : NULL;
        *list = NULL;
 
-       if (server_supports_v2("ls-refs", 1))
-               packet_write_fmt(fd_out, "command=ls-refs\n");
+       ensure_server_supports_v2("ls-refs");
+       packet_write_fmt(fd_out, "command=ls-refs\n");
 
        /* Send capabilities */
        send_capabilities(fd_out, reader);
 
-       if (server_options && server_options->nr &&
-           server_supports_v2("server-option", 1))
+       if (server_options && server_options->nr) {
+               ensure_server_supports_v2("server-option");
                for (i = 0; i < server_options->nr; i++)
                        packet_write_fmt(fd_out, "server-option=%s",
                                         server_options->items[i].string);
+       }
 
        packet_delim(fd_out);
        /* When pushing we don't want to request the peeled tags */
index c53586e929e8b6f11194d9aeb9934e0fbecd5983..b26f7de7841838e0d6e88bb81169191f579fb56d 100644 (file)
--- a/connect.h
+++ b/connect.h
@@ -20,7 +20,8 @@ enum protocol_version discover_version(struct packet_reader *reader);
 
 int server_supports_hash(const char *desired, int *feature_supported);
 const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp, int *offset);
-int server_supports_v2(const char *c, int die_on_error);
+int server_supports_v2(const char *c);
+void ensure_server_supports_v2(const char *c);
 int server_feature_v2(const char *c, const char **v);
 int server_supports_feature(const char *c, const char *feature,
                            int die_on_error);
index ba5c395d2d804f522d5730f7bca2fa6e17d63a96..dc95c34cc853557efd2a59a33825f834e8d934cf 100644 (file)
 #
 #     When set to "1" suggest all options, including options which are
 #     typically hidden (e.g. '--allow-empty' for 'git commit').
+#
+#   GIT_COMPLETION_IGNORE_CASE
+#
+#     When set, uses for-each-ref '--ignore-case' to find refs that match
+#     case insensitively, even on systems with case sensitive file systems
+#     (e.g., completing tag name "FOO" on "git checkout f<TAB>").
 
 case "$COMP_WORDBREAKS" in
 *:*) : great ;;
@@ -646,6 +652,7 @@ __git_heads ()
        local pfx="${1-}" cur_="${2-}" sfx="${3-}"
 
        __git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+                       ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
                        "refs/heads/$cur_*" "refs/heads/$cur_*/**"
 }
 
@@ -659,6 +666,7 @@ __git_remote_heads ()
        local pfx="${1-}" cur_="${2-}" sfx="${3-}"
 
        __git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+                       ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
                        "refs/remotes/$cur_*" "refs/remotes/$cur_*/**"
 }
 
@@ -669,6 +677,7 @@ __git_tags ()
        local pfx="${1-}" cur_="${2-}" sfx="${3-}"
 
        __git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+                       ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
                        "refs/tags/$cur_*" "refs/tags/$cur_*/**"
 }
 
@@ -688,6 +697,7 @@ __git_dwim_remote_heads ()
        # but only output if the branch name is unique
        __git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
                --sort="refname:strip=3" \
+               ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
                "refs/remotes/*/$cur_*" "refs/remotes/*/$cur_*/**" | \
        uniq -u
 }
@@ -712,6 +722,7 @@ __git_refs ()
        local format refs
        local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}"
        local match="${4-}"
+       local umatch="${4-}"
        local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
 
        __git_find_repo_path
@@ -735,12 +746,19 @@ __git_refs ()
                fi
        fi
 
+       if test "${GIT_COMPLETION_IGNORE_CASE:+1}" = "1"
+       then
+               # uppercase with tr instead of ${match,^^} for bash 3.2 compatibility
+               umatch=$(echo "$match" | tr a-z A-Z 2>/dev/null || echo "$match")
+       fi
+
        if [ "$list_refs_from" = path ]; then
                if [[ "$cur_" == ^* ]]; then
                        pfx="$pfx^"
                        fer_pfx="$fer_pfx^"
                        cur_=${cur_#^}
                        match=${match#^}
+                       umatch=${umatch#^}
                fi
                case "$cur_" in
                refs|refs/*)
@@ -751,7 +769,7 @@ __git_refs ()
                *)
                        for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD; do
                                case "$i" in
-                               $match*)
+                               $match*|$umatch*)
                                        if [ -e "$dir/$i" ]; then
                                                echo "$pfx$i$sfx"
                                        fi
@@ -765,6 +783,7 @@ __git_refs ()
                        ;;
                esac
                __git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \
+                       ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
                        "${refs[@]}"
                if [ -n "$track" ]; then
                        __git_dwim_remote_heads "$pfx" "$match" "$sfx"
@@ -784,15 +803,16 @@ __git_refs ()
        *)
                if [ "$list_refs_from" = remote ]; then
                        case "HEAD" in
-                       $match*       echo "${pfx}HEAD$sfx" ;;
+                       $match*|$umatch*)       echo "${pfx}HEAD$sfx" ;;
                        esac
                        __git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
+                               ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
                                "refs/remotes/$remote/$match*" \
                                "refs/remotes/$remote/$match*/**"
                else
                        local query_symref
                        case "HEAD" in
-                       $match*       query_symref="HEAD" ;;
+                       $match*|$umatch*)       query_symref="HEAD" ;;
                        esac
                        __git ls-remote "$remote" $query_symref \
                                "refs/tags/$match*" "refs/heads/$match*" \
index 2edea41a2345af623017d43e14a74d71a32bb873..dec040c366c82a71bc57bad9cf9db865182efe20 100644 (file)
@@ -673,7 +673,7 @@ int index_differs_from(struct repository *r,
        return (has_changes != 0);
 }
 
-static struct strbuf *idiff_prefix_cb(struct diff_options *opt, void *data)
+static struct strbuf *idiff_prefix_cb(struct diff_options *opt UNUSED, void *data)
 {
        return data;
 }
index 18edbdf4b59ec020cc58e3d16d01d92edfdc302e..05fafd0019b6d5acc7295b999a8a46c92e1a649e 100644 (file)
@@ -255,8 +255,7 @@ int diff_no_index(struct rev_info *revs,
        };
        struct option *options;
 
-       options = parse_options_concat(no_index_options,
-                                      revs->diffopt.parseopts);
+       options = add_diff_options(no_index_options, &revs->diffopt);
        argc = parse_options(argc, argv, revs->prefix, options,
                             diff_no_index_usage, 0);
        if (argc != 2) {
diff --git a/diff.c b/diff.c
index 1054a4b7329d0b70ed62311a728b5257df3a8143..9b14543e6ed3a50857da50b139983abe9413787f 100644 (file)
--- a/diff.c
+++ b/diff.c
@@ -604,7 +604,7 @@ static unsigned long diff_filespec_size(struct repository *r,
        return one->size;
 }
 
-static int count_trailing_blank(mmfile_t *mf, unsigned ws_rule)
+static int count_trailing_blank(mmfile_t *mf)
 {
        char *ptr = mf->ptr;
        long size = mf->size;
@@ -622,7 +622,7 @@ static int count_trailing_blank(mmfile_t *mf, unsigned ws_rule)
                for (prev_eol = ptr; mf->ptr <= prev_eol; prev_eol--)
                        if (*prev_eol == '\n')
                                break;
-               if (!ws_blank_line(prev_eol + 1, ptr - prev_eol, ws_rule))
+               if (!ws_blank_line(prev_eol + 1, ptr - prev_eol))
                        break;
                cnt++;
                ptr = prev_eol - 1;
@@ -634,9 +634,8 @@ static void check_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2,
                               struct emit_callback *ecbdata)
 {
        int l1, l2, at;
-       unsigned ws_rule = ecbdata->ws_rule;
-       l1 = count_trailing_blank(mf1, ws_rule);
-       l2 = count_trailing_blank(mf2, ws_rule);
+       l1 = count_trailing_blank(mf1);
+       l2 = count_trailing_blank(mf2);
        if (l2 <= l1) {
                ecbdata->blank_at_eof_in_preimage = 0;
                ecbdata->blank_at_eof_in_postimage = 0;
@@ -1583,7 +1582,7 @@ static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line
              ecbdata->blank_at_eof_in_preimage <= ecbdata->lno_in_preimage &&
              ecbdata->blank_at_eof_in_postimage <= ecbdata->lno_in_postimage))
                return 0;
-       return ws_blank_line(line, len, ecbdata->ws_rule);
+       return ws_blank_line(line, len);
 }
 
 static void emit_add_line(struct emit_callback *ecbdata,
@@ -1955,7 +1954,7 @@ static int color_words_output_graph_prefix(struct diff_words_data *diff_words)
 static void fn_out_diff_words_aux(void *priv,
                                  long minus_first, long minus_len,
                                  long plus_first, long plus_len,
-                                 const char *func, long funclen)
+                                 const char *func UNUSED, long funclen UNUSED)
 {
        struct diff_words_data *diff_words = priv;
        struct diff_words_style *style = diff_words->style;
@@ -2801,7 +2800,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
                else if (file->is_unmerged) {
                        strbuf_addf(&out, " %s%s%*s | %*s",
                                    prefix, name, padding, "",
-                                   number_width, "Unmerged");
+                                   number_width, "Unmerged\n");
                        emit_diff_symbol(options, DIFF_SYMBOL_STATS_LINE,
                                         out.buf, out.len, 0);
                        strbuf_reset(&out);
@@ -3185,8 +3184,9 @@ static int is_conflict_marker(const char *line, int marker_size, unsigned long l
 }
 
 static void checkdiff_consume_hunk(void *priv,
-                                  long ob, long on, long nb, long nn,
-                                  const char *func, long funclen)
+                                  long ob UNUSED, long on UNUSED,
+                                  long nb, long nn UNUSED,
+                                  const char *func UNUSED, long funclen UNUSED)
 
 {
        struct checkdiff_t *data = priv;
@@ -4615,8 +4615,6 @@ static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)
        builtin_checkdiff(name, other, attr_path, p->one, p->two, o);
 }
 
-static void prep_parse_options(struct diff_options *options);
-
 void repo_diff_setup(struct repository *r, struct diff_options *options)
 {
        memcpy(options, &default_diff_options, sizeof(*options));
@@ -4662,8 +4660,6 @@ void repo_diff_setup(struct repository *r, struct diff_options *options)
 
        options->color_moved = diff_color_moved_default;
        options->color_moved_ws_handling = diff_color_moved_ws_default;
-
-       prep_parse_options(options);
 }
 
 static const char diff_status_letters[] = {
@@ -4821,8 +4817,6 @@ void diff_setup_done(struct diff_options *options)
                        options->filter = ~filter_bit[DIFF_STATUS_FILTER_AON];
                options->filter &= ~options->filter_not;
        }
-
-       FREE_AND_NULL(options->parseopts);
 }
 
 int parse_long_opt(const char *opt, const char **argv,
@@ -5419,7 +5413,8 @@ static int diff_opt_rotate_to(const struct option *opt, const char *arg, int uns
        return 0;
 }
 
-static void prep_parse_options(struct diff_options *options)
+struct option *add_diff_options(const struct option *opts,
+                               struct diff_options *options)
 {
        struct option parseopts[] = {
                OPT_GROUP(N_("Diff output format options")),
@@ -5689,22 +5684,25 @@ static void prep_parse_options(struct diff_options *options)
                OPT_END()
        };
 
-       ALLOC_ARRAY(options->parseopts, ARRAY_SIZE(parseopts));
-       memcpy(options->parseopts, parseopts, sizeof(parseopts));
+       return parse_options_concat(opts, parseopts);
 }
 
 int diff_opt_parse(struct diff_options *options,
                   const char **av, int ac, const char *prefix)
 {
+       struct option no_options[] = { OPT_END() };
+       struct option *parseopts = add_diff_options(no_options, options);
+
        if (!prefix)
                prefix = "";
 
-       ac = parse_options(ac, av, prefix, options->parseopts, NULL,
+       ac = parse_options(ac, av, prefix, parseopts, NULL,
                           PARSE_OPT_KEEP_DASHDASH |
                           PARSE_OPT_KEEP_UNKNOWN_OPT |
                           PARSE_OPT_NO_INTERNAL_HELP |
                           PARSE_OPT_ONE_SHOT |
                           PARSE_OPT_STOP_AT_NON_OPTION);
+       free(parseopts);
 
        return ac;
 }
@@ -6513,7 +6511,6 @@ void diff_free(struct diff_options *options)
        diff_free_file(options);
        diff_free_ignore_regex(options);
        clear_pathspec(&options->pathspec);
-       FREE_AND_NULL(options->parseopts);
 }
 
 void diff_flush(struct diff_options *options)
diff --git a/diff.h b/diff.h
index fd33caeb25dc84b53dbac18d59898bcd3cc36a7d..41eb2c3d428801130bc6ffe355cc723067689b85 100644 (file)
--- a/diff.h
+++ b/diff.h
@@ -394,7 +394,6 @@ struct diff_options {
        unsigned color_moved_ws_handling;
 
        struct repository *repo;
-       struct option *parseopts;
        struct strmap *additional_path_headers;
 
        int no_free;
@@ -539,6 +538,7 @@ int git_diff_ui_config(const char *var, const char *value, void *cb);
 #define diff_setup(diffopts) repo_diff_setup(the_repository, diffopts)
 #endif
 void repo_diff_setup(struct repository *, struct diff_options *);
+struct option *add_diff_options(const struct option *, struct diff_options *);
 int diff_opt_parse(struct diff_options *, const char **, int, const char *);
 void diff_setup_done(struct diff_options *);
 int git_config_rename(const char *var, const char *value);
index 998fc2fa1ed4abd32ad0e723115f568768134d3e..04016d1e3250f28ae6cd53a784913f02879769d8 100644 (file)
@@ -1317,15 +1317,15 @@ static void write_fetch_command_and_capabilities(struct strbuf *req_buf,
 {
        const char *hash_name;
 
-       if (server_supports_v2("fetch", 1))
-               packet_buf_write(req_buf, "command=fetch");
-       if (server_supports_v2("agent", 0))
+       ensure_server_supports_v2("fetch");
+       packet_buf_write(req_buf, "command=fetch");
+       if (server_supports_v2("agent"))
                packet_buf_write(req_buf, "agent=%s", git_user_agent_sanitized());
-       if (advertise_sid && server_supports_v2("session-id", 0))
+       if (advertise_sid && server_supports_v2("session-id"))
                packet_buf_write(req_buf, "session-id=%s", trace2_session_id());
-       if (server_options && server_options->nr &&
-           server_supports_v2("server-option", 1)) {
+       if (server_options && server_options->nr) {
                int i;
+               ensure_server_supports_v2("server-option");
                for (i = 0; i < server_options->nr; i++)
                        packet_buf_write(req_buf, "server-option=%s",
                                         server_options->items[i].string);
index a76d0526f79266e1dc512072a4236876df8f8726..76e4b111315339449cd48d17f735f727935c08d8 100644 (file)
@@ -341,11 +341,13 @@ struct itimerval {
 #endif
 
 #ifdef NO_SETITIMER
-static inline int setitimer(int which UNUSED,
-                           const struct itimerval *value UNUSED,
-                           struct itimerval *newvalue UNUSED) {
+static inline int git_setitimer(int which UNUSED,
+                               const struct itimerval *value UNUSED,
+                               struct itimerval *newvalue UNUSED) {
        return 0; /* pretend success */
 }
+#undef setitimer
+#define setitimer(which,value,ovalue) git_setitimer(which,value,ovalue)
 #endif
 
 #ifndef NO_LIBGEN_H
@@ -1471,14 +1473,19 @@ int open_nofollow(const char *path, int flags);
 #endif
 
 #ifndef _POSIX_THREAD_SAFE_FUNCTIONS
-static inline void flockfile(FILE *fh UNUSED)
+static inline void git_flockfile(FILE *fh UNUSED)
 {
        ; /* nothing */
 }
-static inline void funlockfile(FILE *fh UNUSED)
+static inline void git_funlockfile(FILE *fh UNUSED)
 {
        ; /* nothing */
 }
+#undef flockfile
+#undef funlockfile
+#undef getc_unlocked
+#define flockfile(fh) git_flockfile(fh)
+#define funlockfile(fh) git_funlockfile(fh)
 #define getc_unlocked(fh) getc(fh)
 #endif
 
index 9a50f2e9124492589aa3a298a8bec74dbded8e32..7f9582d92343450e0c71ba72e5faee845cc1165b 100755 (executable)
@@ -244,6 +244,9 @@ cmd_update()
                -q|--quiet)
                        quiet=1
                        ;;
+               -v|--verbose)
+                       quiet=0
+                       ;;
                --progress)
                        progress=1
                        ;;
diff --git a/help.c b/help.c
index f1e090a4428f0e9e55b11a528e983d0908ffc70e..812af4cdea62129c12ec33813d934d677c61d714 100644 (file)
--- a/help.c
+++ b/help.c
@@ -563,7 +563,7 @@ static int git_unknown_cmd_config(const char *var, const char *value, void *cb)
        if (skip_prefix(var, "alias.", &p))
                add_cmdname(&aliases, p, strlen(p));
 
-       return git_default_config(var, value, cb);
+       return 0;
 }
 
 static int levenshtein_compare(const void *p1, const void *p2)
index 31bc5c7767ce865bb3fb1a89f311f7d2b03c7e6d..258fec2068262c815ae68b08c8729b0bc60ee498 100644 (file)
@@ -5,6 +5,7 @@
 #include "walker.h"
 #include "strvec.h"
 #include "urlmatch.h"
+#include "trace2.h"
 
 static const char http_fetch_usage[] = "git http-fetch "
 "[-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin | --packfile=hash | commit-id] url";
@@ -137,6 +138,8 @@ int cmd_main(int argc, const char **argv)
        if (nongit)
                die(_("not a git repository"));
 
+       trace2_cmd_name("http-fetch");
+
        git_config(git_default_config, NULL);
 
        if (packfile) {
index 955a8a9535575fe0a397497d765f3e0e97334259..47bf0d6f1a253a01baf6e3d0f68dfa5d5df6a0f0 100644 (file)
@@ -135,7 +135,7 @@ static const char *find_funcname_matching_regexp(xdemitconf_t *xecfg, const char
 {
        int reg_error;
        regmatch_t match[1];
-       while (1) {
+       while (*start) {
                const char *bol, *eol;
                reg_error = regexec(regexp, start, 1, match, 0);
                if (reg_error == REG_NOMATCH)
@@ -148,8 +148,8 @@ static const char *find_funcname_matching_regexp(xdemitconf_t *xecfg, const char
                /* determine extent of line matched */
                bol = start+match[0].rm_so;
                eol = start+match[0].rm_eo;
-               while (bol > start && *bol != '\n')
-                       bol--;
+               while (bol > start && *--bol != '\n')
+                       ; /* nothing */
                if (*bol == '\n')
                        bol++;
                while (*eol && *eol != '\n')
@@ -161,6 +161,7 @@ static const char *find_funcname_matching_regexp(xdemitconf_t *xecfg, const char
                        return bol;
                start = eol;
        }
+       return NULL;
 }
 
 static const char *parse_range_funcname(
index b9543545ca4af96e062ec69546c354e318e4ad0d..7ed21cb299c126fb2d2107eb3e418a18e64fbc6c 100644 (file)
@@ -70,13 +70,13 @@ struct filter {
 };
 
 static enum list_objects_filter_result filter_blobs_none(
-       struct repository *r,
+       struct repository *r UNUSED,
        enum list_objects_filter_situation filter_situation,
        struct object *obj,
-       const char *pathname,
-       const char *filename,
+       const char *pathname UNUSED,
+       const char *filename UNUSED,
        struct oidset *omits,
-       void *filter_data_)
+       void *filter_data_ UNUSED)
 {
        switch (filter_situation) {
        default:
@@ -112,7 +112,7 @@ static enum list_objects_filter_result filter_blobs_none(
 }
 
 static void filter_blobs_none__init(
-       struct list_objects_filter_options *filter_options,
+       struct list_objects_filter_options *filter_options UNUSED,
        struct filter *filter)
 {
        filter->filter_object_fn = filter_blobs_none;
@@ -159,11 +159,11 @@ static int filter_trees_update_omits(
 }
 
 static enum list_objects_filter_result filter_trees_depth(
-       struct repository *r,
+       struct repository *r UNUSED,
        enum list_objects_filter_situation filter_situation,
        struct object *obj,
-       const char *pathname,
-       const char *filename,
+       const char *pathname UNUSED,
+       const char *filename UNUSED,
        struct oidset *omits,
        void *filter_data_)
 {
@@ -274,8 +274,8 @@ static enum list_objects_filter_result filter_blobs_limit(
        struct repository *r,
        enum list_objects_filter_situation filter_situation,
        struct object *obj,
-       const char *pathname,
-       const char *filename,
+       const char *pathname UNUSED,
+       const char *filename UNUSED,
        struct oidset *omits,
        void *filter_data_)
 {
@@ -514,6 +514,7 @@ static enum list_objects_filter_result filter_sparse(
 static void filter_sparse_free(void *filter_data)
 {
        struct filter_sparse_data *d = filter_data;
+       clear_pattern_list(&d->pl);
        free(d->array_frame);
        free(d);
 }
@@ -554,12 +555,12 @@ struct filter_object_type_data {
 };
 
 static enum list_objects_filter_result filter_object_type(
-       struct repository *r,
+       struct repository *r UNUSED,
        enum list_objects_filter_situation filter_situation,
        struct object *obj,
-       const char *pathname,
-       const char *filename,
-       struct oidset *omits,
+       const char *pathname UNUSED,
+       const char *filename UNUSED,
+       struct oidset *omits UNUSED,
        void *filter_data_)
 {
        struct filter_object_type_data *filter_data = filter_data_;
@@ -675,7 +676,7 @@ static enum list_objects_filter_result filter_combine(
        struct object *obj,
        const char *pathname,
        const char *filename,
-       struct oidset *omits,
+       struct oidset *omits UNUSED,
        void *filter_data)
 {
        struct combine_filter_data *d = filter_data;
index 250d9de41cb56072e95420530b203ce417191a2b..7528fe1db2c85c0b4d923854ef3ec53c3a8f1fad 100644 (file)
@@ -81,36 +81,6 @@ static void process_blob(struct traversal_context *ctx,
        strbuf_setlen(path, pathlen);
 }
 
-/*
- * Processing a gitlink entry currently does nothing, since
- * we do not recurse into the subproject.
- *
- * We *could* eventually add a flag that actually does that,
- * which would involve:
- *  - is the subproject actually checked out?
- *  - if so, see if the subproject has already been added
- *    to the alternates list, and add it if not.
- *  - process the commit (or tag) the gitlink points to
- *    recursively.
- *
- * However, it's unclear whether there is really ever any
- * reason to see superprojects and subprojects as such a
- * "unified" object pool (potentially resulting in a totally
- * humongous pack - avoiding which was the whole point of
- * having gitlinks in the first place!).
- *
- * So for now, there is just a note that we *could* follow
- * the link, and how to do it. Whether it necessarily makes
- * any sense what-so-ever to ever do that is another issue.
- */
-static void process_gitlink(struct traversal_context *ctx,
-                           const unsigned char *sha1,
-                           struct strbuf *path,
-                           const char *name)
-{
-       /* Nothing to do */
-}
-
 static void process_tree(struct traversal_context *ctx,
                         struct tree *tree,
                         struct strbuf *base,
@@ -149,8 +119,7 @@ static void process_tree_contents(struct traversal_context *ctx,
                        process_tree(ctx, t, base, entry.path);
                }
                else if (S_ISGITLINK(entry.mode))
-                       process_gitlink(ctx, entry.oid.hash,
-                                       base, entry.path);
+                       ; /* ignore gitlink */
                else {
                        struct blob *b = lookup_blob(ctx->revs->repo, &entry.oid);
                        if (!b) {
index fb6769742cd85ebe3782b071634d45922305f5d0..697d4beb8de43a4a7ae48be8284e10c6be2a9bfd 100644 (file)
--- a/ls-refs.c
+++ b/ls-refs.c
@@ -194,8 +194,9 @@ int ls_refs(struct repository *r, struct packet_reader *request)
        send_possibly_unborn_head(&data);
        if (!data.prefixes.nr)
                strvec_push(&data.prefixes, "");
-       for_each_fullref_in_prefixes(get_git_namespace(), data.prefixes.v,
-                                    send_ref, &data);
+       refs_for_each_fullref_in_prefixes(get_main_ref_store(r),
+                                         get_git_namespace(), data.prefixes.v,
+                                         send_ref, &data);
        packet_fflush(stdout);
        strvec_clear(&data.prefixes);
        strbuf_release(&data.buf);
index 26290554bb4c5f1d679194fe7d3f2b5c78a273e2..80a0cd3b35183476bc56c8ce510d0863e171069e 100644 (file)
@@ -1211,35 +1211,25 @@ static int quick_has_loose(struct repository *r,
 }
 
 /*
- * Map the loose object at "path" if it is not NULL, or the path found by
- * searching for a loose object named "oid".
+ * Map and close the given loose object fd. The path argument is used for
+ * error reporting.
  */
-static void *map_loose_object_1(struct repository *r, const char *path,
-                            const struct object_id *oid, unsigned long *size)
+static void *map_fd(int fd, const char *path, unsigned long *size)
 {
-       void *map;
-       int fd;
-
-       if (path)
-               fd = git_open(path);
-       else
-               fd = open_loose_object(r, oid, &path);
-       map = NULL;
-       if (fd >= 0) {
-               struct stat st;
+       void *map = NULL;
+       struct stat st;
 
-               if (!fstat(fd, &st)) {
-                       *size = xsize_t(st.st_size);
-                       if (!*size) {
-                               /* mmap() is forbidden on empty files */
-                               error(_("object file %s is empty"), path);
-                               close(fd);
-                               return NULL;
-                       }
-                       map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0);
+       if (!fstat(fd, &st)) {
+               *size = xsize_t(st.st_size);
+               if (!*size) {
+                       /* mmap() is forbidden on empty files */
+                       error(_("object file %s is empty"), path);
+                       close(fd);
+                       return NULL;
                }
-               close(fd);
+               map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0);
        }
+       close(fd);
        return map;
 }
 
@@ -1247,7 +1237,12 @@ void *map_loose_object(struct repository *r,
                       const struct object_id *oid,
                       unsigned long *size)
 {
-       return map_loose_object_1(r, NULL, oid, size);
+       const char *p;
+       int fd = open_loose_object(r, oid, &p);
+
+       if (fd < 0)
+               return NULL;
+       return map_fd(fd, p, size);
 }
 
 enum unpack_loose_header_result unpack_loose_header(git_zstream *stream,
@@ -1427,7 +1422,9 @@ static int loose_object_info(struct repository *r,
                             struct object_info *oi, int flags)
 {
        int status = 0;
+       int fd;
        unsigned long mapsize;
+       const char *path;
        void *map;
        git_zstream stream;
        char hdr[MAX_HEADER_LEN];
@@ -1448,7 +1445,6 @@ static int loose_object_info(struct repository *r,
         * object even exists.
         */
        if (!oi->typep && !oi->type_name && !oi->sizep && !oi->contentp) {
-               const char *path;
                struct stat st;
                if (!oi->disk_sizep && (flags & OBJECT_INFO_QUICK))
                        return quick_has_loose(r, oid) ? 0 : -1;
@@ -1459,7 +1455,13 @@ static int loose_object_info(struct repository *r,
                return 0;
        }
 
-       map = map_loose_object(r, oid, &mapsize);
+       fd = open_loose_object(r, oid, &path);
+       if (fd < 0) {
+               if (errno != ENOENT)
+                       error_errno(_("unable to open loose object %s"), oid_to_hex(oid));
+               return -1;
+       }
+       map = map_fd(fd, path, &mapsize);
        if (!map)
                return -1;
 
@@ -1497,6 +1499,10 @@ static int loose_object_info(struct repository *r,
                break;
        }
 
+       if (status && (flags & OBJECT_INFO_DIE_IF_CORRUPT))
+               die(_("loose object %s (stored in %s) is corrupt"),
+                   oid_to_hex(oid), path);
+
        git_inflate_end(&stream);
 cleanup:
        munmap(map, mapsize);
@@ -1575,9 +1581,6 @@ static int do_oid_object_info_extended(struct repository *r,
                if (find_pack_entry(r, real, &e))
                        break;
 
-               if (flags & OBJECT_INFO_IGNORE_LOOSE)
-                       return -1;
-
                /* Most likely it's a loose object. */
                if (!loose_object_info(r, real, oi, flags))
                        return 0;
@@ -1609,6 +1612,15 @@ static int do_oid_object_info_extended(struct repository *r,
                        continue;
                }
 
+               if (flags & OBJECT_INFO_DIE_IF_CORRUPT) {
+                       const struct packed_git *p;
+                       if ((flags & OBJECT_INFO_LOOKUP_REPLACE) && !oideq(real, oid))
+                               die(_("replacement %s not found for %s"),
+                                   oid_to_hex(real), oid_to_hex(oid));
+                       if ((p = has_packed_and_bad(r, real)))
+                               die(_("packed object %s (stored in %s) is corrupt"),
+                                   oid_to_hex(real), p->pack_name);
+               }
                return -1;
        }
 
@@ -1661,7 +1673,8 @@ int oid_object_info(struct repository *r,
 
 static void *read_object(struct repository *r,
                         const struct object_id *oid, enum object_type *type,
-                        unsigned long *size)
+                        unsigned long *size,
+                        int die_if_corrupt)
 {
        struct object_info oi = OBJECT_INFO_INIT;
        void *content;
@@ -1669,7 +1682,8 @@ static void *read_object(struct repository *r,
        oi.sizep = size;
        oi.contentp = &content;
 
-       if (oid_object_info_extended(r, oid, &oi, 0) < 0)
+       if (oid_object_info_extended(r, oid, &oi, die_if_corrupt
+                                    ? OBJECT_INFO_DIE_IF_CORRUPT : 0) < 0)
                return NULL;
        return content;
 }
@@ -1705,35 +1719,14 @@ void *read_object_file_extended(struct repository *r,
                                int lookup_replace)
 {
        void *data;
-       const struct packed_git *p;
-       const char *path;
-       struct stat st;
        const struct object_id *repl = lookup_replace ?
                lookup_replace_object(r, oid) : oid;
 
        errno = 0;
-       data = read_object(r, repl, type, size);
+       data = read_object(r, repl, type, size, 1);
        if (data)
                return data;
 
-       obj_read_lock();
-       if (errno && errno != ENOENT)
-               die_errno(_("failed to read object %s"), oid_to_hex(oid));
-
-       /* die if we replaced an object with one that does not exist */
-       if (repl != oid)
-               die(_("replacement %s not found for %s"),
-                   oid_to_hex(repl), oid_to_hex(oid));
-
-       if (!stat_loose_object(r, repl, &st, &path))
-               die(_("loose object %s (stored in %s) is corrupt"),
-                   oid_to_hex(repl), path);
-
-       if ((p = has_packed_and_bad(r, repl)))
-               die(_("packed object %s (stored in %s) is corrupt"),
-                   oid_to_hex(repl), p->pack_name);
-       obj_read_unlock();
-
        return NULL;
 }
 
@@ -1864,13 +1857,6 @@ out:
        return 0;
 }
 
-static int write_buffer(int fd, const void *buf, size_t len)
-{
-       if (write_in_full(fd, buf, len) < 0)
-               return error_errno(_("file write error"));
-       return 0;
-}
-
 static void hash_object_file_literally(const struct git_hash_algo *algo,
                                       const void *buf, unsigned long len,
                                       const char *type, struct object_id *oid)
@@ -2015,8 +2001,8 @@ static int write_loose_object_common(git_hash_ctx *c,
 
        ret = git_deflate(stream, flush ? Z_FINISH : 0);
        the_hash_algo->update_fn(c, in0, stream->next_in - in0);
-       if (write_buffer(fd, compressed, stream->next_out - compressed) < 0)
-               die(_("unable to write loose object file"));
+       if (write_in_full(fd, compressed, stream->next_out - compressed) < 0)
+               die_errno(_("unable to write loose object file"));
        stream->next_out = compressed;
        stream->avail_out = compressed_len;
 
@@ -2276,7 +2262,7 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
 
        if (has_loose_object(oid))
                return 0;
-       buf = read_object(the_repository, oid, &type, &len);
+       buf = read_object(the_repository, oid, &type, &len, 0);
        if (!buf)
                return error(_("cannot read object for %s"), oid_to_hex(oid));
        hdrlen = format_object_header(hdr, sizeof(hdr), type, len);
@@ -2792,13 +2778,16 @@ int read_loose_object(const char *path,
                      struct object_info *oi)
 {
        int ret = -1;
+       int fd;
        void *map = NULL;
        unsigned long mapsize;
        git_zstream stream;
        char hdr[MAX_HEADER_LEN];
        unsigned long *size = oi->sizep;
 
-       map = map_loose_object_1(the_repository, path, NULL, &mapsize);
+       fd = git_open(path);
+       if (fd >= 0)
+               map = map_fd(fd, path, &mapsize);
        if (!map) {
                error_errno(_("unable to mmap %s"), path);
                goto out;
index 1be57abaf10d7aa527df7f22ebaf660f6430d4d8..98c1d67946f7351120b1389f3ed124720e901a3a 100644 (file)
@@ -434,19 +434,20 @@ struct object_info {
 #define OBJECT_INFO_ALLOW_UNKNOWN_TYPE 2
 /* Do not retry packed storage after checking packed and loose storage */
 #define OBJECT_INFO_QUICK 8
-/* Do not check loose object */
-#define OBJECT_INFO_IGNORE_LOOSE 16
 /*
  * Do not attempt to fetch the object if missing (even if fetch_is_missing is
  * nonzero).
  */
-#define OBJECT_INFO_SKIP_FETCH_OBJECT 32
+#define OBJECT_INFO_SKIP_FETCH_OBJECT 16
 /*
  * This is meant for bulk prefetching of missing blobs in a partial
  * clone. Implies OBJECT_INFO_SKIP_FETCH_OBJECT and OBJECT_INFO_QUICK
  */
 #define OBJECT_INFO_FOR_PREFETCH (OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK)
 
+/* Die if object corruption (not just an object being missing) was detected. */
+#define OBJECT_INFO_DIE_IF_CORRUPT 32
+
 int oid_object_info_extended(struct repository *r,
                             const struct object_id *,
                             struct object_info *, unsigned flags);
index 682b852a46c1aa89c85c24c66660a1948b5c2184..344087de4de5184fcbfb599277180cec8f39c474 100644 (file)
--- a/object.c
+++ b/object.c
@@ -212,8 +212,7 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id
        if (type == OBJ_BLOB) {
                struct blob *blob = lookup_blob(r, oid);
                if (blob) {
-                       if (parse_blob_buffer(blob, buffer, size))
-                               return NULL;
+                       parse_blob_buffer(blob);
                        obj = &blob->object;
                }
        } else if (type == OBJ_TREE) {
@@ -292,7 +291,7 @@ struct object *parse_object_with_flags(struct repository *r,
                        error(_("hash mismatch %s"), oid_to_hex(oid));
                        return NULL;
                }
-               parse_blob_buffer(lookup_blob(r, oid), NULL, 0);
+               parse_blob_buffer(lookup_blob(r, oid));
                return lookup_object(r, oid);
        }
 
index 00787e306db4c010ae68845f27ed69966fb9e250..336372974872882a235598d254c876e31c49b24a 100644 (file)
@@ -5,7 +5,6 @@
 #include "chunk-format.h"
 #include "pack-mtimes.h"
 #include "oidmap.h"
-#include "chunk-format.h"
 #include "pack-objects.h"
 
 void reset_pack_idx_option(struct pack_idx_option *opts)
index 8b7d81adc1be09d91a1551c370c08058766f76f6..8255ab4349c009bec7c2c7200365d2bd9b018c16 100644 (file)
@@ -269,14 +269,18 @@ static void find_exact_matches(struct string_list *a, struct string_list *b)
        hashmap_clear(&map);
 }
 
-static int diffsize_consume(void *data, char *line, unsigned long len)
+static int diffsize_consume(void *data,
+                            char *line UNUSED,
+                            unsigned long len UNUSED)
 {
        (*(int *)data)++;
        return 0;
 }
 
-static void diffsize_hunk(void *data, long ob, long on, long nb, long nn,
-                         const char *funcline, long funclen)
+static void diffsize_hunk(void *data,
+                         long ob UNUSED, long on UNUSED,
+                         long nb UNUSED, long nn UNUSED,
+                         const char *func UNUSED, long funclen UNUSED)
 {
        diffsize_consume(data, NULL, 0);
 }
@@ -461,7 +465,7 @@ static void patch_diff(const char *a, const char *b,
        diff_flush(diffopt);
 }
 
-static struct strbuf *output_prefix_cb(struct diff_options *opt, void *data)
+static struct strbuf *output_prefix_cb(struct diff_options *opt UNUSED, void *data)
 {
        return data;
 }
index caf10ab23eb49520d674654c52e585fb2d96307a..a24324123e727b762e2df915802920728ee8f63d 100644 (file)
@@ -228,6 +228,22 @@ static int strbuf_addf_ret(struct strbuf *sb, int ret, const char *fmt, ...)
        return ret;
 }
 
+static int err_no_arg(struct strbuf *sb, const char *name)
+{
+       size_t namelen = strchrnul(name, ':') - name;
+       strbuf_addf(sb, _("%%(%.*s) does not take arguments"),
+                   (int)namelen, name);
+       return -1;
+}
+
+static int err_bad_arg(struct strbuf *sb, const char *name, const char *arg)
+{
+       size_t namelen = strchrnul(name, ':') - name;
+       strbuf_addf(sb, _("unrecognized %%(%.*s) argument: %s"),
+                   (int)namelen, name, arg);
+       return -1;
+}
+
 static int color_atom_parser(struct ref_format *format, struct used_atom *atom,
                             const char *color_value, struct strbuf *err)
 {
@@ -262,7 +278,7 @@ static int refname_atom_parser_internal(struct refname_atom *atom, const char *a
                if (strtol_i(arg, 10, &atom->rstrip))
                        return strbuf_addf_ret(err, -1, _("Integer value expected refname:rstrip=%s"), arg);
        } else
-               return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), name, arg);
+               return err_bad_arg(err, name, arg);
        return 0;
 }
 
@@ -317,7 +333,7 @@ static int objecttype_atom_parser(struct ref_format *format, struct used_atom *a
                                  const char *arg, struct strbuf *err)
 {
        if (arg)
-               return strbuf_addf_ret(err, -1, _("%%(objecttype) does not take arguments"));
+               return err_no_arg(err, "objecttype");
        if (*atom->name == '*')
                oi_deref.info.typep = &oi_deref.type;
        else
@@ -341,7 +357,7 @@ static int objectsize_atom_parser(struct ref_format *format, struct used_atom *a
                else
                        oi.info.disk_sizep = &oi.disk_size;
        } else
-               return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "objectsize", arg);
+               return err_bad_arg(err, "objectsize", arg);
        return 0;
 }
 
@@ -349,7 +365,7 @@ static int deltabase_atom_parser(struct ref_format *format, struct used_atom *at
                                 const char *arg, struct strbuf *err)
 {
        if (arg)
-               return strbuf_addf_ret(err, -1, _("%%(deltabase) does not take arguments"));
+               return err_no_arg(err, "deltabase");
        if (*atom->name == '*')
                oi_deref.info.delta_base_oid = &oi_deref.delta_base_oid;
        else
@@ -361,7 +377,7 @@ static int body_atom_parser(struct ref_format *format, struct used_atom *atom,
                            const char *arg, struct strbuf *err)
 {
        if (arg)
-               return strbuf_addf_ret(err, -1, _("%%(body) does not take arguments"));
+               return err_no_arg(err, "body");
        atom->u.contents.option = C_BODY_DEP;
        return 0;
 }
@@ -374,7 +390,7 @@ static int subject_atom_parser(struct ref_format *format, struct used_atom *atom
        else if (!strcmp(arg, "sanitize"))
                atom->u.contents.option = C_SUB_SANITIZE;
        else
-               return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "subject", arg);
+               return err_bad_arg(err, "subject", arg);
        return 0;
 }
 
@@ -428,7 +444,7 @@ static int contents_atom_parser(struct ref_format *format, struct used_atom *ato
                if (strtoul_ui(arg, 10, &atom->u.contents.nlines))
                        return strbuf_addf_ret(err, -1, _("positive value expected contents:lines=%s"), arg);
        } else
-               return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "contents", arg);
+               return err_bad_arg(err, "contents", arg);
        return 0;
 }
 
@@ -440,7 +456,7 @@ static int raw_atom_parser(struct ref_format *format, struct used_atom *atom,
        else if (!strcmp(arg, "size"))
                atom->u.raw_data.option = RAW_LENGTH;
        else
-               return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "raw", arg);
+               return err_bad_arg(err, "raw", arg);
        return 0;
 }
 
@@ -459,7 +475,7 @@ static int oid_atom_parser(struct ref_format *format, struct used_atom *atom,
                if (atom->u.oid.length < MINIMUM_ABBREV)
                        atom->u.oid.length = MINIMUM_ABBREV;
        } else
-               return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), atom->name, arg);
+               return err_bad_arg(err, atom->name, arg);
        return 0;
 }
 
@@ -473,7 +489,7 @@ static int person_email_atom_parser(struct ref_format *format, struct used_atom
        else if (!strcmp(arg, "localpart"))
                atom->u.email_option.option = EO_LOCALPART;
        else
-               return strbuf_addf_ret(err, -1, _("unrecognized email option: %s"), arg);
+               return err_bad_arg(err, atom->name, arg);
        return 0;
 }
 
@@ -557,7 +573,7 @@ static int if_atom_parser(struct ref_format *format, struct used_atom *atom,
        } else if (skip_prefix(arg, "notequals=", &atom->u.if_then_else.str)) {
                atom->u.if_then_else.cmp_status = COMPARE_UNEQUAL;
        } else
-               return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "if", arg);
+               return err_bad_arg(err, "if", arg);
        return 0;
 }
 
@@ -565,14 +581,16 @@ static int rest_atom_parser(struct ref_format *format, struct used_atom *atom,
                            const char *arg, struct strbuf *err)
 {
        if (arg)
-               return strbuf_addf_ret(err, -1, _("%%(rest) does not take arguments"));
+               return err_no_arg(err, "rest");
        format->use_rest = 1;
        return 0;
 }
 
 static int head_atom_parser(struct ref_format *format, struct used_atom *atom,
-                           const char *arg, struct strbuf *unused_err)
+                           const char *arg, struct strbuf *err)
 {
+       if (arg)
+               return err_no_arg(err, "HEAD");
        atom->u.head = resolve_refdup("HEAD", RESOLVE_REF_READING, NULL, NULL);
        return 0;
 }
@@ -2129,8 +2147,9 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
                return for_each_fullref_in("", cb, cb_data);
        }
 
-       return for_each_fullref_in_prefixes(NULL, filter->name_patterns,
-                                           cb, cb_data);
+       return refs_for_each_fullref_in_prefixes(get_main_ref_store(the_repository),
+                                                NULL, filter->name_patterns,
+                                                cb, cb_data);
 }
 
 /*
index 78e9350e20526a279fd5f5cedfb3d5a726edd481..04630f56ec6b3661ecb027fa0a8a5f49155bb3da 100644 (file)
--- a/reflog.c
+++ b/reflog.c
@@ -193,7 +193,6 @@ static void mark_reachable(struct expire_reflog_policy_cb *cb)
                        commit_list_insert(commit, &leftover);
                        continue;
                }
-               commit->object.flags |= REACHABLE;
                parent = commit->parents;
                while (parent) {
                        commit = parent->item;
@@ -371,6 +370,9 @@ void reflog_expiry_cleanup(void *cb_data)
                clear_commit_marks(cb->tip_commit, REACHABLE);
                break;
        }
+       for (elem = cb->mark_list; elem; elem = elem->next)
+               clear_commit_marks(elem->item, REACHABLE);
+       free_commit_list(cb->mark_list);
 }
 
 int count_reflog_ent(struct object_id *ooid UNUSED,
diff --git a/refs.c b/refs.c
index 2c7e88b1902b8d35b63808d781f4076d5567560f..e31dbcda5990b8f2e7143547ce134b7218041fd2 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -1723,9 +1723,10 @@ static void find_longest_prefixes(struct string_list *out,
        strbuf_release(&prefix);
 }
 
-int for_each_fullref_in_prefixes(const char *namespace,
-                                const char **patterns,
-                                each_ref_fn fn, void *cb_data)
+int refs_for_each_fullref_in_prefixes(struct ref_store *ref_store,
+                                     const char *namespace,
+                                     const char **patterns,
+                                     each_ref_fn fn, void *cb_data)
 {
        struct string_list prefixes = STRING_LIST_INIT_DUP;
        struct string_list_item *prefix;
@@ -1740,7 +1741,7 @@ int for_each_fullref_in_prefixes(const char *namespace,
 
        for_each_string_list_item(prefix, &prefixes) {
                strbuf_addstr(&buf, prefix->string);
-               ret = for_each_fullref_in(buf.buf, fn, cb_data);
+               ret = refs_for_each_fullref_in(ref_store, buf.buf, fn, cb_data);
                if (ret)
                        break;
                strbuf_setlen(&buf, namespace_len);
diff --git a/refs.h b/refs.h
index 3266fd8f57d39938c2c496c8f869b14697c34c69..935cdd1ece3db3af483cb2225f204966c0e6cfa5 100644 (file)
--- a/refs.h
+++ b/refs.h
@@ -354,8 +354,10 @@ int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data);
  *
  * callers should be prepared to ignore references that they did not ask for.
  */
-int for_each_fullref_in_prefixes(const char *namespace, const char **patterns,
-                                each_ref_fn fn, void *cb_data);
+int refs_for_each_fullref_in_prefixes(struct ref_store *refs,
+                                     const char *namespace, const char **patterns,
+                                     each_ref_fn fn, void *cb_data);
+
 /**
  * iterate refs from the respective area.
  */
index c1c71d183ea3c0baf082b16cf18bc373a7615fe3..6f5a0709fba65e80081fdb04563019e1f1e15400 100644 (file)
@@ -1263,7 +1263,8 @@ static int write_with_updates(struct packed_ref_store *refs,
                goto error;
        }
 
-       if (fsync_component(FSYNC_COMPONENT_REFERENCE, get_tempfile_fd(refs->tempfile)) ||
+       if (fflush(out) ||
+           fsync_component(FSYNC_COMPONENT_REFERENCE, get_tempfile_fd(refs->tempfile)) ||
            close_tempfile_gently(refs->tempfile)) {
                strbuf_addf(err, "error closing file %s: %s",
                            get_tempfile_path(refs->tempfile),
index 1c4621b414bdc0372613e58c3b2133b84004d1e7..1ebbe42792ec67230b62dbbe4cb8ed9646576858 100644 (file)
--- a/remote.h
+++ b/remote.h
@@ -234,6 +234,11 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
                             const struct string_list *server_options,
                             int stateless_rpc);
 
+/* Used for protocol v2 in order to retrieve refs from a remote */
+struct bundle_list;
+int get_remote_bundle_uri(int fd_out, struct packet_reader *reader,
+                         struct bundle_list *bundles, int stateless_rpc);
+
 int resolve_remote_symref(struct ref *ref, struct ref *list);
 
 /*
index c86e76e47165eda61ef9778d4991aeaecab5b195..100e5ad5110b1f851801c11639434da7191a229e 100644 (file)
@@ -600,10 +600,12 @@ static struct commit *one_relevant_parent(const struct rev_info *revs,
 static int tree_difference = REV_TREE_SAME;
 
 static void file_add_remove(struct diff_options *options,
-                   int addremove, unsigned mode,
-                   const struct object_id *oid,
-                   int oid_valid,
-                   const char *fullpath, unsigned dirty_submodule)
+                   int addremove,
+                   unsigned mode UNUSED,
+                   const struct object_id *oid UNUSED,
+                   int oid_valid UNUSED,
+                   const char *fullpath UNUSED,
+                   unsigned dirty_submodule UNUSED)
 {
        int diff = addremove == '+' ? REV_TREE_NEW : REV_TREE_OLD;
        struct rev_info *revs = options->change_fn_data;
@@ -614,12 +616,15 @@ static void file_add_remove(struct diff_options *options,
 }
 
 static void file_change(struct diff_options *options,
-                unsigned old_mode, unsigned new_mode,
-                const struct object_id *old_oid,
-                const struct object_id *new_oid,
-                int old_oid_valid, int new_oid_valid,
-                const char *fullpath,
-                unsigned old_dirty_submodule, unsigned new_dirty_submodule)
+                unsigned old_mode UNUSED,
+                unsigned new_mode UNUSED,
+                const struct object_id *old_oid UNUSED,
+                const struct object_id *new_oid UNUSED,
+                int old_oid_valid UNUSED,
+                int new_oid_valid UNUSED,
+                const char *fullpath UNUSED,
+                unsigned old_dirty_submodule UNUSED,
+                unsigned new_dirty_submodule UNUSED)
 {
        tree_difference = REV_TREE_DIFFERENT;
        options->flags.has_changes = 1;
index 48b9ba6d6f077e5729f3efc4c1a88ab2be508c36..756f1839aab22b9c79337400a7424d0243088368 100644 (file)
@@ -1019,7 +1019,7 @@ static void *run_thread(void *data)
                sigset_t mask;
                sigemptyset(&mask);
                sigaddset(&mask, SIGPIPE);
-               if (pthread_sigmask(SIG_BLOCK, &mask, NULL) < 0) {
+               if (pthread_sigmask(SIG_BLOCK, &mask, NULL)) {
                        ret = error("unable to block SIGPIPE in async thread");
                        return (void *)ret;
                }
index dbd56121e24f8a6adaad5d2634b64e320dfeeb78..bcb662e23be9e8d2962a88bd16b4cad93981619d 100644 (file)
@@ -36,7 +36,6 @@
 #include "rebase-interactive.h"
 #include "reset.h"
 #include "branch.h"
-#include "log-tree.h"
 
 #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION"
 
diff --git a/serve.c b/serve.c
index 733347f602aa1ede3e45fee94050163790d65bf9..cbf4a143cfea9bd450d5d033b1ec051025af8a1f 100644 (file)
--- a/serve.c
+++ b/serve.c
@@ -7,6 +7,7 @@
 #include "protocol-caps.h"
 #include "serve.h"
 #include "upload-pack.h"
+#include "bundle-uri.h"
 
 static int advertise_sid = -1;
 static int client_hash_algo = GIT_HASH_SHA1;
@@ -135,6 +136,11 @@ static struct protocol_capability capabilities[] = {
                .advertise = always_advertise,
                .command = cap_object_info,
        },
+       {
+               .name = "bundle-uri",
+               .advertise = bundle_uri_advertise,
+               .command = bundle_uri_command,
+       },
 };
 
 void protocol_v2_advertise_capabilities(void)
index 0890b1405c5cc6888396bac8558549ebdb2e2977..c383f41a3c5ccc6c6228c4ed4f9631529633f878 100644 (file)
--- a/strbuf.c
+++ b/strbuf.c
@@ -1200,3 +1200,9 @@ int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
        free(path2);
        return res;
 }
+
+void strbuf_strip_file_from_path(struct strbuf *sb)
+{
+       char *path_sep = find_last_dir_sep(sb->buf);
+       strbuf_setlen(sb, path_sep ? path_sep - sb->buf + 1 : 0);
+}
index 76965a17d444829b4a5b5edc099d12bf1fcc7ea3..f6dbb9681ee768221e707a39c37dc0a00f63b95d 100644 (file)
--- a/strbuf.h
+++ b/strbuf.h
@@ -664,6 +664,17 @@ int launch_sequence_editor(const char *path, struct strbuf *buffer,
 int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
                              const char *const *env);
 
+/*
+ * Remove the filename from the provided path string. If the path
+ * contains a trailing separator, then the path is considered a directory
+ * and nothing is modified.
+ *
+ * Examples:
+ * - "/path/to/file" -> "/path/to/"
+ * - "/path/to/dir/" -> "/path/to/dir/"
+ */
+void strbuf_strip_file_from_path(struct strbuf *sb);
+
 void strbuf_add_lines(struct strbuf *sb,
                      const char *prefix,
                      const char *buf,
index 8ac2fca855d6c3615be2e5b8a7f16a4746441e1a..fae24ef34a52f721547f9a88fe2fcc6de710a315 100644 (file)
@@ -832,7 +832,7 @@ static void changed_submodule_data_clear(struct changed_submodule_data *cs_data)
 }
 
 static void collect_changed_submodules_cb(struct diff_queue_struct *q,
-                                         struct diff_options *options,
+                                         struct diff_options *options UNUSED,
                                          void *data)
 {
        struct collect_changed_submodules_cb_data *me = data;
index 25afd3934284ddc8bc0fdca7cca514a742e44e7e..5df5bc3b89e04a9893518fc8cb5fe9158f24578c 100644 (file)
@@ -3,6 +3,10 @@
 #include "bundle-uri.h"
 #include "strbuf.h"
 #include "string-list.h"
+#include "transport.h"
+#include "ref-filter.h"
+#include "remote.h"
+#include "refs.h"
 
 enum input_mode {
        KEY_VALUE_PAIRS,
@@ -36,6 +40,8 @@ static int cmd__bundle_uri_parse(int argc, const char **argv, enum input_mode mo
 
        init_bundle_list(&list);
 
+       list.baseURI = xstrdup("<uri>");
+
        switch (mode) {
        case KEY_VALUE_PAIRS:
                if (argc != 1)
@@ -68,6 +74,46 @@ usage:
        usage_with_options(usage, options);
 }
 
+static int cmd_ls_remote(int argc, const char **argv)
+{
+       const char *uploadpack = NULL;
+       struct string_list server_options = STRING_LIST_INIT_DUP;
+       const char *dest;
+       struct remote *remote;
+       struct transport *transport;
+       int status = 0;
+
+       dest = argc > 1 ? argv[1] : NULL;
+
+       remote = remote_get(dest);
+       if (!remote) {
+               if (dest)
+                       die(_("bad repository '%s'"), dest);
+               die(_("no remote configured to get bundle URIs from"));
+       }
+       if (!remote->url_nr)
+               die(_("remote '%s' has no configured URL"), dest);
+
+       transport = transport_get(remote, NULL);
+       if (uploadpack)
+               transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);
+       if (server_options.nr)
+               transport->server_options = &server_options;
+
+       if (transport_get_remote_bundle_uri(transport) < 0) {
+               error(_("could not get the bundle-uri list"));
+               status = 1;
+               goto cleanup;
+       }
+
+       print_bundle_list(stdout, transport->bundles);
+
+cleanup:
+       if (transport_disconnect(transport))
+               return 1;
+       return status;
+}
+
 int cmd__bundle_uri(int argc, const char **argv)
 {
        const char *usage[] = {
@@ -88,6 +134,8 @@ int cmd__bundle_uri(int argc, const char **argv)
                return cmd__bundle_uri_parse(argc - 1, argv + 1, KEY_VALUE_PAIRS);
        if (!strcmp(argv[1], "parse-config"))
                return cmd__bundle_uri_parse(argc - 1, argv + 1, CONFIG_FILE);
+       if (!strcmp(argv[1], "ls-remote"))
+               return cmd_ls_remote(argc - 1, argv + 1);
        error("there is no test-tool bundle-uri tool '%s'", argv[1]);
 
 usage:
diff --git a/t/lib-bundle-uri-protocol.sh b/t/lib-bundle-uri-protocol.sh
new file mode 100644 (file)
index 0000000..a4a1af8
--- /dev/null
@@ -0,0 +1,216 @@
+# Set up and run tests of the 'bundle-uri' command in protocol v2
+#
+# The test that includes this script should set BUNDLE_URI_PROTOCOL
+# to one of "file", "git", or "http".
+
+BUNDLE_URI_TEST_PARENT=
+BUNDLE_URI_TEST_URI=
+BUNDLE_URI_TEST_BUNDLE_URI=
+case "$BUNDLE_URI_PROTOCOL" in
+file)
+       BUNDLE_URI_PARENT=file_parent
+       BUNDLE_URI_REPO_URI="file://$PWD/file_parent"
+       BUNDLE_URI_BUNDLE_URI="$BUNDLE_URI_REPO_URI/fake.bdl"
+       test_set_prereq BUNDLE_URI_FILE
+       ;;
+git)
+       . "$TEST_DIRECTORY"/lib-git-daemon.sh
+       start_git_daemon --export-all --enable=receive-pack
+       BUNDLE_URI_PARENT="$GIT_DAEMON_DOCUMENT_ROOT_PATH/parent"
+       BUNDLE_URI_REPO_URI="$GIT_DAEMON_URL/parent"
+       BUNDLE_URI_BUNDLE_URI="https://example.com/fake.bdl"
+       test_set_prereq BUNDLE_URI_GIT
+       ;;
+http)
+       . "$TEST_DIRECTORY"/lib-httpd.sh
+       start_httpd
+       BUNDLE_URI_PARENT="$HTTPD_DOCUMENT_ROOT_PATH/http_parent"
+       BUNDLE_URI_REPO_URI="$HTTPD_URL/smart/http_parent"
+       BUNDLE_URI_BUNDLE_URI="https://example.com/fake.bdl"
+       test_set_prereq BUNDLE_URI_HTTP
+       ;;
+*)
+       BUG "Need to pass valid BUNDLE_URI_PROTOCOL (was \"$BUNDLE_URI_PROTOCOL\")"
+       ;;
+esac
+
+test_expect_success "setup protocol v2 $BUNDLE_URI_PROTOCOL:// tests" '
+       git init "$BUNDLE_URI_PARENT" &&
+       test_commit -C "$BUNDLE_URI_PARENT" one &&
+       git -C "$BUNDLE_URI_PARENT" config uploadpack.advertiseBundleURIs true
+'
+
+case "$BUNDLE_URI_PROTOCOL" in
+http)
+       test_expect_success "setup config for $BUNDLE_URI_PROTOCOL:// tests" '
+               git -C "$BUNDLE_URI_PARENT" config http.receivepack true
+       '
+       ;;
+*)
+       ;;
+esac
+BUNDLE_URI_BUNDLE_URI_ESCAPED=$(echo "$BUNDLE_URI_BUNDLE_URI" | test_uri_escape)
+
+test_expect_success "connect with $BUNDLE_URI_PROTOCOL:// using protocol v2: no bundle-uri" '
+       test_when_finished "rm -f log" &&
+       test_when_finished "git -C \"$BUNDLE_URI_PARENT\" config uploadpack.advertiseBundleURIs true" &&
+       git -C "$BUNDLE_URI_PARENT" config uploadpack.advertiseBundleURIs false &&
+
+       GIT_TRACE_PACKET="$PWD/log" \
+       git \
+               -c protocol.version=2 \
+               ls-remote --symref "$BUNDLE_URI_REPO_URI" \
+               >actual 2>err &&
+
+       # Server responded using protocol v2
+       grep "< version 2" log &&
+
+       ! grep bundle-uri log
+'
+
+test_expect_success "connect with $BUNDLE_URI_PROTOCOL:// using protocol v2: have bundle-uri" '
+       test_when_finished "rm -f log" &&
+
+       GIT_TRACE_PACKET="$PWD/log" \
+       git \
+               -c protocol.version=2 \
+               ls-remote --symref "$BUNDLE_URI_REPO_URI" \
+               >actual 2>err &&
+
+       # Server responded using protocol v2
+       grep "< version 2" log &&
+
+       # Server advertised bundle-uri capability
+       grep "< bundle-uri" log
+'
+
+test_expect_success "clone with $BUNDLE_URI_PROTOCOL:// using protocol v2: request bundle-uris" '
+       test_when_finished "rm -rf log* cloned*" &&
+
+       GIT_TRACE_PACKET="$PWD/log" \
+       git \
+               -c transfer.bundleURI=false \
+               -c protocol.version=2 \
+               clone "$BUNDLE_URI_REPO_URI" cloned \
+               >actual 2>err &&
+
+       # Server responded using protocol v2
+       grep "< version 2" log &&
+
+       # Server advertised bundle-uri capability
+       grep "< bundle-uri" log &&
+
+       # Client did not issue bundle-uri command
+       ! grep "> command=bundle-uri" log &&
+
+       GIT_TRACE_PACKET="$PWD/log" \
+       git \
+               -c transfer.bundleURI=true \
+               -c protocol.version=2 \
+               clone "$BUNDLE_URI_REPO_URI" cloned2 \
+               >actual 2>err &&
+
+       # Server responded using protocol v2
+       grep "< version 2" log &&
+
+       # Server advertised bundle-uri capability
+       grep "< bundle-uri" log &&
+
+       # Client issued bundle-uri command
+       grep "> command=bundle-uri" log &&
+
+       GIT_TRACE_PACKET="$PWD/log3" \
+       git \
+               -c transfer.bundleURI=true \
+               -c protocol.version=2 \
+               clone --bundle-uri="$BUNDLE_URI_BUNDLE_URI" \
+               "$BUNDLE_URI_REPO_URI" cloned3 \
+               >actual 2>err &&
+
+       # Server responded using protocol v2
+       grep "< version 2" log3 &&
+
+       # Server advertised bundle-uri capability
+       grep "< bundle-uri" log3 &&
+
+       # Client did not issue bundle-uri command (--bundle-uri override)
+       ! grep "> command=bundle-uri" log3
+'
+
+# The remaining tests will all assume transfer.bundleURI=true
+#
+# This test can be removed when transfer.bundleURI is enabled by default.
+test_expect_success 'enable transfer.bundleURI for remaining tests' '
+       git config --global transfer.bundleURI true
+'
+
+test_expect_success "test bundle-uri with $BUNDLE_URI_PROTOCOL:// using protocol v2" '
+       test_config -C "$BUNDLE_URI_PARENT" \
+               bundle.only.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED" &&
+
+       # All data about bundle URIs
+       cat >expect <<-EOF &&
+       [bundle]
+               version = 1
+               mode = all
+       [bundle "only"]
+               uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED
+       EOF
+
+       test-tool bundle-uri \
+               ls-remote \
+               "$BUNDLE_URI_REPO_URI" \
+               >actual &&
+       test_cmp_config_output expect actual
+'
+
+test_expect_success "test bundle-uri with $BUNDLE_URI_PROTOCOL:// using protocol v2 and extra data" '
+       test_config -C "$BUNDLE_URI_PARENT" \
+               bundle.only.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED" &&
+
+       # Extra data should be ignored
+       test_config -C "$BUNDLE_URI_PARENT" bundle.only.extra bogus &&
+
+       # All data about bundle URIs
+       cat >expect <<-EOF &&
+       [bundle]
+               version = 1
+               mode = all
+       [bundle "only"]
+               uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED
+       EOF
+
+       test-tool bundle-uri \
+               ls-remote \
+               "$BUNDLE_URI_REPO_URI" \
+               >actual &&
+       test_cmp_config_output expect actual
+'
+
+test_expect_success "test bundle-uri with $BUNDLE_URI_PROTOCOL:// using protocol v2 with list" '
+       test_config -C "$BUNDLE_URI_PARENT" \
+               bundle.bundle1.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED-1.bdl" &&
+       test_config -C "$BUNDLE_URI_PARENT" \
+               bundle.bundle2.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED-2.bdl" &&
+       test_config -C "$BUNDLE_URI_PARENT" \
+               bundle.bundle3.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED-3.bdl" &&
+
+       # All data about bundle URIs
+       cat >expect <<-EOF &&
+       [bundle]
+               version = 1
+               mode = all
+       [bundle "bundle1"]
+               uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED-1.bdl
+       [bundle "bundle2"]
+               uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED-2.bdl
+       [bundle "bundle3"]
+               uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED-3.bdl
+       EOF
+
+       test-tool bundle-uri \
+               ls-remote \
+               "$BUNDLE_URI_REPO_URI" \
+               >actual &&
+       test_cmp_config_output expect actual
+'
index 433d242897ca903004156dab58a5ac66ffc3fbc9..eeb8539c1bcb2df86a5aff1fa2c78fc555598d14 100755 (executable)
@@ -109,6 +109,44 @@ test_expect_success 'get GIT_EDITOR with configuration and environment variable
        )
 '
 
+test_expect_success 'get GIT_SEQUENCE_EDITOR without configuration' '
+       (
+               sane_unset GIT_SEQUENCE_EDITOR &&
+               git var GIT_EDITOR >expect &&
+               git var GIT_SEQUENCE_EDITOR >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success 'get GIT_SEQUENCE_EDITOR with configuration' '
+       test_config sequence.editor foo &&
+       (
+               sane_unset GIT_SEQUENCE_EDITOR &&
+               echo foo >expect &&
+               git var GIT_SEQUENCE_EDITOR >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success 'get GIT_SEQUENCE_EDITOR with environment variable' '
+       (
+               sane_unset GIT_SEQUENCE_EDITOR &&
+               echo bar >expect &&
+               GIT_SEQUENCE_EDITOR=bar git var GIT_SEQUENCE_EDITOR >actual &&
+               test_cmp expect actual
+       )
+'
+
+test_expect_success 'get GIT_SEQUENCE_EDITOR with configuration and environment variable' '
+       test_config sequence.editor foo &&
+       (
+               sane_unset GIT_SEQUENCE_EDITOR &&
+               echo bar >expect &&
+               GIT_SEQUENCE_EDITOR=bar git var GIT_SEQUENCE_EDITOR >actual &&
+               test_cmp expect actual
+       )
+'
+
 # For git var -l, we check only a representative variable;
 # testing the whole output would make our test too brittle with
 # respect to unrelated changes in the test suite's environment.
index 793bf4d269e6a1f101481ae70280dd5db19e75a9..3399344f25dc859ad743b3914a3f5c37e92bffbb 100755 (executable)
@@ -57,6 +57,16 @@ test_expect_success 'create branch with pseudo-qualified name' '
        expect_branch refs/heads/refs/heads/qualified two
 '
 
+test_expect_success 'force-copy a branch to itself via @{-1} is no-op' '
+       git branch -t copiable main &&
+       git checkout copiable &&
+       git checkout - &&
+       git branch -C @{-1} copiable &&
+       git config --get-all branch.copiable.merge >actual &&
+       echo refs/heads/main >expect &&
+       test_cmp expect actual
+'
+
 test_expect_success 'delete branch via @{-1}' '
        git branch previous-del &&
 
index 4c661d4d54a779f8bc056c62e5d9e864401420c7..67fd2345affd78507a6cb714b48565ed190cb5af 100755 (executable)
@@ -12,7 +12,7 @@ create_crlf_ref () {
        cat >.crlf-orig-$branch.txt &&
        cat .crlf-orig-$branch.txt | append_cr >.crlf-message-$branch.txt &&
        grep 'Subject' .crlf-orig-$branch.txt | tr '\n' ' ' | sed 's/[ ]*$//' | tr -d '\n' >.crlf-subject-$branch.txt &&
-       grep 'Body' .crlf-message-$branch.txt >.crlf-body-$branch.txt || true &&
+       grep 'Body' .crlf-orig-$branch.txt | append_cr >.crlf-body-$branch.txt &&
        LIB_CRLF_BRANCHES="${LIB_CRLF_BRANCHES} ${branch}" &&
        test_tick &&
        hash=$(git commit-tree HEAD^{tree} -p HEAD -F .crlf-message-${branch}.txt) &&
index de1da4673da9626f0c155fd4c67597a403870ece..012f155e10ae9f9e1fcbd3472cd9a789bae919ec 100755 (executable)
@@ -2281,7 +2281,7 @@ test_expect_success 'format-patch --attach cover-letter only is non-multipart' '
        test_line_count = 1 output
 '
 
-test_expect_success 'format-patch --pretty=mboxrd' '
+test_expect_success '-c format.mboxrd format-patch' '
        sp=" " &&
        cat >msg <<-INPUT_END &&
        mboxrd should escape the body
@@ -2316,7 +2316,9 @@ test_expect_success 'format-patch --pretty=mboxrd' '
        INPUT_END
 
        C=$(git commit-tree HEAD^^{tree} -p HEAD <msg) &&
-       git format-patch --pretty=mboxrd --stdout -1 $C~1..$C >patch &&
+       git -c format.mboxrd format-patch --stdout -1 $C~1..$C >patch &&
+       git format-patch --pretty=mboxrd --stdout -1 $C~1..$C >compat &&
+       test_cmp patch compat &&
        git grep -h --no-index -A11 \
                "^>From could trip up a loose mbox parser" patch >actual &&
        test_cmp expect actual
index 7cb99092938d7dd64e8ab6f4e147fc5f70c0a310..787605ce3fd076b101d1c825fca174020ae7ff46 100755 (executable)
@@ -52,8 +52,8 @@ test_expect_success setup '
 '
 
 test_expect_success 'cross renames to be detected for regular files' '
-
-       git diff-tree five six -r --name-status -B -M | sort >actual &&
+       git diff-tree five six -r --name-status -B -M >out &&
+       sort out >actual &&
        {
                echo "R100      foo     bar" &&
                echo "R100      bar     foo"
@@ -63,8 +63,8 @@ test_expect_success 'cross renames to be detected for regular files' '
 '
 
 test_expect_success 'cross renames to be detected for typechange' '
-
-       git diff-tree one two -r --name-status -B -M | sort >actual &&
+       git diff-tree one two -r --name-status -B -M >out &&
+       sort out >actual &&
        {
                echo "R100      foo     bar" &&
                echo "R100      bar     foo"
@@ -74,8 +74,8 @@ test_expect_success 'cross renames to be detected for typechange' '
 '
 
 test_expect_success 'moves and renames' '
-
-       git diff-tree three four -r --name-status -B -M | sort >actual &&
+       git diff-tree three four -r --name-status -B -M >out &&
+       sort out >actual &&
        {
                # see -B -M (#6) in t4008
                echo "C100      foo     bar" &&
index 0ae0cd3a524da312d7f1cc7b1d4b0f6ed7b2b529..ffaf69335f7b224f76ece7228435a4ce057e5c83 100755 (executable)
@@ -86,4 +86,14 @@ test_expect_success 'diff-files -3' '
        test_cmp diff-files-3.expect diff-files-3.actual
 '
 
+test_expect_success 'diff --stat' '
+       for path in $paths
+       do
+               echo " $path | Unmerged" || return 1
+       done >diff-stat.expect &&
+       echo " 0 files changed" >>diff-stat.expect &&
+       git diff --cached --stat >diff-stat.actual &&
+       test_cmp diff-stat.expect diff-stat.actual
+'
+
 test_done
index cdad4b688078adc24da922bce14e130982f4484e..7646e856d513f3dc3d396f675189ed9b86a43f72 100755 (executable)
@@ -1033,7 +1033,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '
        >From extra escape for reversibility
        INPUT_END
        git commit -F msg &&
-       git format-patch --pretty=mboxrd --stdout -1 >mboxrd1 &&
+       git -c format.mboxrd format-patch --stdout -1 >mboxrd1 &&
        grep "^>From could trip up a loose mbox parser" mboxrd1 &&
        git checkout -f first &&
        git am --patch-format=mboxrd mboxrd1 &&
index cd1cab3e54b9170d5751279bd68e02dbc3cbcad2..fa7f987284b117607fa051c91dd439749da546d4 100755 (executable)
@@ -1022,4 +1022,69 @@ test_expect_success '--mailmap enables mailmap in cat-file for annotated tag obj
        test_cmp expect actual
 '
 
+test_expect_success 'git cat-file -s returns correct size with --use-mailmap' '
+       test_when_finished "rm .mailmap" &&
+       cat >.mailmap <<-\EOF &&
+       C O Mitter <committer@example.com> Orig <orig@example.com>
+       EOF
+       git cat-file commit HEAD >commit.out &&
+       echo $(wc -c <commit.out) >expect &&
+       git cat-file --use-mailmap commit HEAD >commit.out &&
+       echo $(wc -c <commit.out) >>expect &&
+       git cat-file -s HEAD >actual &&
+       git cat-file --use-mailmap -s HEAD >>actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'git cat-file -s returns correct size with --use-mailmap for tag objects' '
+       test_when_finished "rm .mailmap" &&
+       cat >.mailmap <<-\EOF &&
+       Orig <orig@example.com> C O Mitter <committer@example.com>
+       EOF
+       git tag -a -m "annotated tag" v3 &&
+       git cat-file tag v3 >tag.out &&
+       echo $(wc -c <tag.out) >expect &&
+       git cat-file --use-mailmap tag v3 >tag.out &&
+       echo $(wc -c <tag.out) >>expect &&
+       git cat-file -s v3 >actual &&
+       git cat-file --use-mailmap -s v3 >>actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-check returns correct size with --use-mailmap' '
+       test_when_finished "rm .mailmap" &&
+       cat >.mailmap <<-\EOF &&
+       C O Mitter <committer@example.com> Orig <orig@example.com>
+       EOF
+       git cat-file commit HEAD >commit.out &&
+       commit_size=$(wc -c <commit.out) &&
+       commit_sha=$(git rev-parse HEAD) &&
+       echo $commit_sha commit $commit_size >expect &&
+       git cat-file --use-mailmap commit HEAD >commit.out &&
+       commit_size=$(wc -c <commit.out) &&
+       echo $commit_sha commit $commit_size >>expect &&
+       echo "HEAD" >in &&
+       git cat-file --batch-check <in >actual &&
+       git cat-file --use-mailmap --batch-check <in >>actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command returns correct size with --use-mailmap' '
+       test_when_finished "rm .mailmap" &&
+       cat >.mailmap <<-\EOF &&
+       C O Mitter <committer@example.com> Orig <orig@example.com>
+       EOF
+       git cat-file commit HEAD >commit.out &&
+       commit_size=$(wc -c <commit.out) &&
+       commit_sha=$(git rev-parse HEAD) &&
+       echo $commit_sha commit $commit_size >expect &&
+       git cat-file --use-mailmap commit HEAD >commit.out &&
+       commit_size=$(wc -c <commit.out) &&
+       echo $commit_sha commit $commit_size >>expect &&
+       echo "info HEAD" >in &&
+       git cat-file --batch-command <in >actual &&
+       git cat-file --use-mailmap --batch-command <in >>actual &&
+       test_cmp expect actual
+'
+
 test_done
index e448ef2928a8261e7c991ee6eb0e96bf299d84ee..0404491d6ee9fa275764497f917d90a7334d6776 100755 (executable)
@@ -156,7 +156,7 @@ test_expect_success 'NUL termination with --reflog --pretty=oneline' '
        for r in $revs
        do
                git show -s --pretty=oneline "$r" >raw &&
-               cat raw | lf_to_nul || exit 1
+               cat raw | lf_to_nul || return 1
        done >expect &&
        # the trailing NUL is already produced so we do not need to
        # output another one
index ac9e4d0928593cd37b4a79e27f5fe99b6e4a3faf..c6540e822fbdc56f068ae1b8d991175303bff038 100755 (executable)
@@ -315,4 +315,26 @@ test_expect_success 'line-log with --before' '
        test_cmp expect actual
 '
 
+test_expect_success 'setup tests for zero-width regular expressions' '
+       cat >expect <<-EOF
+       Modify func1() in file.c
+       Add func1() and func2() in file.c
+       EOF
+'
+
+test_expect_success 'zero-width regex $ matches any function name' '
+       git log --format="%s" --no-patch "-L:$:file.c" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'zero-width regex ^ matches any function name' '
+       git log --format="%s" --no-patch "-L:^:file.c" >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'zero-width regex .* matches any function name' '
+       git log --format="%s" --no-patch "-L:.*:file.c" >actual &&
+       test_cmp expect actual
+'
+
 test_done
index 73a241743aa50101c032b53566de7ba2e7a3b410..82734b9a3c4420a63b91901d165ae06f4b823ea7 100755 (executable)
@@ -63,13 +63,16 @@ TEST_PASSES_SANITIZE_LEAK=true
 # Note that the two variants of "file" must be similar enough to convince git
 # to create the delta.
 make_pack () {
-       {
-               printf '%s\n' "-$(git rev-parse $2)"
-               printf '%s dummy\n' "$(git rev-parse $1:dummy)"
-               printf '%s file\n' "$(git rev-parse $1:file)"
-       } |
-       git pack-objects --stdout |
-       git index-pack --stdin --fix-thin
+       ln1=$(git rev-parse "$2") &&
+       ln2=$(git rev-parse "$1:dummy") &&
+       ln3=$(git rev-parse "$1:file") &&
+       cat >list <<-EOF
+       -$ln1
+       $ln2 dummy
+       $ln3 file
+       EOF
+       git pack-objects --stdout <list >pack &&
+       git index-pack --stdin --fix-thin <pack
 }
 
 test_expect_success 'setup' '
index b2524a24c29796960bfd4dc59ec9a9650e53175e..1928ea1dd7cb9b42e7b6f6db6216c1545bb77a9e 100755 (executable)
@@ -772,6 +772,65 @@ test_expect_success 'reject cloning shallow repository using HTTP' '
        git clone --no-reject-shallow $HTTPD_URL/smart/repo.git repo
 '
 
+test_expect_success 'auto-discover bundle URI from HTTP clone' '
+       test_when_finished rm -rf trace.txt repo2 "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" &&
+       git -C src bundle create "$HTTPD_DOCUMENT_ROOT_PATH/everything.bundle" --all &&
+       git clone --bare --no-local src "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" &&
+
+       git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \
+               uploadpack.advertiseBundleURIs true &&
+       git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \
+               bundle.version 1 &&
+       git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \
+               bundle.mode all &&
+       git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \
+               bundle.everything.uri "$HTTPD_URL/everything.bundle" &&
+
+       GIT_TRACE2_EVENT="$(pwd)/trace.txt" \
+               git -c protocol.version=2 \
+                   -c transfer.bundleURI=true clone \
+               $HTTPD_URL/smart/repo2.git repo2 &&
+       cat >pattern <<-EOF &&
+       "event":"child_start".*"argv":\["git-remote-https","$HTTPD_URL/everything.bundle"\]
+       EOF
+       grep -f pattern trace.txt
+'
+
+test_expect_success 'auto-discover multiple bundles from HTTP clone' '
+       test_when_finished rm -rf trace.txt repo3 "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" &&
+
+       test_commit -C src new &&
+       git -C src bundle create "$HTTPD_DOCUMENT_ROOT_PATH/new.bundle" HEAD~1..HEAD &&
+       git clone --bare --no-local src "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" &&
+
+       git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
+               uploadpack.advertiseBundleURIs true &&
+       git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
+               bundle.version 1 &&
+       git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
+               bundle.mode all &&
+
+       git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
+               bundle.everything.uri "$HTTPD_URL/everything.bundle" &&
+       git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
+               bundle.new.uri "$HTTPD_URL/new.bundle" &&
+
+       GIT_TRACE2_EVENT="$(pwd)/trace.txt" \
+               git -c protocol.version=2 \
+                   -c transfer.bundleURI=true clone \
+               $HTTPD_URL/smart/repo3.git repo3 &&
+
+       # We should fetch _both_ bundles
+       cat >pattern <<-EOF &&
+       "event":"child_start".*"argv":\["git-remote-https","$HTTPD_URL/everything.bundle"\]
+       EOF
+       grep -f pattern trace.txt &&
+       cat >pattern <<-EOF &&
+       "event":"child_start".*"argv":\["git-remote-https","$HTTPD_URL/new.bundle"\]
+       EOF
+       grep -f pattern trace.txt
+'
+
 # DO NOT add non-httpd-specific tests here, because the last part of this
 # test script is only executed when httpd is available and enabled.
 
index 1896f671cb37f916bc09e50f0f5a45df81da1327..f21e5e9d33d199368df3aeb5ebae64e6b20cc5e3 100755 (executable)
@@ -13,7 +13,7 @@ test_expect_success 'test capability advertisement' '
        wrong_algo sha1:sha256
        wrong_algo sha256:sha1
        EOF
-       cat >expect <<-EOF &&
+       cat >expect.base <<-EOF &&
        version 2
        agent=git/$(git version | cut -d" " -f3)
        ls-refs=unborn
@@ -21,8 +21,11 @@ test_expect_success 'test capability advertisement' '
        server-option
        object-format=$(test_oid algo)
        object-info
+       EOF
+       cat >expect.trailer <<-EOF &&
        0000
        EOF
+       cat expect.base expect.trailer >expect &&
 
        GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \
                --advertise-capabilities >out &&
@@ -342,4 +345,39 @@ test_expect_success 'basics of object-info' '
        test_cmp expect actual
 '
 
+test_expect_success 'test capability advertisement with uploadpack.advertiseBundleURIs' '
+       test_config uploadpack.advertiseBundleURIs true &&
+
+       cat >expect.extra <<-EOF &&
+       bundle-uri
+       EOF
+       cat expect.base \
+           expect.extra \
+           expect.trailer >expect &&
+
+       GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \
+               --advertise-capabilities >out &&
+       test-tool pkt-line unpack <out >actual &&
+       test_cmp expect actual
+'
+
+test_expect_success 'basics of bundle-uri: dies if not enabled' '
+       test-tool pkt-line pack >in <<-EOF &&
+       command=bundle-uri
+       0000
+       EOF
+
+       cat >err.expect <<-\EOF &&
+       fatal: invalid command '"'"'bundle-uri'"'"'
+       EOF
+
+       cat >expect <<-\EOF &&
+       ERR serve: invalid command '"'"'bundle-uri'"'"'
+       EOF
+
+       test_must_fail test-tool serve-v2 --stateless-rpc <in >out 2>err.actual &&
+       test_cmp err.expect err.actual &&
+       test_must_be_empty out
+'
+
 test_done
diff --git a/t/t5730-protocol-v2-bundle-uri-file.sh b/t/t5730-protocol-v2-bundle-uri-file.sh
new file mode 100755 (executable)
index 0000000..37bdb72
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+test_description="Test bundle-uri with protocol v2 and 'file://' transport"
+
+TEST_NO_CREATE_REPO=1
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+# Test protocol v2 with 'file://' transport
+#
+BUNDLE_URI_PROTOCOL=file
+. "$TEST_DIRECTORY"/lib-bundle-uri-protocol.sh
+
+test_done
diff --git a/t/t5731-protocol-v2-bundle-uri-git.sh b/t/t5731-protocol-v2-bundle-uri-git.sh
new file mode 100755 (executable)
index 0000000..8add1b3
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+test_description="Test bundle-uri with protocol v2 and 'git://' transport"
+
+TEST_NO_CREATE_REPO=1
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+# Test protocol v2 with 'git://' transport
+#
+BUNDLE_URI_PROTOCOL=git
+. "$TEST_DIRECTORY"/lib-bundle-uri-protocol.sh
+
+test_done
diff --git a/t/t5732-protocol-v2-bundle-uri-http.sh b/t/t5732-protocol-v2-bundle-uri-http.sh
new file mode 100755 (executable)
index 0000000..129daa0
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+test_description="Test bundle-uri with protocol v2 and 'http://' transport"
+
+TEST_NO_CREATE_REPO=1
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+# Test protocol v2 with 'http://' transport
+#
+BUNDLE_URI_PROTOCOL=http
+. "$TEST_DIRECTORY"/lib-bundle-uri-protocol.sh
+
+test_done
index c2fe3f9c5a5c40543e8c2c0b65949c0dbfc1b594..7b4f930e532a90f7aec76e1047b4bec79f855f21 100755 (executable)
@@ -30,6 +30,58 @@ test_expect_success 'bundle_uri_parse_line() just URIs' '
        test_cmp_config_output expect actual
 '
 
+test_expect_success 'bundle_uri_parse_line(): relative URIs' '
+       cat >in <<-\EOF &&
+       bundle.one.uri=bundle.bdl
+       bundle.two.uri=../bundle.bdl
+       bundle.three.uri=sub/dir/bundle.bdl
+       EOF
+
+       cat >expect <<-\EOF &&
+       [bundle]
+               version = 1
+               mode = all
+       [bundle "one"]
+               uri = <uri>/bundle.bdl
+       [bundle "two"]
+               uri = bundle.bdl
+       [bundle "three"]
+               uri = <uri>/sub/dir/bundle.bdl
+       EOF
+
+       test-tool bundle-uri parse-key-values in >actual 2>err &&
+       test_must_be_empty err &&
+       test_cmp_config_output expect actual
+'
+
+test_expect_success 'bundle_uri_parse_line(): relative URIs and parent paths' '
+       cat >in <<-\EOF &&
+       bundle.one.uri=bundle.bdl
+       bundle.two.uri=../bundle.bdl
+       bundle.three.uri=../../bundle.bdl
+       EOF
+
+       cat >expect <<-\EOF &&
+       [bundle]
+               version = 1
+               mode = all
+       [bundle "one"]
+               uri = <uri>/bundle.bdl
+       [bundle "two"]
+               uri = bundle.bdl
+       [bundle "three"]
+               uri = <uri>/../bundle.bdl
+       EOF
+
+       # TODO: We would prefer if parsing a bundle list would not cause
+       # a die() and instead would give a warning and allow the rest of
+       # a Git command to continue. This test_must_fail is necessary for
+       # now until the interface for relative_url() allows for reporting
+       # an error instead of die()ing.
+       test_must_fail test-tool bundle-uri parse-key-values in >actual 2>err &&
+       grep "fatal: cannot strip one component off url" err
+'
+
 test_expect_success 'bundle_uri_parse_line() parsing edge cases: empty key or value' '
        cat >in <<-\EOF &&
        =bogus-value
@@ -136,6 +188,36 @@ test_expect_success 'parse config format: just URIs' '
        test_cmp_config_output expect actual
 '
 
+test_expect_success 'parse config format: relative URIs' '
+       cat >in <<-\EOF &&
+       [bundle]
+               version = 1
+               mode = all
+       [bundle "one"]
+               uri = bundle.bdl
+       [bundle "two"]
+               uri = ../bundle.bdl
+       [bundle "three"]
+               uri = sub/dir/bundle.bdl
+       EOF
+
+       cat >expect <<-\EOF &&
+       [bundle]
+               version = 1
+               mode = all
+       [bundle "one"]
+               uri = <uri>/bundle.bdl
+       [bundle "two"]
+               uri = bundle.bdl
+       [bundle "three"]
+               uri = <uri>/sub/dir/bundle.bdl
+       EOF
+
+       test-tool bundle-uri parse-config in >actual 2>err &&
+       test_must_be_empty err &&
+       test_cmp_config_output expect actual
+'
+
 test_expect_success 'parse config format edge cases: empty key or value' '
        cat >in1 <<-\EOF &&
        = bogus-value
index fa38b874416220d3d3c39ee48a99ad53b94dc2df..2ae1fc721b1c477e8830d15eeda323c7e4b9bb7a 100755 (executable)
@@ -1242,6 +1242,24 @@ test_expect_success 'basic atom: rest must fail' '
        test_must_fail git for-each-ref --format="%(rest)" refs/heads/main
 '
 
+test_expect_success 'HEAD atom does not take arguments' '
+       test_must_fail git for-each-ref --format="%(HEAD:foo)" 2>err &&
+       echo "fatal: %(HEAD) does not take arguments" >expect &&
+       test_cmp expect err
+'
+
+test_expect_success 'subject atom rejects unknown arguments' '
+       test_must_fail git for-each-ref --format="%(subject:foo)" 2>err &&
+       echo "fatal: unrecognized %(subject) argument: foo" >expect &&
+       test_cmp expect err
+'
+
+test_expect_success 'refname atom rejects unknown arguments' '
+       test_must_fail git for-each-ref --format="%(refname:foo)" 2>err &&
+       echo "fatal: unrecognized %(refname) argument: foo" >expect &&
+       test_cmp expect err
+'
+
 test_expect_success 'trailer parsing not fooled by --- line' '
        git commit --allow-empty -F - <<-\EOF &&
        this is the subject
index 2b7ef6c41a455423c0c62087a440e51bc4c72486..aed07c5b622e9a244313e781ceba0e6898024d21 100755 (executable)
@@ -1676,4 +1676,74 @@ test_expect_success 'racy timestamps will be fixed for dirty worktree' '
        ! test_is_magic_mtime .git/index
 '
 
+test_expect_success 'setup slow status advice' '
+       GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main git init slowstatus &&
+       (
+               cd slowstatus &&
+               cat >.gitignore <<-\EOF &&
+               /actual
+               /expected
+               /out
+               EOF
+               git add .gitignore &&
+               git commit -m "Add .gitignore" &&
+               git config advice.statusuoption true
+       )
+'
+
+test_expect_success 'slow status advice when core.untrackedCache and fsmonitor are unset' '
+       (
+               cd slowstatus &&
+               git config core.untrackedCache false &&
+               git config core.fsmonitor false &&
+               GIT_TEST_UF_DELAY_WARNING=1 git status >actual &&
+               cat >expected <<-\EOF &&
+               On branch main
+
+               It took 3.25 seconds to enumerate untracked files.
+               See '\''git help status'\'' for information on how to improve this.
+
+               nothing to commit, working tree clean
+               EOF
+               test_cmp expected actual
+       )
+'
+
+test_expect_success 'slow status advice when core.untrackedCache true, but not fsmonitor' '
+       (
+               cd slowstatus &&
+               git config core.untrackedCache true &&
+               git config core.fsmonitor false &&
+               GIT_TEST_UF_DELAY_WARNING=1 git status >actual &&
+               cat >expected <<-\EOF &&
+               On branch main
+
+               It took 3.25 seconds to enumerate untracked files.
+               See '\''git help status'\'' for information on how to improve this.
+
+               nothing to commit, working tree clean
+               EOF
+               test_cmp expected actual
+       )
+'
+
+test_expect_success 'slow status advice when core.untrackedCache true, and fsmonitor' '
+       (
+               cd slowstatus &&
+               git config core.untrackedCache true &&
+               git config core.fsmonitor true &&
+               GIT_TEST_UF_DELAY_WARNING=1 git status >actual &&
+               cat >expected <<-\EOF &&
+               On branch main
+
+               It took 3.25 seconds to enumerate untracked files,
+               but the results were cached, and subsequent runs may be faster.
+               See '\''git help status'\'' for information on how to improve this.
+
+               nothing to commit, working tree clean
+               EOF
+               test_cmp expected actual
+       )
+'
+
 test_done
index 7c3f6ed99431839abc42533d520cd342f25dafd1..060e145957f3ad94933b37ebe6148ffbdf168d37 100755 (executable)
@@ -105,7 +105,7 @@ verify_mergeheads () {
        test_write_lines "$@" >mergehead.expected &&
        while read sha1 rest
        do
-               git rev-parse $sha1
+               git rev-parse $sha1 || return 1
        done <.git/MERGE_HEAD >mergehead.actual &&
        test_cmp mergehead.expected mergehead.actual
 }
index 4b9cb4c942f8e91c7a34109a1426594410b0c9a5..14a704d0a8c311ff776f65313178073e70b0a38f 100755 (executable)
@@ -62,4 +62,10 @@ test_expect_success 'autocorrect can be declined altogether' '
        test_line_count = 1 actual
 '
 
+test_expect_success 'autocorrect works in work tree created from bare repo' '
+       git clone --bare . bare.git &&
+       git -C bare.git worktree add ../worktree &&
+       git -C worktree -c help.autocorrect=immediate stauts
+'
+
 test_done
index 8201c3e808a931d07bc7e135f87bcc0499f65e20..088d1c57a88a209d57bdc95e45368f40af87c7a6 100755 (executable)
@@ -28,7 +28,7 @@ test_cmp_info () {
        rm -f tmp.expect tmp.actual
 }
 
-quoted_svnrepo="$(echo $svnrepo | sed 's/ /%20/')"
+quoted_svnrepo="$(echo $svnrepo | test_uri_escape)"
 
 test_expect_success 'setup repository and import' '
        mkdir info &&
index 43de868b8005d330c10ec5d81fcacdc325aff858..d6c0478d98b85412307a422b142386c180ad030a 100755 (executable)
@@ -2255,6 +2255,36 @@ test_expect_success 'checkout completes ref names' '
        EOF
 '
 
+test_expect_success 'checkout does not match ref names of a different case' '
+       test_completion "git checkout M" ""
+'
+
+test_expect_success 'checkout matches case insensitively with GIT_COMPLETION_IGNORE_CASE' '
+       (
+               GIT_COMPLETION_IGNORE_CASE=1 &&
+               test_completion "git checkout M" <<-\EOF
+               main Z
+               mybranch Z
+               mytag Z
+               EOF
+       )
+'
+
+test_expect_success 'checkout completes pseudo refs' '
+       test_completion "git checkout H" <<-\EOF
+       HEAD Z
+       EOF
+'
+
+test_expect_success 'checkout completes pseudo refs case insensitively with GIT_COMPLETION_IGNORE_CASE' '
+       (
+               GIT_COMPLETION_IGNORE_CASE=1 &&
+               test_completion "git checkout h" <<-\EOF
+               HEAD Z
+               EOF
+       )
+'
+
 test_expect_success 'git -C <path> checkout uses the right repo' '
        test_completion "git -C subdir -C subsubdir -C .. -C ../otherrepo checkout b" <<-\EOF
        branch-in-other Z
index f51b97663fee664069dc4de1b10753c777ed91c1..f036c4d300393e69f9cb99b895985e27b87595af 100644 (file)
@@ -1751,6 +1751,13 @@ test_path_is_hidden () {
        return 1
 }
 
+# Poor man's URI escaping. Good enough for the test suite whose trash
+# directory has a space in it. See 93c3fcbe4d4 (git-svn: attempt to
+# mimic SVN 1.7 URL canonicalization, 2012-07-28) for prior art.
+test_uri_escape() {
+       sed 's/ /%20/g'
+}
+
 # Check that the given command was invoked as part of the
 # trace2-format trace on stdin.
 #
index e95267a4ab54dc12318435d157d1fdd37821f567..3ea7c2bb5ad8c462ae0f54c9466af210bc27d0c2 100644 (file)
@@ -1267,9 +1267,22 @@ static struct ref *get_refs_list_using_list(struct transport *transport,
        return ret;
 }
 
+static int get_bundle_uri(struct transport *transport)
+{
+       get_helper(transport);
+
+       if (process_connect(transport, 0)) {
+               do_take_over(transport);
+               return transport->vtable->get_bundle_uri(transport);
+       }
+
+       return -1;
+}
+
 static struct transport_vtable vtable = {
        .set_option     = set_helper_option,
        .get_refs_list  = get_refs_list,
+       .get_bundle_uri = get_bundle_uri,
        .fetch_refs     = fetch_refs,
        .push_refs      = push_refs,
        .connect        = connect_helper,
index c4ca0b733acbdbe7fc7a5906490e396240ec7b06..90ea749e5cfbf7de994a8747186ad5fb3ae7c653 100644 (file)
@@ -26,6 +26,13 @@ struct transport_vtable {
        struct ref *(*get_refs_list)(struct transport *transport, int for_push,
                                     struct transport_ls_refs_options *transport_options);
 
+       /**
+        * Populates the remote side's bundle-uri under protocol v2,
+        * if the "bundle-uri" capability was advertised. Returns 0 if
+        * OK, negative values on error.
+        */
+       int (*get_bundle_uri)(struct transport *transport);
+
        /**
         * Fetch the objects for the given refs. Note that this gets
         * an array, and should ignore the list structure.
index e7b97194c103a3a7fad6d4174e40c96db9ff2a4c..77a61a9d7bb06a5cfc7992c6fc4f9f3aa8a8ada5 100644 (file)
@@ -22,6 +22,7 @@
 #include "protocol.h"
 #include "object-store.h"
 #include "color.h"
+#include "bundle-uri.h"
 
 static int transport_use_color = -1;
 static char transport_colors[][COLOR_MAXLEN] = {
@@ -197,7 +198,7 @@ struct git_transport_data {
        struct git_transport_options options;
        struct child_process *conn;
        int fd[2];
-       unsigned got_remote_heads : 1;
+       unsigned finished_handshake : 1;
        enum protocol_version version;
        struct oid_array extra_have;
        struct oid_array shallow;
@@ -344,7 +345,7 @@ static struct ref *handshake(struct transport *transport, int for_push,
        case protocol_unknown_version:
                BUG("unknown protocol version");
        }
-       data->got_remote_heads = 1;
+       data->finished_handshake = 1;
        transport->hash_algo = reader.hash_algo;
 
        if (reader.line_peeked)
@@ -359,6 +360,39 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
        return handshake(transport, for_push, options, 1);
 }
 
+static int get_bundle_uri(struct transport *transport)
+{
+       struct git_transport_data *data = transport->data;
+       struct packet_reader reader;
+       int stateless_rpc = transport->stateless_rpc;
+
+       if (!transport->bundles) {
+               CALLOC_ARRAY(transport->bundles, 1);
+               init_bundle_list(transport->bundles);
+       }
+
+       if (!data->finished_handshake) {
+               struct ref *refs = handshake(transport, 0, NULL, 0);
+
+               if (refs)
+                       free_refs(refs);
+       }
+
+       /*
+        * "Support" protocol v0 and v2 without bundle-uri support by
+        * silently degrading to a NOOP.
+        */
+       if (!server_supports_v2("bundle-uri"))
+               return 0;
+
+       packet_reader_init(&reader, data->fd[0], NULL, 0,
+                          PACKET_READ_CHOMP_NEWLINE |
+                          PACKET_READ_GENTLE_ON_EOF);
+
+       return get_remote_bundle_uri(data->fd[1], &reader,
+                                    transport->bundles, stateless_rpc);
+}
+
 static int fetch_refs_via_pack(struct transport *transport,
                               int nr_heads, struct ref **to_fetch)
 {
@@ -394,7 +428,7 @@ static int fetch_refs_via_pack(struct transport *transport,
        args.negotiation_tips = data->options.negotiation_tips;
        args.reject_shallow_remote = transport->smart_options->reject_shallow;
 
-       if (!data->got_remote_heads) {
+       if (!data->finished_handshake) {
                int i;
                int must_list_refs = 0;
                for (i = 0; i < nr_heads; i++) {
@@ -434,7 +468,7 @@ static int fetch_refs_via_pack(struct transport *transport,
                          to_fetch, nr_heads, &data->shallow,
                          &transport->pack_lockfiles, data->version);
 
-       data->got_remote_heads = 0;
+       data->finished_handshake = 0;
        data->options.self_contained_and_connected =
                args.self_contained_and_connected;
        data->options.connectivity_checked = args.connectivity_checked;
@@ -819,7 +853,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
        if (transport_color_config() < 0)
                return -1;
 
-       if (!data->got_remote_heads)
+       if (!data->finished_handshake)
                get_refs_via_connect(transport, 1, NULL);
 
        memset(&args, 0, sizeof(args));
@@ -867,7 +901,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
        else
                ret = finish_connect(data->conn);
        data->conn = NULL;
-       data->got_remote_heads = 0;
+       data->finished_handshake = 0;
 
        return ret;
 }
@@ -887,7 +921,7 @@ static int disconnect_git(struct transport *transport)
 {
        struct git_transport_data *data = transport->data;
        if (data->conn) {
-               if (data->got_remote_heads && !transport->stateless_rpc)
+               if (data->finished_handshake && !transport->stateless_rpc)
                        packet_flush(data->fd[1]);
                close(data->fd[0]);
                if (data->fd[1] >= 0)
@@ -902,6 +936,7 @@ static int disconnect_git(struct transport *transport)
 
 static struct transport_vtable taken_over_vtable = {
        .get_refs_list  = get_refs_via_connect,
+       .get_bundle_uri = get_bundle_uri,
        .fetch_refs     = fetch_refs_via_pack,
        .push_refs      = git_transport_push,
        .disconnect     = disconnect_git
@@ -921,7 +956,7 @@ void transport_take_over(struct transport *transport,
        data->conn = child;
        data->fd[0] = data->conn->out;
        data->fd[1] = data->conn->in;
-       data->got_remote_heads = 0;
+       data->finished_handshake = 0;
        transport->data = data;
 
        transport->vtable = &taken_over_vtable;
@@ -1054,6 +1089,7 @@ static struct transport_vtable bundle_vtable = {
 
 static struct transport_vtable builtin_smart_vtable = {
        .get_refs_list  = get_refs_via_connect,
+       .get_bundle_uri = get_bundle_uri,
        .fetch_refs     = fetch_refs_via_pack,
        .push_refs      = git_transport_push,
        .connect        = connect_git,
@@ -1068,6 +1104,9 @@ struct transport *transport_get(struct remote *remote, const char *url)
        ret->progress = isatty(2);
        string_list_init_dup(&ret->pack_lockfiles);
 
+       CALLOC_ARRAY(ret->bundles, 1);
+       init_bundle_list(ret->bundles);
+
        if (!remote)
                BUG("No remote provided to transport_get()");
 
@@ -1118,7 +1157,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
                ret->smart_options = &(data->options);
 
                data->conn = NULL;
-               data->got_remote_heads = 0;
+               data->finished_handshake = 0;
        } else {
                /* Unknown protocol in URL. Pass to external handler. */
                int len = external_specification_len(url);
@@ -1482,6 +1521,34 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs)
        return rc;
 }
 
+int transport_get_remote_bundle_uri(struct transport *transport)
+{
+       int value = 0;
+       const struct transport_vtable *vtable = transport->vtable;
+
+       /* Check config only once. */
+       if (transport->got_remote_bundle_uri)
+               return 0;
+       transport->got_remote_bundle_uri = 1;
+
+       /*
+        * Don't request bundle-uri from the server unless configured to
+        * do so by the transfer.bundleURI=true config option.
+        */
+       if (git_config_get_bool("transfer.bundleuri", &value) || !value)
+               return 0;
+
+       if (!transport->bundles->baseURI)
+               transport->bundles->baseURI = xstrdup(transport->url);
+
+       if (!vtable->get_bundle_uri)
+               return error(_("bundle-uri operation not supported by protocol"));
+
+       if (vtable->get_bundle_uri(transport) < 0)
+               return error(_("could not retrieve server-advertised bundle-uri list"));
+       return 0;
+}
+
 void transport_unlock_pack(struct transport *transport, unsigned int flags)
 {
        int in_signal_handler = !!(flags & TRANSPORT_UNLOCK_PACK_IN_SIGNAL_HANDLER);
@@ -1512,6 +1579,8 @@ int transport_disconnect(struct transport *transport)
                ret = transport->vtable->disconnect(transport);
        if (transport->got_remote_refs)
                free_refs((void *)transport->remote_refs);
+       clear_bundle_list(transport->bundles);
+       free(transport->bundles);
        free(transport);
        return ret;
 }
index b5bf7b3e70418a9ded196bf124b1e445bc8076cb..85150f504fbfb9501109d297223f566cc36fe0e5 100644 (file)
@@ -62,6 +62,7 @@ enum transport_family {
        TRANSPORT_FAMILY_IPV6
 };
 
+struct bundle_list;
 struct transport {
        const struct transport_vtable *vtable;
 
@@ -76,6 +77,18 @@ struct transport {
         */
        unsigned got_remote_refs : 1;
 
+       /**
+        * Indicates whether we already called get_bundle_uri_list(); set by
+        * transport.c::transport_get_remote_bundle_uri().
+        */
+       unsigned got_remote_bundle_uri : 1;
+
+       /*
+        * The results of "command=bundle-uri", if both sides support
+        * the "bundle-uri" capability.
+        */
+       struct bundle_list *bundles;
+
        /*
         * Transports that call take-over destroys the data specific to
         * the transport type while doing so, and cannot be reused.
@@ -281,6 +294,12 @@ void transport_ls_refs_options_release(struct transport_ls_refs_options *opts);
 const struct ref *transport_get_remote_refs(struct transport *transport,
                                            struct transport_ls_refs_options *transport_options);
 
+/**
+ * Retrieve bundle URI(s) from a remote. Populates "struct
+ * transport"'s "bundle_uri" and "got_remote_bundle_uri".
+ */
+int transport_get_remote_bundle_uri(struct transport *transport);
+
 /*
  * Fetch the hash algorithm used by a remote.
  *
index 8a762aa0772eb4f7e107da6807092fe0a2be1a61..d11bef96bf3b8d46577bc1e055ad4cc58c5f1a64 100644 (file)
@@ -19,7 +19,6 @@
 #include "promisor-remote.h"
 #include "entry.h"
 #include "parallel-checkout.h"
-#include "sparse-index.h"
 
 /*
  * Error messages expected by scripts out of plumbing commands such as
index 151d9a52784b1f4a149913d38739c91e389d95d6..e25356a06124dae49a486884ccdd2872cb429a29 100644 (file)
@@ -315,7 +315,8 @@ struct find_by_namelen_data {
 };
 
 static int userdiff_find_by_namelen_cb(struct userdiff_driver *driver,
-                                      enum userdiff_driver_type type, void *priv)
+                                      enum userdiff_driver_type type UNUSED,
+                                      void *priv)
 {
        struct find_by_namelen_data *cb_data = priv;
 
diff --git a/ws.c b/ws.c
index 6e69877f25791632d98bf7b109a2eaebd04c96af..46a77bcad6670eacb793c9e07334f61a4b93f242 100644 (file)
--- a/ws.c
+++ b/ws.c
@@ -252,7 +252,7 @@ unsigned ws_check(const char *line, int len, unsigned ws_rule)
        return ws_check_emit_1(line, len, ws_rule, NULL, NULL, NULL, NULL);
 }
 
-int ws_blank_line(const char *line, int len, unsigned ws_rule)
+int ws_blank_line(const char *line, int len)
 {
        /*
         * We _might_ want to treat CR differently from other
index 5813174896cc9ae5fa9287c8bcc432dc8cf2ef47..3162241a570cb60393607f06a8a12963b71afb78 100644 (file)
 #include "worktree.h"
 #include "lockfile.h"
 #include "sequencer.h"
+#include "fsmonitor-settings.h"
 
 #define AB_DELAY_WARNING_IN_MS (2 * 1000)
+#define UF_DELAY_WARNING_IN_MS (2 * 1000)
 
 static const char cut_line[] =
 "------------------------ >8 ------------------------\n";
@@ -438,7 +440,7 @@ static char short_submodule_status(struct wt_status_change_data *d)
 }
 
 static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
-                                        struct diff_options *options,
+                                        struct diff_options *options UNUSED,
                                         void *data)
 {
        struct wt_status *s = data;
@@ -525,7 +527,7 @@ static int unmerged_mask(struct index_state *istate, const char *path)
 }
 
 static void wt_status_collect_updated_cb(struct diff_queue_struct *q,
-                                        struct diff_options *options,
+                                        struct diff_options *options UNUSED,
                                         void *data)
 {
        struct wt_status *s = data;
@@ -1205,6 +1207,13 @@ static void wt_longstatus_print_tracking(struct wt_status *s)
        strbuf_release(&sb);
 }
 
+static int uf_was_slow(struct wt_status *s)
+{
+       if (getenv("GIT_TEST_UF_DELAY_WARNING"))
+               s->untracked_in_ms = 3250;
+       return UF_DELAY_WARNING_IN_MS < s->untracked_in_ms;
+}
+
 static void show_merge_in_progress(struct wt_status *s,
                                   const char *color)
 {
@@ -1814,6 +1823,7 @@ static void wt_longstatus_print(struct wt_status *s)
 {
        const char *branch_color = color(WT_STATUS_ONBRANCH, s);
        const char *branch_status_color = color(WT_STATUS_HEADER, s);
+       enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(s->repo);
 
        if (s->branch) {
                const char *on_what = _("On branch ");
@@ -1870,13 +1880,21 @@ static void wt_longstatus_print(struct wt_status *s)
                wt_longstatus_print_other(s, &s->untracked, _("Untracked files"), "add");
                if (s->show_ignored_mode)
                        wt_longstatus_print_other(s, &s->ignored, _("Ignored files"), "add -f");
-               if (advice_enabled(ADVICE_STATUS_U_OPTION) && 2000 < s->untracked_in_ms) {
+               if (advice_enabled(ADVICE_STATUS_U_OPTION) && uf_was_slow(s)) {
                        status_printf_ln(s, GIT_COLOR_NORMAL, "%s", "");
+                       if (fsm_mode > FSMONITOR_MODE_DISABLED) {
+                               status_printf_ln(s, GIT_COLOR_NORMAL,
+                                               _("It took %.2f seconds to enumerate untracked files,\n"
+                                               "but the results were cached, and subsequent runs may be faster."),
+                                               s->untracked_in_ms / 1000.0);
+                       } else {
+                               status_printf_ln(s, GIT_COLOR_NORMAL,
+                                               _("It took %.2f seconds to enumerate untracked files."),
+                                               s->untracked_in_ms / 1000.0);
+                       }
                        status_printf_ln(s, GIT_COLOR_NORMAL,
-                                        _("It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
-                                          "may speed it up, but you have to be careful not to forget to add\n"
-                                          "new files yourself (see 'git help status')."),
-                                        s->untracked_in_ms / 1000.0);
+                                       _("See 'git help status' for information on how to improve this."));
+                       status_printf_ln(s, GIT_COLOR_NORMAL, "%s", "");
                }
        } else if (s->committable)
                status_printf_ln(s, GIT_COLOR_NORMAL, _("Untracked files not listed%s"),
index 32652ded2d7c5cad87f120a13c3c6c84d6def61f..344c2dfc3eb443a721cc45b6ba3be56e9f186c97 100644 (file)
@@ -973,7 +973,7 @@ void xdl_free_script(xdchange_t *xscr) {
        }
 }
 
-static int xdl_call_hunk_func(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb,
+static int xdl_call_hunk_func(xdfenv_t *xe UNUSED, xdchange_t *xscr, xdemitcb_t *ecb,
                              xdemitconf_t const *xecfg)
 {
        xdchange_t *xch, *xche;
index c4ccd68d4760bc08735d6ca3b7dcdd3440abaf16..75f0fe498661c43078fe19f8b5d10926700763de 100644 (file)
@@ -95,7 +95,7 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg)
 }
 
 
-static long def_ff(const char *rec, long len, char *buf, long sz, void *priv)
+static long def_ff(const char *rec, long len, char *buf, long sz)
 {
        if (len > 0 &&
                        (isalpha((unsigned char)*rec) || /* identifier? */
@@ -117,7 +117,7 @@ static long match_func_rec(xdfile_t *xdf, xdemitconf_t const *xecfg, long ri,
        const char *rec;
        long len = xdl_get_rec(xdf, ri, &rec);
        if (!xecfg->find_func)
-               return def_ff(rec, len, buf, sz, xecfg->find_func_priv);
+               return def_ff(rec, len, buf, sz);
        return xecfg->find_func(rec, len, buf, sz, xecfg->find_func_priv);
 }