Git 2.40.3
Signed-off-by: Junio C Hamano <gitster@pobox.com>
diff --git a/.gitattributes b/.gitattributes
index b0044cf..158c3d4 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,17 +1,17 @@
* whitespace=!indent,trail,space
*.[ch] whitespace=indent,trail,space diff=cpp
-*.sh whitespace=indent,trail,space eol=lf
-*.perl eol=lf diff=perl
-*.pl eof=lf diff=perl
-*.pm eol=lf diff=perl
-*.py eol=lf diff=python
-*.bat eol=crlf
+*.sh whitespace=indent,trail,space text eol=lf
+*.perl text eol=lf diff=perl
+*.pl text eof=lf diff=perl
+*.pm text eol=lf diff=perl
+*.py text eol=lf diff=python
+*.bat text eol=crlf
CODE_OF_CONDUCT.md -whitespace
-/Documentation/**/*.txt eol=lf
-/command-list.txt eol=lf
-/GIT-VERSION-GEN eol=lf
-/mergetools/* eol=lf
-/t/oid-info/* eol=lf
+/Documentation/**/*.txt text eol=lf
+/command-list.txt text eol=lf
+/GIT-VERSION-GEN text eol=lf
+/mergetools/* text eol=lf
+/t/oid-info/* text eol=lf
/Documentation/git-merge.txt conflict-marker-size=32
/Documentation/gitk.txt conflict-marker-size=32
/Documentation/user-manual.txt conflict-marker-size=32
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 76e3f1e..bd390ab 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -288,8 +288,9 @@
- uses: actions/checkout@v4
- run: ci/install-dependencies.sh
- run: ci/run-build-and-tests.sh
- - run: ci/print-test-failures.sh
+ - name: print test failures
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+ run: ci/print-test-failures.sh
- name: Upload failed tests' directories
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
uses: actions/upload-artifact@v4
@@ -324,8 +325,9 @@
if: matrix.vector.jobname == 'linux32'
- run: ci/install-docker-dependencies.sh
- run: ci/run-build-and-tests.sh
- - run: ci/print-test-failures.sh
+ - name: print test failures
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+ run: ci/print-test-failures.sh
- name: Upload failed tests' directories
if: failure() && env.FAILED_TEST_ARTIFACTS != '' && matrix.vector.jobname != 'linux32'
uses: actions/upload-artifact@v4
diff --git a/.gitignore b/.gitignore
index 0832f1d..e875c59 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,14 +14,12 @@
/bin-wrappers/
/git
/git-add
-/git-add--interactive
/git-am
/git-annotate
/git-apply
/git-archimport
/git-archive
/git-bisect
-/git-bisect--helper
/git-blame
/git-branch
/git-bugreport
@@ -60,7 +58,6 @@
/git-difftool
/git-difftool--helper
/git-describe
-/git-env--helper
/git-fast-export
/git-fast-import
/git-fetch
diff --git a/Documentation/RelNotes/2.30.8.txt b/Documentation/RelNotes/2.30.8.txt
index 38c23e0..5ed3efb 100644
--- a/Documentation/RelNotes/2.30.8.txt
+++ b/Documentation/RelNotes/2.30.8.txt
@@ -49,4 +49,3 @@
t5619: demonstrate clone_local() with ambiguous transport
clone: delay picking a transport until after get_repo_path()
dir-iterator: prevent top-level symlinks without FOLLOW_SYMLINKS
-
diff --git a/Documentation/RelNotes/2.40.0.txt b/Documentation/RelNotes/2.40.0.txt
new file mode 100644
index 0000000..3ea445b
--- /dev/null
+++ b/Documentation/RelNotes/2.40.0.txt
@@ -0,0 +1,320 @@
+Git v2.40 Release Notes
+=======================
+
+UI, Workflows & Features
+
+ * "merge-tree" learns a new `--merge-base` option.
+
+ * "git jump" (in contrib/) learned to present the "quickfix list" to
+ its standard output (instead of letting it consumed by the editor
+ it invokes), and learned to also drive emacs/emacsclient.
+
+ * "git var UNKNOWN_VARIABLE" and "git var VARIABLE" with the variable
+ given an empty value used to behave identically. Now the latter
+ 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,
+
+ * 'cat-file' gains mailmap support for its '--batch-check' and '-s'
+ options.
+
+ * Conditionally skip the pre-applypatch and applypatch-msg hooks when
+ applying patches with 'git am'.
+
+ * Introduce an optional configuration to allow the trailing hash that
+ protects the index file from bit flipping.
+
+ * "git check-attr" learned to take an optional tree-ish to read the
+ .gitattributes file from.
+
+ * "scalar" learned to give progress bar.
+
+ * "grep -P" learned to use Unicode Character Property to grok
+ character classes when processing \b and \w etc.
+
+ * "git rebase" often ignored incompatible options instead of
+ complaining, which has been corrected.
+
+ * "scalar" warns but continues when its periodic maintenance
+ feature cannot be enabled.
+
+ * The bundle-URI subsystem adds support for creation-token heuristics
+ to help incremental fetches.
+
+ * Userdiff regexp update for Java language.
+
+ * "git fetch --jobs=0" used to hit a BUG(), which has been corrected
+ to use the available CPUs.
+
+ * An invalid label or ref in the "rebase -i" todo file used to
+ trigger an runtime error. SUch an error is now diagnosed while the
+ todo file is parsed.
+
+ * The "diff" drivers specified by the "diff" attribute attached to
+ paths can now specify which algorithm (e.g. histogram) to use.
+
+ * "git range-diff" learned --abbrev=<num> option.
+
+ * "git archive HEAD^{tree}" records the paths with the current
+ timestamp in the archive, making it harder to obtain a stable
+ output. The command learned the --mtime option to specify an
+ arbitrary timestamp (e.g. --mtime="@0 +0000" for the epoch).
+
+ * The credential subsystem learned that a password may have an
+ explicit expiration.
+
+ * The format.attach configuration variable lacked a way to override a
+ value defined in a lower-priority configuration file (e.g. the
+ system one) by redefining it in a higher-priority configuration
+ file. Now, setting format.attach to an empty string means show the
+ patch inline in the e-mail message, without using MIME attachment.
+
+ This is a backward incompatible change.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * `git bisect` becomes a builtin.
+
+ * 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.
+
+ * Even in a repository with promisor remote, it is useless to
+ attempt to lazily attempt fetching an object that is expected to be
+ commit, because no "filter" mode omits commit objects. Take
+ advantage of this assumption to fail fast on errors.
+
+ * Stop using "git --super-prefix" and narrow the scope of its use to
+ the submodule--helper.
+
+ * Stop running win+VS build by default.
+
+ * CI updates. We probably want a clean-up to move the long shell
+ script embedded in yaml file into a separate file, but that can
+ come later.
+
+ * Use `git diff --no-index` as a test_cmp on Windows.
+
+ We'd probably need to revisit "do we really want to, and have to,
+ lose CRLF vs LF?" later, at which time we may be able to further
+ clean this up by replacing "git diff --no-index" with "diff -u".
+
+ * Avoid unnecessary builds in CI, with settings configured in
+ ci-config.
+
+ * Plug leaks in sequencer subsystem and its users.
+
+ * In-tree .gitattributes update to match the way we recommend our
+ users to mark a file as text.
+ (merge 1f34e0cd3d po/attributes-text later to maint).
+
+ * Finally retire the scripted "git add -p/-i" implementation and have
+ everybody use the one reimplemented in C.
+
+
+Fixes since v2.39
+-----------------
+
+ * Various leak fixes.
+
+ * Fix a bug where `pack-objects` would not respect multiple `--filter`
+ 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.
+
+ * 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.
+
+ * Fix the sequence to fsync $GIT_DIR/packed-refs file that forgot to
+ flush its output to the disk..
+
+ * Fix to a small regression in 2.38 days.
+
+ * "git diff --relative" did not mix well with "git diff --ext-diff",
+ which has been corrected.
+
+ * The logic to see if we are using the "cone" mode by checking the
+ sparsity patterns has been tightened to avoid mistaking a pattern
+ that names a single file as specifying a cone.
+
+ * Deal with a few deprecation warning from cURL library.
+
+ * Doc update for environment variables set when hooks are invoked.
+
+ * Document ORIG_HEAD a bit more.
+
+ * "git ls-tree --format='%(path) %(path)' $tree $path" showed the
+ path three times, which has been corrected.
+
+ * Remove "git env--helper" and demote it to a test-tool subcommand.
+ (merge 4a1baacd46 ab/test-env-helper later to maint).
+
+ * Newer regex library macOS stopped enabling GNU-like enhanced BRE,
+ where '\(A\|B\)' works as alternation, unless explicitly asked with
+ the REG_ENHANCED flag. "git grep" now can be compiled to do so, to
+ retain the old behaviour.
+
+ * Pthread emulation on Win32 leaked thread handle when a thread is
+ joined.
+ (merge 238a9dfe86 sk/win32-close-handle-upon-pthread-join later to maint).
+
+ * "git send-email -v 3" used to be expanded to "git send-email
+ --validate 3" when the user meant to pass them down to
+ "format-patch", which has been corrected.
+ (merge 8774aa56ad km/send-email-with-v-reroll-count later to maint).
+
+ * Document that "branch -f <branch>" disables only the safety to
+ avoid recreating an existing branch.
+
+ * "git fetch <group>", when "<group>" of remotes lists the same
+ remote twice, unnecessarily failed when parallel fetching was
+ enabled, which has been corrected.
+ (merge 06a668cb90 cw/fetch-remote-group-with-duplication later to maint).
+
+ * Clarify how "checkout -b/-B" and "git branch [-f]" are similar but
+ different in the documentation.
+
+ * "git hash-object" now checks that the resulting object is well
+ formed with the same code as "git fsck".
+ (merge 8e4309038f jk/hash-object-fsck later to maint).
+
+ * Improve the error message given when private key is not loaded in
+ the ssh agent in the codepath to sign with an ssh key.
+ (merge dce7b31126 as/ssh-signing-improve-key-missing-error later to maint).
+
+ * Adjust "git request-pull" to strip embedded signature from signed
+ tags to notice non-PGP signatures.
+ (merge a9cad02538 gm/request-pull-with-non-pgp-signed-tags later to maint).
+
+ * Remove support for MSys, which now lags way behind MSys2.
+ (merge 2987407f3c hj/remove-msys-support later to maint).
+
+ * Fix use of CreateThread() API call made early in the windows
+ start-up code.
+ (merge 592bcab61b sk/winansi-createthread-fix later to maint).
+
+ * "git pack-objects" learned to release delta-island bitmap data when
+ it is done using it, saving peak heap memory usage.
+ (merge 647982bb71 ew/free-island-marks later to maint).
+
+ * In an environment where dynamically generated code is prohibited to
+ run (e.g. SELinux), failure to JIT pcre patterns is expected. Fall
+ back to interpreted execution in such a case.
+ (merge 50b6ad55b0 cb/grep-fallback-failing-jit later to maint).
+
+ * "git name-rev" heuristics update.
+ (merge b2182a8730 en/name-rev-make-taggerdate-much-less-important later to maint).
+
+ * Remove more remaining uses of macros that relies on the_index
+ singleton instance without explicitly spelling it out.
+
+ * Remove unnecessary explicit sizing of strbuf.
+ (merge 93ea118bed rs/cache-tree-strbuf-growth-fix later to maint).
+
+ * Doc update.
+ (merge d9ec3b0dc0 jk/doc-ls-remote-matching later to maint).
+
+ * Error messages given upon a signature verification failure used to
+ discard the errors from underlying gpg program, which has been
+ corrected.
+ (merge ad6b320756 js/gpg-errors later to maint).
+
+ * Update --date=default documentation.
+ (merge 9deef088ae rd/doc-default-date-format later to maint).
+
+ * A test helper had a single write(2) of 256kB, which was too big for
+ some platforms (e.g. NonStop), which has been corrected by using
+ xwrite() wrapper appropriately.
+ (merge 58eab6ff13 jc/genzeros-avoid-raw-write later to maint).
+
+ * sscanf(3) used in "git symbolic-ref --short" implementation found
+ to be not working reliably on macOS in UTF-8 locales. Rewrite the
+ code to avoid sscanf() altogether to work it around.
+ (merge 613bef56b8 jk/shorten-unambiguous-ref-wo-sscanf later to maint).
+
+ * Various fix-ups on HTTP tests.
+ (merge 8f2146dbf1 jk/http-test-fixes later to maint).
+
+ * Fixes to code that parses the todo file used in "rebase -i".
+ (merge 666b6e1135 pw/rebase-i-parse-fix later to maint).
+
+ * Test library clean-up.
+ (merge c600a91c94 ar/test-lib-remove-stale-comment later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge 4eb1ccecd4 dh/mingw-ownership-check-typofix later to maint).
+ (merge f95526419b ar/typofix-gitattributes-doc later to maint).
+ (merge 27875aeec9 km/doc-branch-start-point later to maint).
+ (merge 35c194dc57 es/t1509-root-fixes later to maint).
+ (merge 7b341645e3 pw/ci-print-failure-name-fix later to maint).
+ (merge bcb71d45bf jx/t1301-updates later to maint).
+ (merge ebdc46c242 jc/doc-diff-patch.txt later to maint).
+ (merge a87a20cbb4 ar/test-cleanup later to maint).
+ (merge f5156f1885 ar/bisect-doc-update later to maint).
+ (merge fca2d86c97 jk/interop-error later to maint).
+ (merge cf4936ed74 tl/ls-tree-code-clean-up later to maint).
+ (merge dcb47e52b0 en/t6426-todo-cleanup later to maint).
+ (merge 5b8db44bdd jc/format-patch-v-unleak later to maint).
+ (merge 590b636737 jk/hash-object-literally-fd-leak later to maint).
+ (merge 5458ba0a4d tb/t0003-invoke-dd-more-portably later to maint).
+ (merge 70661d288b ar/markup-em-dash later to maint).
+ (merge e750951e74 en/ls-files-doc-update later to maint).
+ (merge 4f542975d1 mh/doc-credential-cache-only-in-core later to maint).
+ (merge 3a2ebaebc7 gc/index-format-doc later to maint).
+ (merge b08edf709d jk/httpd-test-updates later to maint).
+ (merge d85e9448dd wl/new-command-doc later to maint).
+ (merge d912a603ed kf/t5000-modernise later to maint).
+ (merge e65b868d07 rs/size-t-fixes later to maint).
+ (merge 3eb1e1ca9a ab/config-h-remove-unused later to maint).
+ (merge d390e08076 cw/doc-pushurl-vs-url later to maint).
+ (merge 567342fc77 rs/ctype-test later to maint).
+ (merge d35d8f2e7a ap/t2015-style-update later to maint).
diff --git a/Documentation/RelNotes/2.40.1.txt b/Documentation/RelNotes/2.40.1.txt
new file mode 100644
index 0000000..e72f6b1
--- /dev/null
+++ b/Documentation/RelNotes/2.40.1.txt
@@ -0,0 +1,8 @@
+Git v2.40.1 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.30.9, v2.31.8,
+v2.32.7, v2.33.8, v2.34.8, v2.35.8, v2.36.6, v2.37.7, v2.38.5
+and v2.39.3 to address the security issues CVE-2023-25652,
+CVE-2023-25815, and CVE-2023-29007; see the release notes for these
+versions for details.
diff --git a/Documentation/RelNotes/2.40.2.txt b/Documentation/RelNotes/2.40.2.txt
new file mode 100644
index 0000000..646a2cc
--- /dev/null
+++ b/Documentation/RelNotes/2.40.2.txt
@@ -0,0 +1,7 @@
+Git v2.40.2 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.39.4 to address
+the security issues CVE-2024-32002, CVE-2024-32004, CVE-2024-32020,
+CVE-2024-32021 and CVE-2024-32465; see the release notes for that
+version for details.
diff --git a/Documentation/RelNotes/2.40.3.txt b/Documentation/RelNotes/2.40.3.txt
new file mode 100644
index 0000000..6ca088e
--- /dev/null
+++ b/Documentation/RelNotes/2.40.3.txt
@@ -0,0 +1,26 @@
+Git v2.40.3 Release Notes
+=========================
+
+In preparing security fixes for four CVEs, we made overly aggressive
+"defense in depth" changes that broke legitimate use cases like 'git
+lfs' and 'git annex.' This release is to revert these misguided, if
+well-intentioned, changes that were shipped in 2.40.2 and were not
+direct security fixes.
+
+Jeff King (5):
+ send-email: drop FakeTerm hack
+ send-email: avoid creating more than one Term::ReadLine object
+ ci: drop mention of BREW_INSTALL_PACKAGES variable
+ ci: avoid bare "gcc" for osx-gcc job
+ ci: stop installing "gcc-13" for osx-gcc
+
+Johannes Schindelin (6):
+ hook: plug a new memory leak
+ init: use the correct path of the templates directory again
+ Revert "core.hooksPath: add some protection while cloning"
+ tests: verify that `clone -c core.hooksPath=/dev/null` works again
+ clone: drop the protections where hooks aren't run
+ Revert "Add a helper function to compare file contents"
+
+Junio C Hamano (1):
+ Revert "fsck: warn about symlink pointing inside a gitdir"
diff --git a/Documentation/config/add.txt b/Documentation/config/add.txt
index 3e859f3..e0354ce 100644
--- a/Documentation/config/add.txt
+++ b/Documentation/config/add.txt
@@ -7,6 +7,7 @@
variables.
add.interactive.useBuiltin::
- Set to `false` to fall back to the original Perl implementation of
- the interactive version of linkgit:git-add[1] instead of the built-in
- version. Is `true` by default.
+ Unused configuration variable. Used in Git versions v2.25.0 to
+ v2.36.0 to enable the built-in version of linkgit:git-add[1]'s
+ interactive mode, which then became the default in Git
+ versions v2.37.0 to v2.39.0.
diff --git a/Documentation/config/bundle.txt b/Documentation/config/bundle.txt
index daa21eb..3faae386 100644
--- a/Documentation/config/bundle.txt
+++ b/Documentation/config/bundle.txt
@@ -15,6 +15,13 @@
complete understanding of the bundled information (`all`) or if any one
of the listed bundle URIs is sufficient (`any`).
+bundle.heuristic::
+ If this string-valued key exists, then the bundle list is designed to
+ work well with incremental `git fetch` commands. The heuristic signals
+ that there are additional keys available for each bundle that help
+ determine which subset of bundles the client should download. The
+ only value currently understood is `creationToken`.
+
bundle.<id>.*::
The `bundle.<id>.*` keys are used to describe a single item in the
bundle list, grouped under `<id>` for identification purposes.
diff --git a/Documentation/config/feature.txt b/Documentation/config/feature.txt
index 95975e5..e52bc6b 100644
--- a/Documentation/config/feature.txt
+++ b/Documentation/config/feature.txt
@@ -23,6 +23,11 @@
working directory. With many files, commands such as `git status` and
`git checkout` may be slow and these new defaults improve performance:
+
+* `index.skipHash=true` speeds up index writes by not computing a trailing
+ checksum. Note that this will cause Git versions earlier than 2.13.0 to
+ refuse to parse the index and Git versions earlier than 2.40.0 will report
+ a corrupted index during `git fsck`.
++
* `index.version=4` enables path-prefix compression in the index.
+
* `core.untrackedCache=true` enables the untracked cache. This setting assumes
diff --git a/Documentation/config/fetch.txt b/Documentation/config/fetch.txt
index cd65d23..568f0f7 100644
--- a/Documentation/config/fetch.txt
+++ b/Documentation/config/fetch.txt
@@ -96,3 +96,27 @@
merge and the write may take longer. Having an updated commit-graph
file helps performance of many Git commands, including `git merge-base`,
`git push -f`, and `git log --graph`. Defaults to false.
+
+fetch.bundleURI::
+ This value stores a URI for downloading Git object data from a bundle
+ URI before performing an incremental fetch from the origin Git server.
+ This is similar to how the `--bundle-uri` option behaves in
+ linkgit:git-clone[1]. `git clone --bundle-uri` will set the
+ `fetch.bundleURI` value if the supplied bundle URI contains a bundle
+ list that is organized for incremental fetches.
++
+If you modify this value and your repository has a `fetch.bundleCreationToken`
+value, then remove that `fetch.bundleCreationToken` value before fetching from
+the new bundle URI.
+
+fetch.bundleCreationToken::
+ When using `fetch.bundleURI` to fetch incrementally from a bundle
+ list that uses the "creationToken" heuristic, this config value
+ stores the maximum `creationToken` value of the downloaded bundles.
+ This value is used to prevent downloading bundles in the future
+ if the advertised `creationToken` is not strictly larger than this
+ value.
++
+The creation token values are chosen by the provider serving the specific
+bundle URI. If you modify the URI at `fetch.bundleURI`, then be sure to
+remove the value for the `fetch.bundleCreationToken` value before fetching.
diff --git a/Documentation/config/format.txt b/Documentation/config/format.txt
index c7303d8..73678d8 100644
--- a/Documentation/config/format.txt
+++ b/Documentation/config/format.txt
@@ -3,7 +3,8 @@
'format-patch'. The value can also be a double quoted string
which will enable attachments as the default and set the
value as the boundary. See the --attach option in
- linkgit:git-format-patch[1].
+ linkgit:git-format-patch[1]. To countermand an earlier
+ value, set it to an empty string.
format.from::
Provides the default value for the `--from` option to format-patch.
@@ -139,3 +140,7 @@
------------
+
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.
diff --git a/Documentation/config/gpg.txt b/Documentation/config/gpg.txt
index 86f6308..37e2831 100644
--- a/Documentation/config/gpg.txt
+++ b/Documentation/config/gpg.txt
@@ -12,6 +12,9 @@
gpg.format::
Specifies which key format to use when signing with `--gpg-sign`.
Default is "openpgp". Other possible values are "x509", "ssh".
++
+See linkgit:gitformat-signature[5] for the signature format, which differs
+based on the selected `gpg.format`.
gpg.<format>.program::
Use this to customize the program used for the signing format you
diff --git a/Documentation/config/index.txt b/Documentation/config/index.txt
index 75f3a2d..23c7985 100644
--- a/Documentation/config/index.txt
+++ b/Documentation/config/index.txt
@@ -30,3 +30,14 @@
Specify the version with which new index files should be
initialized. This does not affect existing repositories.
If `feature.manyFiles` is enabled, then the default is 4.
+
+index.skipHash::
+ When enabled, do not compute the trailing hash for the index file.
+ This accelerates Git commands that manipulate the index, such as
+ `git add`, `git commit`, or `git status`. Instead of storing the
+ checksum, write a trailing set of bytes with value zero, indicating
+ that the computation was skipped.
++
+If you enable `index.skipHash`, then Git clients older than 2.13.0 will
+refuse to parse the index and Git clients older than 2.40.0 will report an
+error during `git fsck`.
diff --git a/Documentation/config/transfer.txt b/Documentation/config/transfer.txt
index 264812c..c3ac767 100644
--- a/Documentation/config/transfer.txt
+++ b/Documentation/config/transfer.txt
@@ -115,3 +115,9 @@
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`.
diff --git a/Documentation/diff-generate-patch.txt b/Documentation/diff-generate-patch.txt
index c78063d..546adf7 100644
--- a/Documentation/diff-generate-patch.txt
+++ b/Documentation/diff-generate-patch.txt
@@ -1,3 +1,4 @@
+[[generate_patch_text_with_p]]
Generating patch text with -p
-----------------------------
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 3674ac4..7d73e97 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -22,7 +22,13 @@
-p::
-u::
--patch::
- Generate patch (see section on generating patches).
+ Generate patch (see section titled
+ifdef::git-log[]
+<<generate_patch_text_with_p, "Generating patch text with -p">>).
+endif::git-log[]
+ifndef::git-log[]
+"Generating patch text with -p").
+endif::git-log[]
ifdef::git-diff[]
This is the default.
endif::git-diff[]
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index a030d33..ed44c1c 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -274,7 +274,7 @@
------------
staged unstaged path
1: binary nothing foo.png
- 2: +403/-35 +1/-1 git-add--interactive.perl
+ 2: +403/-35 +1/-1 add-interactive.c
------------
+
It shows that foo.png has differences from HEAD (but that is
@@ -282,7 +282,7 @@
difference between indexed copy and the working tree
version (if the working tree version were also different,
'binary' would have been shown in place of 'nothing'). The
-other file, git-add{litdd}interactive.perl, has 403 lines added
+other file, add-interactive.c, has 403 lines added
and 35 lines deleted if you commit what is in the index, but
working tree file has further modifications (one addition and
one deletion).
@@ -303,7 +303,7 @@
------------
staged unstaged path
1: binary nothing foo.png
-* 2: +403/-35 +1/-1 git-add--interactive.perl
+* 2: +403/-35 +1/-1 add-interactive.c
------------
+
To remove selection, prefix the input with `-`
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 326276e..0c1dfb3 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -9,7 +9,7 @@
SYNOPSIS
--------
[verse]
-'git am' [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8]
+'git am' [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8] [--no-verify]
[--[no-]3way] [--interactive] [--committer-date-is-author-date]
[--ignore-date] [--ignore-space-change | --ignore-whitespace]
[--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>]
@@ -138,6 +138,12 @@
--interactive::
Run interactively.
+-n::
+--no-verify::
+ By default, the pre-applypatch and applypatch-msg hooks are run.
+ When any of `--no-verify` or `-n` is given, these are bypassed.
+ See also linkgit:githooks[5].
+
--committer-date-is-author-date::
By default the command records the date from the e-mail
message as the commit author date, and uses the time of
diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt
index 1d478cb..5e16e6d 100644
--- a/Documentation/git-apply.txt
+++ b/Documentation/git-apply.txt
@@ -208,7 +208,7 @@
* `warn` outputs warnings for a few such errors, but applies the
patch as-is (default).
* `fix` outputs warnings for a few such errors, and applies the
- patch after fixing them (`strip` is a synonym --- the tool
+ patch after fixing them (`strip` is a synonym -- the tool
used to consider only trailing whitespace characters as errors, and the
fix involved 'stripping' them, but modern Gits do more).
* `error` outputs warnings for a few such errors, and refuses
diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt
index 60c0409..6bab201 100644
--- a/Documentation/git-archive.txt
+++ b/Documentation/git-archive.txt
@@ -86,6 +86,11 @@
Look for attributes in .gitattributes files in the working tree
as well (see <<ATTRIBUTES>>).
+--mtime=<time>::
+ Set modification time of archive entries. Without this option
+ the committer time is used if `<tree-ish>` is a commit or tag,
+ and the current time if it is a tree.
+
<extra>::
This can be any options that the archiver backend understands.
See next section.
diff --git a/Documentation/git-bisect-lk2009.txt b/Documentation/git-bisect-lk2009.txt
index f3d9566..0bc1657 100644
--- a/Documentation/git-bisect-lk2009.txt
+++ b/Documentation/git-bisect-lk2009.txt
@@ -1347,8 +1347,8 @@
References
----------
-- [[[1]]] https://www.nist.gov/sites/default/files/documents/director/planning/report02-3.pdf['The Economic Impacts of Inadequate Infratructure for Software Testing'. Nist Planning Report 02-3], see Executive Summary and Chapter 8.
-- [[[2]]] http://www.oracle.com/technetwork/java/codeconvtoc-136057.html['Code Conventions for the Java Programming Language'. Sun Microsystems.]
+- [[[1]]] https://web.archive.org/web/20091206032101/http://www.nist.gov/public_affairs/releases/n02-10.htm['Software Errors Cost U.S. Economy $59.5 Billion Annually'. Nist News Release.] See also https://www.nist.gov/system/files/documents/director/planning/report02-3.pdf['The Economic Impacts of Inadequate Infratructure for Software Testing'. Nist Planning Report 02-3], Executive Summary and Chapter 8.
+- [[[2]]] https://www.oracle.com/java/technologies/javase/codeconventions-introduction.html['Code Conventions for the Java Programming Language: 1. Introduction'. Sun Microsystems.]
- [[[3]]] https://en.wikipedia.org/wiki/Software_maintenance['Software maintenance'. Wikipedia.]
- [[[4]]] https://lore.kernel.org/git/7vps5xsbwp.fsf_-_@assigned-by-dhcp.cox.net/[Junio C Hamano. 'Automated bisect success story'.]
- [[[5]]] https://lwn.net/Articles/317154/[Christian Couder. 'Fully automated bisecting with "git bisect run"'. LWN.net.]
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 2aaf13b..d382ac6 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -116,7 +116,7 @@
-f::
--force::
- Reset <branchname> to <startpoint>, even if <branchname> exists
+ Reset <branchname> to <start-point>, even if <branchname> exists
already. Without `-f`, 'git branch' refuses to change an existing branch.
In combination with `-d` (or `--delete`), allow deleting the
branch irrespective of its merged status, or whether it even
diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt
index ec30b5c..411de2e 100644
--- a/Documentation/git-cat-file.txt
+++ b/Documentation/git-cat-file.txt
@@ -45,7 +45,9 @@
-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,54 @@
--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:
+
diff --git a/Documentation/git-check-attr.txt b/Documentation/git-check-attr.txt
index 84f41a8..6e4f3aa 100644
--- a/Documentation/git-check-attr.txt
+++ b/Documentation/git-check-attr.txt
@@ -9,8 +9,8 @@
SYNOPSIS
--------
[verse]
-'git check-attr' [-a | --all | <attr>...] [--] <pathname>...
-'git check-attr' --stdin [-z] [-a | --all | <attr>...]
+'git check-attr' [--source <tree-ish>] [-a | --all | <attr>...] [--] <pathname>...
+'git check-attr' --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]
DESCRIPTION
-----------
@@ -36,6 +36,11 @@
If `--stdin` is also given, input paths are separated
with a NUL character instead of a linefeed character.
+--source=<tree-ish>::
+ Check attributes against the specified tree-ish. It is common to
+ specify the source tree by naming a commit, branch or tag associated
+ with it.
+
\--::
Interpret all preceding arguments as attributes and all following
arguments as path names.
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index dcff441..6bb32ab 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -479,9 +479,9 @@
any of these will create a reference to it:
------------
-$ git checkout -b foo <1>
-$ git branch foo <2>
-$ git tag foo <3>
+$ git checkout -b foo # or "git switch -c foo" <1>
+$ git branch foo <2>
+$ git tag foo <3>
------------
<1> creates a new branch `foo`, which refers to commit `f`, and then
diff --git a/Documentation/git-credential-cache.txt b/Documentation/git-credential-cache.txt
index 432e159..f473994 100644
--- a/Documentation/git-credential-cache.txt
+++ b/Documentation/git-credential-cache.txt
@@ -14,10 +14,13 @@
DESCRIPTION
-----------
-This command caches credentials in memory for use by future Git
-programs. The stored credentials never touch the disk, and are forgotten
-after a configurable timeout. The cache is accessible over a Unix
-domain socket, restricted to the current user by filesystem permissions.
+This command caches credentials for use by future Git programs.
+The stored credentials are kept in memory of the cache-daemon
+process (instead of written to a file) and are forgotten after a
+configurable timeout. Credentials are forgotten sooner if the
+cache-daemon dies, for example if the system restarts. The cache
+is accessible over a Unix domain socket, restricted to the current
+user by filesystem permissions.
You probably don't want to invoke this command directly; it is meant to
be used as a credential helper by other parts of Git. See
diff --git a/Documentation/git-credential.txt b/Documentation/git-credential.txt
index ac2818b..29d184a 100644
--- a/Documentation/git-credential.txt
+++ b/Documentation/git-credential.txt
@@ -144,6 +144,12 @@
The credential's password, if we are asking it to be stored.
+`password_expiry_utc`::
+
+ Generated passwords such as an OAuth access token may have an expiry date.
+ When reading credentials from helpers, `git credential fill` ignores expired
+ passwords. Represented as Unix time UTC, seconds since 1970.
+
`url`::
When this special attribute is read by `git credential`, the
diff --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt
index 63d9569..fba66f1 100644
--- a/Documentation/git-fetch.txt
+++ b/Documentation/git-fetch.txt
@@ -251,10 +251,10 @@
$ git fetch origin
------------------------------------------------
+
-The above command copies all branches from the remote refs/heads/
-namespace and stores them to the local refs/remotes/origin/ namespace,
-unless the branch.<name>.fetch option is used to specify a non-default
-refspec.
+The above command copies all branches from the remote `refs/heads/`
+namespace and stores them to the local `refs/remotes/origin/` namespace,
+unless the `remote.<repository>.fetch` option is used to specify a
+non-default refspec.
* Using refspecs explicitly:
+
diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt
index 77c3a8a..3407f3c 100644
--- a/Documentation/git-hook.txt
+++ b/Documentation/git-hook.txt
@@ -8,7 +8,7 @@
SYNOPSIS
--------
[verse]
-'git hook' run [--ignore-missing] <hook-name> [-- <hook-args>]
+'git hook' run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-args>]
DESCRIPTION
-----------
@@ -31,6 +31,11 @@
OPTIONS
-------
+--to-stdin::
+ For "run"; Specify a file which will be streamed into the
+ hook's stdin. The hook will receive the entire file from
+ beginning to EOF.
+
--ignore-missing::
Ignore any missing hook by quietly returning zero. Used for
tools that want to do a blind one-shot run of a hook that may
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index 440043c..1abdd3c 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -12,6 +12,7 @@
'git ls-files' [-z] [-t] [-v] [-f]
[-c|--cached] [-d|--deleted] [-o|--others] [-i|--ignored]
[-s|--stage] [-u|--unmerged] [-k|--killed] [-m|--modified]
+ [--resolve-undo]
[--directory [--no-empty-directory]] [--eol]
[--deduplicate]
[-x <pattern>|--exclude=<pattern>]
@@ -28,21 +29,26 @@
directory list, and shows different combinations of the two.
One or more of the options below may be used to determine the files
-shown:
+shown, and each file may be printed multiple times if there are
+multiple entries in the index or multiple statuses are applicable for
+the relevant file selection options.
OPTIONS
-------
-c::
--cached::
- Show cached files in the output (default)
+ Show all files cached in Git's index, i.e. all tracked files.
+ (This is the default if no -c/-s/-d/-o/-u/-k/-m/--resolve-undo
+ options are specified.)
-d::
--deleted::
- Show deleted files in the output
+ Show files with an unstaged deletion
-m::
--modified::
- Show modified files in the output
+ Show files with an unstaged modification (note that an unstaged
+ deletion also counts as an unstaged modification)
-o::
--others::
@@ -50,11 +56,14 @@
-i::
--ignored::
- Show only ignored files in the output. When showing files in the
- index, print only those matched by an exclude pattern. When
- showing "other" files, show only those matched by an exclude
- pattern. Standard ignore rules are not automatically activated,
- therefore at least one of the `--exclude*` options is required.
+ Show only ignored files in the output. Must be used with
+ either an explicit '-c' or '-o'. When showing files in the
+ index (i.e. when used with '-c'), print only those files
+ matching an exclude pattern. When showing "other" files
+ (i.e. when used with '-o'), show only those matched by an
+ exclude pattern. Standard ignore rules are not automatically
+ activated, therefore at least one of the `--exclude*` options
+ is required.
-s::
--stage::
@@ -63,19 +72,29 @@
--directory::
If a whole directory is classified as "other", show just its
name (with a trailing slash) and not its whole contents.
+ Has no effect without -o/--others.
--no-empty-directory::
Do not list empty directories. Has no effect without --directory.
-u::
--unmerged::
- Show unmerged files in the output (forces --stage)
+ Show information about unmerged files in the output, but do
+ not show any other tracked files (forces --stage, overrides
+ --cached).
-k::
--killed::
- Show files on the filesystem that need to be removed due
- to file/directory conflicts for checkout-index to
- succeed.
+ Show untracked files on the filesystem that need to be removed
+ due to file/directory conflicts for tracked files to be able to
+ be written to the filesystem.
+
+--resolve-undo::
+ Show files having resolve-undo information in the index
+ together with their resolve-undo information. (resolve-undo
+ information is what is used to implement "git checkout -m
+ $PATH", i.e. to recreate merge conflicts that were
+ accidentally resolved)
-z::
\0 line termination on output and do not quote filenames.
@@ -100,7 +119,8 @@
--exclude-per-directory=<file>::
Read additional exclude patterns that apply only to the
- directory and its subdirectories in <file>.
+ directory and its subdirectories in <file>. Deprecated; use
+ --exclude-standard instead.
--exclude-standard::
Add the standard Git exclusions: .git/info/exclude, .gitignore
@@ -118,24 +138,27 @@
with `-s` or `-u` options does not make any sense.
-t::
- This feature is semi-deprecated. For scripting purpose,
- linkgit:git-status[1] `--porcelain` and
+ Show status tags together with filenames. Note that for
+ scripting purposes, linkgit:git-status[1] `--porcelain` and
linkgit:git-diff-files[1] `--name-status` are almost always
superior alternatives, and users should look at
linkgit:git-status[1] `--short` or linkgit:git-diff[1]
`--name-status` for more user-friendly alternatives.
+
--
-This option identifies the file status with the following tags (followed by
-a space) at the start of each line:
+This option provides a reason for showing each filename, in the form
+of a status tag (which is followed by a space and then the filename).
+The status tags are all single characters from the following list:
- H:: cached
- S:: skip-worktree
- M:: unmerged
- R:: removed/deleted
- C:: modified/changed
- K:: to be killed
- ?:: other
+ H:: tracked file that is not either unmerged or skip-worktree
+ S:: tracked file that is skip-worktree
+ M:: tracked file that is unmerged
+ R:: tracked file with unstaged removal/deletion
+ C:: tracked file with unstaged modification/change
+ K:: untracked paths which are part of file/directory conflicts
+ which prevent checking out tracked files
+ ?:: untracked file
+ U:: file with resolve-undo information
--
-v::
@@ -269,7 +292,9 @@
flags --others or --ignored are specified. linkgit:gitignore[5]
specifies the format of exclude patterns.
-These exclude patterns come from these places, in order:
+Generally, you should just use --exclude-standard, but for historical
+reasons the exclude patterns can be specified from the following
+places, in order:
1. The command-line flag --exclude=<pattern> specifies a
single pattern. Patterns are ordered in the same order
diff --git a/Documentation/git-ls-remote.txt b/Documentation/git-ls-remote.txt
index 492e573..ff3da54 100644
--- a/Documentation/git-ls-remote.txt
+++ b/Documentation/git-ls-remote.txt
@@ -11,7 +11,7 @@
[verse]
'git ls-remote' [--heads] [--tags] [--refs] [--upload-pack=<exec>]
[-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]
- [--symref] [<repository> [<refs>...]]
+ [--symref] [<repository> [<patterns>...]]
DESCRIPTION
-----------
@@ -85,25 +85,32 @@
either a URL or the name of a remote (see the GIT URLS and
REMOTES sections of linkgit:git-fetch[1]).
-<refs>...::
+<patterns>...::
When unspecified, all references, after filtering done
- with --heads and --tags, are shown. When <refs>... are
- specified, only references matching the given patterns
- are displayed.
+ with --heads and --tags, are shown. When <patterns>... are
+ specified, only references matching one or more of the given
+ patterns are displayed. Each pattern is interpreted as a glob
+ (see `glob` in linkgit:gitglossary[7]) which is matched against
+ the "tail" of a ref, starting either from the start of the ref
+ (so a full name like `refs/heads/foo` matches) or from a slash
+ separator (so `bar` matches `refs/heads/bar` but not
+ `refs/heads/foobar`).
EXAMPLES
--------
----
-$ git ls-remote --tags ./.
+$ git ls-remote --tags .
d6602ec5194c87b0fc87103ca4d67251c76f233a refs/tags/v0.99
f25a265a342aed6041ab0cc484224d9ca54b6f41 refs/tags/v0.99.1
7ceca275d047c90c0c7d5afb13ab97efdf51bd6e refs/tags/v0.99.3
c5db5456ae3b0873fc659c19fafdde22313cc441 refs/tags/v0.99.2
0918385dbd9656cab0d1d81ba7453d49bbc16250 refs/tags/junio-gpg-pub
+
$ git ls-remote http://www.kernel.org/pub/scm/git/git.git master seen rc
5fe978a5381f1fbad26a80e682ddd2a401966740 refs/heads/master
c781a84b5204fb294c9ccc79f8b3baceeb32c061 refs/heads/seen
+
$ git remote add korg http://www.kernel.org/pub/scm/git/git.git
$ git ls-remote --tags korg v\*
d6602ec5194c87b0fc87103ca4d67251c76f233a refs/tags/v0.99
diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt
index 04bcc41..88ee942 100644
--- a/Documentation/git-merge-tree.txt
+++ b/Documentation/git-merge-tree.txt
@@ -64,6 +64,11 @@
share no common history. This flag can be given to override that
check and make the merge proceed anyway.
+--merge-base=<commit>::
+ Instead of finding the merge-bases for <branch1> and <branch2>,
+ specify a merge-base for the merge, and specifying multiple bases is
+ currently not supported. This option is incompatible with `--stdin`.
+
[[OUTPUT]]
OUTPUT
------
@@ -216,6 +221,17 @@
* any messages that would have been printed to stdout (the
<<IM,Informational messages>>)
+INPUT FORMAT
+------------
+'git merge-tree --stdin' input format is fully text based. Each line
+has this format:
+
+ [<base-commit> -- ]<branch1> <branch2>
+
+If one line is separated by `--`, the string before the separator is
+used for specifying a merge-base for the merge and the string after
+the separator describes the branches to be merged.
+
MISTAKES TO AVOID
-----------------
diff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt
index 7567955..b097074 100644
--- a/Documentation/git-read-tree.txt
+++ b/Documentation/git-read-tree.txt
@@ -219,7 +219,7 @@
`git diff-index --cached $M`. Note that this does not
necessarily match what `git diff-index --cached $H` would have
produced before such a two tree merge. This is because of cases
-18 and 19 --- if you already had the changes in $M (e.g. maybe
+18 and 19 -- if you already had the changes in $M (e.g. maybe
you picked it up via e-mail in a patch form), `git diff-index
--cached $H` would have told you about the change before this
merge, but it would not show in `git diff-index --cached $M`
diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index d811c1c..9a295bc 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -208,6 +208,39 @@
git rebase --abort
+MODE OPTIONS
+------------
+
+The options in this section cannot be used with any other option,
+including not with each other:
+
+--continue::
+ Restart the rebasing process after having resolved a merge conflict.
+
+--skip::
+ Restart the rebasing process by skipping the current patch.
+
+--abort::
+ Abort the rebase operation and reset HEAD to the original
+ branch. If `<branch>` was provided when the rebase operation was
+ started, then `HEAD` will be reset to `<branch>`. Otherwise `HEAD`
+ will be reset to where it was when the rebase operation was
+ started.
+
+--quit::
+ Abort the rebase operation but `HEAD` is not reset back to the
+ original branch. The index and working tree are also left
+ unchanged as a result. If a temporary stash entry was created
+ using `--autostash`, it will be saved to the stash list.
+
+--edit-todo::
+ Edit the todo list during an interactive rebase.
+
+--show-current-patch::
+ Show the current patch in an interactive rebase or when rebase
+ is stopped because of conflicts. This is the equivalent of
+ `git show REBASE_HEAD`.
+
OPTIONS
-------
--onto <newbase>::
@@ -249,22 +282,6 @@
<branch>::
Working branch; defaults to `HEAD`.
---continue::
- Restart the rebasing process after having resolved a merge conflict.
-
---abort::
- Abort the rebase operation and reset HEAD to the original
- branch. If `<branch>` was provided when the rebase operation was
- started, then `HEAD` will be reset to `<branch>`. Otherwise `HEAD`
- will be reset to where it was when the rebase operation was
- started.
-
---quit::
- Abort the rebase operation but `HEAD` is not reset back to the
- original branch. The index and working tree are also left
- unchanged as a result. If a temporary stash entry was created
- using `--autostash`, it will be saved to the stash list.
-
--apply::
Use applying strategies to rebase (calling `git-am`
internally). This option may become a no-op in the future
@@ -321,7 +338,6 @@
upstream changes, the behavior towards them is controlled by
the `--empty` flag.)
+
-
In the absence of `--keep-base` (or if `--no-reapply-cherry-picks` is
given), these commits will be automatically dropped. Because this
necessitates reading all upstream commits, this can be expensive in
@@ -330,7 +346,6 @@
dropped commit (unless `--quiet` is given). Advice will also be issued
unless `advice.skippedCherryPicks` is set to false (see
linkgit:git-config[1]).
-
+
`--reapply-cherry-picks` allows rebase to forgo reading all upstream
commits, potentially improving performance.
@@ -345,17 +360,6 @@
+
See also INCOMPATIBLE OPTIONS below.
---skip::
- Restart the rebasing process by skipping the current patch.
-
---edit-todo::
- Edit the todo list during an interactive rebase.
-
---show-current-patch::
- Show the current patch in an interactive rebase or when rebase
- is stopped because of conflicts. This is the equivalent of
- `git show REBASE_HEAD`.
-
-m::
--merge::
Using merging strategies to rebase (default).
@@ -574,10 +578,7 @@
--root::
Rebase all commits reachable from `<branch>`, instead of
limiting them with an `<upstream>`. This allows you to rebase
- the root commit(s) on a branch. When used with `--onto`, it
- will skip changes already contained in `<newbase>` (instead of
- `<upstream>`) whereas without `--onto` it will operate on every
- change.
+ the root commit(s) on a branch.
+
See also INCOMPATIBLE OPTIONS below.
@@ -630,6 +631,8 @@
+
If the configuration variable `rebase.updateRefs` is set, then this option
can be used to override and disable this setting.
++
+See also INCOMPATIBLE OPTIONS below.
INCOMPATIBLE OPTIONS
--------------------
@@ -645,17 +648,15 @@
* --merge
* --strategy
* --strategy-option
- * --allow-empty-message
- * --[no-]autosquash
+ * --autosquash
* --rebase-merges
* --interactive
* --exec
* --no-keep-empty
* --empty=
- * --reapply-cherry-picks
- * --edit-todo
+ * --[no-]reapply-cherry-picks when used without --keep-base
* --update-refs
- * --root when used in combination with --onto
+ * --root when used without --onto
In addition, the following pairs of options are incompatible:
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index 5e438a7..a051b1e 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -457,6 +457,66 @@
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]
diff --git a/Documentation/git-var.txt b/Documentation/git-var.txt
index 6aa521f..f40202b 100644
--- a/Documentation/git-var.txt
+++ b/Documentation/git-var.txt
@@ -13,7 +13,8 @@
DESCRIPTION
-----------
-Prints a Git logical variable.
+Prints a Git logical variable. Exits with code 1 if the variable has
+no value.
OPTIONS
-------
@@ -49,6 +50,14 @@
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
diff --git a/Documentation/git.txt b/Documentation/git.txt
index d296946..898907b 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -13,8 +13,7 @@
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
[-p|--paginate|-P|--no-pager] [--no-replace-objects] [--bare]
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
- [--super-prefix=<path>] [--config-env=<name>=<envvar>]
- <command> [<args>]
+ [--config-env=<name>=<envvar>] <command> [<args>]
DESCRIPTION
-----------
@@ -169,11 +168,6 @@
details. Equivalent to setting the `GIT_NAMESPACE` environment
variable.
---super-prefix=<path>::
- Currently for internal use only. Set a prefix which gives a path from
- above a repository down to its root. One use is to give submodules
- context about the superproject that invoked it.
-
--bare::
Treat the repository as a bare repository. If GIT_DIR
environment is not set, it is set to the current working
@@ -619,7 +613,7 @@
(e.g. `new-file` in "git-diff-files"), `/dev/null` (e.g. `old-file`
when a new file is added), or a temporary file (e.g. `old-file` in the
index). `GIT_EXTERNAL_DIFF` should not worry about unlinking the
-temporary file --- it is removed when `GIT_EXTERNAL_DIFF` exits.
+temporary file -- it is removed when `GIT_EXTERNAL_DIFF` exits.
+
For a path that is unmerged, `GIT_EXTERNAL_DIFF` is called with 1
parameter, <path>.
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 4b36d51..39bfbca 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -758,6 +758,37 @@
parameters, just like `GIT_EXTERNAL_DIFF` program is called.
See linkgit:git[1] for details.
+Setting the internal diff algorithm
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The diff algorithm can be set through the `diff.algorithm` config key, but
+sometimes it may be helpful to set the diff algorithm per path. For example,
+one may want to use the `minimal` diff algorithm for .json files, and the
+`histogram` for .c files, and so on without having to pass in the algorithm
+through the command line each time.
+
+First, in `.gitattributes`, assign the `diff` attribute for paths.
+
+------------------------
+*.json diff=<name>
+------------------------
+
+Then, define a "diff.<name>.algorithm" configuration to specify the diff
+algorithm, choosing from `myers`, `patience`, `minimal`, or `histogram`.
+
+----------------------------------------------------------------
+[diff "<name>"]
+ algorithm = histogram
+----------------------------------------------------------------
+
+This diff algorithm applies to user facing diff output like git-diff(1),
+git-show(1) and is used for the `--stat` output as well. The merge machinery
+will not use the diff algorithm set through this method.
+
+NOTE: If `diff.<name>.command` is defined for path with the
+`diff=<name>` attribute, it is executed as an external diff driver
+(see above), and adding `diff.<name>.algorithm` has no effect, as the
+algorithm is not passed to the external diff driver.
Defining a custom hunk-header
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1155,7 +1186,7 @@
String::
- Specify a comma separate list of common whitespace problems to
+ Specify a comma separated list of common whitespace problems to
notice in the same format as the `core.whitespace` configuration
variable.
diff --git a/Documentation/gitcredentials.txt b/Documentation/gitcredentials.txt
index 4522471..100f045 100644
--- a/Documentation/gitcredentials.txt
+++ b/Documentation/gitcredentials.txt
@@ -167,7 +167,7 @@
If there are multiple instances of the `credential.helper` configuration
variable, each helper will be tried in turn, and may provide a username,
password, or nothing. Once Git has acquired both a username and a
-password, no more helpers will be tried.
+non-expired password, no more helpers will be tried.
+
If `credential.helper` is configured to the empty string, this resets
the helper list to empty (so you may override a helper set by a
diff --git a/Documentation/gitformat-index.txt b/Documentation/gitformat-index.txt
index 015cb21..0773e5c 100644
--- a/Documentation/gitformat-index.txt
+++ b/Documentation/gitformat-index.txt
@@ -83,11 +83,13 @@
32-bit mode, split into (high to low bits)
+ 16-bit unused, must be zero
+
4-bit object type
valid values in binary are 1000 (regular file), 1010 (symbolic link)
and 1110 (gitlink)
- 3-bit unused
+ 3-bit unused, must be zero
9-bit unix permission. Only 0755 and 0644 are valid for regular files.
Symbolic links and gitlinks have value 0 in this field.
diff --git a/Documentation/gitformat-signature.txt b/Documentation/gitformat-signature.txt
index a249869..d4d3a31 100644
--- a/Documentation/gitformat-signature.txt
+++ b/Documentation/gitformat-signature.txt
@@ -17,12 +17,24 @@
Git uses cryptographic signatures in various places, currently objects (tags,
commits, mergetags) and transactions (pushes). In every case, the command which
is about to create an object or transaction determines a payload from that,
-calls gpg to obtain a detached signature for the payload (`gpg -bsa`) and
-embeds the signature into the object or transaction.
+calls an external program to obtain a detached signature for the payload
+(`gpg -bsa` in the case of PGP signatures), and embeds the signature into the
+object or transaction.
-Signatures always begin with `-----BEGIN PGP SIGNATURE-----`
-and end with `-----END PGP SIGNATURE-----`, unless gpg is told to
-produce RFC1991 signatures which use `MESSAGE` instead of `SIGNATURE`.
+Signatures begin with an "ASCII Armor" header line and end with a tail line,
+which differ depending on signature type (as selected by `gpg.format`, see
+linkgit:git-config[1]). These are, for `gpg.format` values:
+
+`gpg` (PGP)::
+ `-----BEGIN PGP SIGNATURE-----` and `-----END PGP SIGNATURE-----`.
+ Or, if gpg is told to produce RFC1991 signatures,
+ `-----BEGIN PGP MESSAGE-----` and `-----END PGP MESSAGE-----`
+
+`ssh` (SSH)::
+ `-----BEGIN SSH SIGNATURE-----` and `-----END SSH SIGNATURE-----`
+
+`x509` (X.509)::
+ `-----BEGIN SIGNED MESSAGE-----` and `-----END SIGNED MESSAGE-----`
Signatures sometimes appear as a part of the normal payload
(e.g. a signed tag has the signature block appended after the payload
@@ -37,7 +49,7 @@
This is even true for an originally empty line. In the following
examples, the end of line that ends with a whitespace letter is
highlighted with a `$` sign; if you are trying to recreate these
-example by hand, do not cut and paste them---they are there
+example by hand, do not cut and paste them--they are there
primarily to highlight extra whitespace at the end of some lines.
The signed payload and the way the signature is embedded depends
diff --git a/Documentation/gitprotocol-v2.txt b/Documentation/gitprotocol-v2.txt
index 59bf41c..acb97ad 100644
--- a/Documentation/gitprotocol-v2.txt
+++ b/Documentation/gitprotocol-v2.txt
@@ -578,6 +578,207 @@
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(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
diff --git a/Documentation/howto/new-command.txt b/Documentation/howto/new-command.txt
index 15a4c80..880c511 100644
--- a/Documentation/howto/new-command.txt
+++ b/Documentation/howto/new-command.txt
@@ -1,13 +1,13 @@
From: Eric S. Raymond <esr@thyrsus.com>
Abstract: This is how-to documentation for people who want to add extension
- commands to Git. It should be read alongside api-builtin.txt.
+ commands to Git. It should be read alongside builtin.h.
Content-type: text/asciidoc
How to integrate new subcommands
================================
This is how-to documentation for people who want to add extension
-commands to Git. It should be read alongside api-builtin.txt.
+commands to Git. It should be read alongside builtin.h.
Runtime environment
-------------------
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index 0b4c1c8..3b71334 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -146,24 +146,34 @@
'%m':: left (`<`), right (`>`) or boundary (`-`) mark
'%w([<w>[,<i1>[,<i2>]]])':: switch line wrapping, like the -w option of
linkgit:git-shortlog[1].
-'%<(<N>[,trunc|ltrunc|mtrunc])':: make the next placeholder take at
- least N columns, padding spaces on
+'%<( <N> [,trunc|ltrunc|mtrunc])':: make the next placeholder take at
+ least N column widths, padding spaces on
the right if necessary. Optionally
- truncate at the beginning (ltrunc),
- the middle (mtrunc) or the end
- (trunc) if the output is longer than
- N columns. Note that truncating
+ truncate (with ellipsis '..') at the left (ltrunc) `..ft`,
+ the middle (mtrunc) `mi..le`, or the end
+ (trunc) `rig..`, if the output is longer than
+ N columns.
+ Note 1: that truncating
only works correctly with N >= 2.
-'%<|(<N>)':: make the next placeholder take at least until Nth
- columns, padding spaces on the right if necessary
-'%>(<N>)', '%>|(<N>)':: similar to '%<(<N>)', '%<|(<N>)' respectively,
+ Note 2: spaces around the N and M (see below)
+ values are optional.
+ Note 3: Emojis and other wide characters
+ will take two display columns, which may
+ over-run column boundaries.
+ Note 4: decomposed character combining marks
+ may be misplaced at padding boundaries.
+'%<|( <M> )':: make the next placeholder take at least until Mth
+ display column, padding spaces on the right if necessary.
+ Use negative M values for column positions measured
+ from the right hand edge of the terminal window.
+'%>( <N> )', '%>|( <M> )':: similar to '%<( <N> )', '%<|( <M> )' respectively,
but padding spaces on the left
-'%>>(<N>)', '%>>|(<N>)':: similar to '%>(<N>)', '%>|(<N>)'
+'%>>( <N> )', '%>>|( <M> )':: similar to '%>( <N> )', '%>|( <M> )'
respectively, except that if the next
placeholder takes more spaces than given and
there are spaces on its left, use those
spaces
-'%><(<N>)', '%><|(<N>)':: similar to '%<(<N>)', '%<|(<N>)'
+'%><( <N> )', '%><|( <M> )':: similar to '%<( <N> )', '%<|( <M> )'
respectively, but padding both sides
(i.e. the text is centered)
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index ff68e48..0d90d5b 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -1100,12 +1100,12 @@
format placeholders. When using `-local`, the correct syntax is
`--date=format-local:...`.
-`--date=default` is the default format, and is similar to
-`--date=rfc2822`, with a few exceptions:
+`--date=default` is the default format, and is based on ctime(3)
+output. It shows a single line with three-letter day of the week,
+three-letter month, day-of-month, hour-minute-seconds in "HH:MM:SS"
+format, followed by 4-digit year, plus timezone information, unless
+the local time zone is used, e.g. `Thu Jan 1 00:00:00 1970 +0000`.
--
- - there is no comma after the day-of-week
-
- - the time zone is omitted when the local time zone is used
ifdef::git-rev-list[]
--header::
diff --git a/Documentation/technical/bundle-uri.txt b/Documentation/technical/bundle-uri.txt
index b78d01d..91d3a13 100644
--- a/Documentation/technical/bundle-uri.txt
+++ b/Documentation/technical/bundle-uri.txt
@@ -479,14 +479,14 @@
(This choice is an opt-in via a config option and a command-line
option.)
-4. Allow the client to understand the `bundle.flag=forFetch` configuration
+4. Allow the client to understand the `bundle.heuristic` configuration key
and the `bundle.<id>.creationToken` heuristic. When `git clone`
- discovers a bundle URI with `bundle.flag=forFetch`, it configures the
- client repository to check that bundle URI during later `git fetch <remote>`
+ discovers a bundle URI with `bundle.heuristic`, it configures the client
+ repository to check that bundle URI during later `git fetch <remote>`
commands.
5. Allow clients to discover bundle URIs during `git fetch` and configure
- a bundle URI for later fetches if `bundle.flag=forFetch`.
+ a bundle URI for later fetches if `bundle.heuristic` is set.
6. Implement the "inspect headers" heuristic to reduce data downloads when
the `bundle.<id>.creationToken` heuristic is not available.
diff --git a/Documentation/technical/hash-function-transition.txt b/Documentation/technical/hash-function-transition.txt
index e2ac36d..ed57481 100644
--- a/Documentation/technical/hash-function-transition.txt
+++ b/Documentation/technical/hash-function-transition.txt
@@ -562,7 +562,7 @@
The design described here allows fetches by SHA-1 clients of a
personal SHA-256 repository because it's not much more difficult than
allowing pushes from that repository. This support needs to be guarded
-by a configuration option --- servers like git.kernel.org that serve a
+by a configuration option -- servers like git.kernel.org that serve a
large number of clients would not be expected to bear that cost.
Meaning of signatures
diff --git a/Documentation/technical/rerere.txt b/Documentation/technical/rerere.txt
index 35d4541..be58f1b 100644
--- a/Documentation/technical/rerere.txt
+++ b/Documentation/technical/rerere.txt
@@ -99,7 +99,7 @@
compatible with what AB and AC wanted to do.
So the conflict we would see when merging AB into ACAB should be
-resolved the same way---it is the resolution that is in line with that
+resolved the same way--it is the resolution that is in line with that
declaration.
Imagine that similarly previously a branch XYXZ was forked from XY,
diff --git a/Documentation/urls-remotes.txt b/Documentation/urls-remotes.txt
index 86d0008..e410912 100644
--- a/Documentation/urls-remotes.txt
+++ b/Documentation/urls-remotes.txt
@@ -33,7 +33,9 @@
------------
The `<pushurl>` is used for pushes only. It is optional and defaults
-to `<URL>`.
+to `<URL>`. Pushing to a remote affects all defined pushurls or to all
+defined urls if no pushurls are defined. Fetch, however, will only
+fetch from the first defined url if muliple urls are defined.
Named file in `$GIT_DIR/remotes`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index b58a5e2..b345e89 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.39.5
+DEF_VER=v2.40.3
LF='
'
diff --git a/INSTALL b/INSTALL
index 232314e..6745146 100644
--- a/INSTALL
+++ b/INSTALL
@@ -120,7 +120,7 @@
for everyday use (e.g. "bisect", "request-pull").
- "Perl" version 5.8 or later is needed to use some of the
- features (e.g. preparing a partial commit using "git add -i/-p",
+ features (e.g. sending patches using "git send-email",
interacting with svn repositories with "git svn"). If you can
live without these, use NO_PERL. Note that recent releases of
Redhat/Fedora are reported to ship Perl binary package with some
diff --git a/Makefile b/Makefile
index 4b1502b..79ed649 100644
--- a/Makefile
+++ b/Makefile
@@ -515,10 +515,8 @@
# 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
@@ -695,7 +693,6 @@
# interactive shell sessions without exporting it.
unexport CDPATH
-SCRIPT_SH += git-bisect.sh
SCRIPT_SH += git-difftool--helper.sh
SCRIPT_SH += git-filter-branch.sh
SCRIPT_SH += git-merge-octopus.sh
@@ -711,7 +708,6 @@
SCRIPT_LIB += git-sh-i18n
SCRIPT_LIB += git-sh-setup
-SCRIPT_PERL += git-add--interactive.perl
SCRIPT_PERL += git-archimport.perl
SCRIPT_PERL += git-cvsexportcommit.perl
SCRIPT_PERL += git-cvsimport.perl
@@ -805,6 +801,7 @@
TEST_BUILTINS_OBJS += test-dump-fsmonitor.o
TEST_BUILTINS_OBJS += test-dump-split-index.o
TEST_BUILTINS_OBJS += test-dump-untracked-cache.o
+TEST_BUILTINS_OBJS += test-env-helper.o
TEST_BUILTINS_OBJS += test-example-decorate.o
TEST_BUILTINS_OBJS += test-fast-rebase.o
TEST_BUILTINS_OBJS += test-fsmonitor-client.o
@@ -1206,7 +1203,7 @@
BUILTIN_OBJS += builtin/annotate.o
BUILTIN_OBJS += builtin/apply.o
BUILTIN_OBJS += builtin/archive.o
-BUILTIN_OBJS += builtin/bisect--helper.o
+BUILTIN_OBJS += builtin/bisect.o
BUILTIN_OBJS += builtin/blame.o
BUILTIN_OBJS += builtin/branch.o
BUILTIN_OBJS += builtin/bugreport.o
@@ -1238,7 +1235,6 @@
BUILTIN_OBJS += builtin/diff-tree.o
BUILTIN_OBJS += builtin/diff.o
BUILTIN_OBJS += builtin/difftool.o
-BUILTIN_OBJS += builtin/env--helper.o
BUILTIN_OBJS += builtin/fast-export.o
BUILTIN_OBJS += builtin/fast-import.o
BUILTIN_OBJS += builtin/fetch-pack.o
@@ -1916,7 +1912,7 @@
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
@@ -1933,7 +1929,7 @@
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
diff --git a/RelNotes b/RelNotes
index eda5122..afb47e2 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.39.5.txt
\ No newline at end of file
+Documentation/RelNotes/2.40.3.txt
\ No newline at end of file
diff --git a/apply.c b/apply.c
index b17e833..9762157 100644
--- a/apply.c
+++ b/apply.c
@@ -4105,7 +4105,7 @@ static int preimage_oid_in_gitlink_patch(struct patch *p, struct object_id *oid)
static int build_fake_ancestor(struct apply_state *state, struct patch *list)
{
struct patch *patch;
- struct index_state result = { NULL };
+ struct index_state result = INDEX_STATE_INIT(state->repo);
struct lock_file lock = LOCK_INIT;
int res;
diff --git a/archive.c b/archive.c
index 941495f..9aeaf2b 100644
--- a/archive.c
+++ b/archive.c
@@ -120,7 +120,7 @@ static const struct attr_check *get_archive_attrs(struct index_state *istate,
static struct attr_check *check;
if (!check)
check = attr_check_initl("export-ignore", "export-subst", NULL);
- git_check_attr(istate, path, check);
+ git_check_attr(istate, NULL, path, check);
return check;
}
@@ -472,6 +472,8 @@ static void parse_treeish_arg(const char **argv,
commit_oid = NULL;
archive_time = time(NULL);
}
+ if (ar_args->mtime_option)
+ archive_time = approxidate(ar_args->mtime_option);
tree = parse_tree_indirect(&oid);
if (!tree)
@@ -586,6 +588,7 @@ static int parse_archive_args(int argc, const char **argv,
const char *remote = NULL;
const char *exec = NULL;
const char *output = NULL;
+ const char *mtime_option = NULL;
int compression_level = -1;
int verbose = 0;
int i;
@@ -607,6 +610,9 @@ static int parse_archive_args(int argc, const char **argv,
OPT_BOOL(0, "worktree-attributes", &worktree_attributes,
N_("read .gitattributes in working directory")),
OPT__VERBOSE(&verbose, N_("report archived files on stderr")),
+ { OPTION_STRING, 0, "mtime", &mtime_option, N_("time"),
+ N_("set modification time of archive entries"),
+ PARSE_OPT_NONEG },
OPT_NUMBER_CALLBACK(&compression_level,
N_("set compression level"), number_callback),
OPT_GROUP(""),
@@ -668,6 +674,7 @@ static int parse_archive_args(int argc, const char **argv,
args->base = base;
args->baselen = strlen(base);
args->worktree_attributes = worktree_attributes;
+ args->mtime_option = mtime_option;
return argc;
}
@@ -710,6 +717,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
string_list_clear_func(&args.extra_files, extra_file_info_clear);
free(args.refname);
+ clear_pathspec(&args.pathspec);
return rc;
}
diff --git a/archive.h b/archive.h
index 08bed3e..7178e2a 100644
--- a/archive.h
+++ b/archive.h
@@ -16,6 +16,7 @@ struct archiver_args {
struct tree *tree;
const struct object_id *commit_oid;
const struct commit *commit;
+ const char *mtime_option;
timestamp_t time;
struct pathspec pathspec;
unsigned int verbose : 1;
diff --git a/attr.c b/attr.c
index 9922529..1053dfc 100644
--- a/attr.c
+++ b/attr.c
@@ -13,6 +13,8 @@
#include "dir.h"
#include "utf8.h"
#include "quote.h"
+#include "revision.h"
+#include "object-store.h"
#include "thread-utils.h"
const char git_attr__true[] = "(builtin)true";
@@ -603,8 +605,7 @@ struct attr_check *attr_check_dup(const struct attr_check *check)
ret->nr = check->nr;
ret->alloc = check->alloc;
- ALLOC_ARRAY(ret->items, ret->nr);
- COPY_ARRAY(ret->items, check->items, ret->nr);
+ DUP_ARRAY(ret->items, check->items, ret->nr);
return ret;
}
@@ -745,13 +746,61 @@ static struct attr_stack *read_attr_from_file(const char *path, unsigned flags)
return res;
}
-static struct attr_stack *read_attr_from_index(struct index_state *istate,
- const char *path,
- unsigned flags)
+static struct attr_stack *read_attr_from_buf(char *buf, const char *path,
+ unsigned flags)
{
struct attr_stack *res;
- char *buf, *sp;
+ char *sp;
int lineno = 0;
+
+ if (!buf)
+ return NULL;
+
+ CALLOC_ARRAY(res, 1);
+ for (sp = buf; *sp;) {
+ char *ep;
+ int more;
+
+ ep = strchrnul(sp, '\n');
+ more = (*ep == '\n');
+ *ep = '\0';
+ handle_attr_line(res, sp, path, ++lineno, flags);
+ sp = ep + more;
+ }
+ free(buf);
+
+ return res;
+}
+
+static struct attr_stack *read_attr_from_blob(struct index_state *istate,
+ const struct object_id *tree_oid,
+ const char *path, unsigned flags)
+{
+ struct object_id oid;
+ unsigned long sz;
+ enum object_type type;
+ void *buf;
+ unsigned short mode;
+
+ if (!tree_oid)
+ return NULL;
+
+ if (get_tree_entry(istate->repo, tree_oid, path, &oid, &mode))
+ return NULL;
+
+ buf = repo_read_object_file(istate->repo, &oid, &type, &sz);
+ if (!buf || type != OBJ_BLOB) {
+ free(buf);
+ return NULL;
+ }
+
+ return read_attr_from_buf(buf, path, flags);
+}
+
+static struct attr_stack *read_attr_from_index(struct index_state *istate,
+ const char *path, unsigned flags)
+{
+ char *buf;
unsigned long size;
if (!istate)
@@ -779,28 +828,19 @@ static struct attr_stack *read_attr_from_index(struct index_state *istate,
return NULL;
}
- CALLOC_ARRAY(res, 1);
- for (sp = buf; *sp; ) {
- char *ep;
- int more;
-
- ep = strchrnul(sp, '\n');
- more = (*ep == '\n');
- *ep = '\0';
- handle_attr_line(res, sp, path, ++lineno, flags);
- sp = ep + more;
- }
- free(buf);
- return res;
+ return read_attr_from_buf(buf, path, flags);
}
static struct attr_stack *read_attr(struct index_state *istate,
+ const struct object_id *tree_oid,
const char *path, unsigned flags)
{
struct attr_stack *res = NULL;
if (direction == GIT_ATTR_INDEX) {
res = read_attr_from_index(istate, path, flags);
+ } else if (tree_oid) {
+ res = read_attr_from_blob(istate, tree_oid, path, flags);
} else if (!is_bare_repository()) {
if (direction == GIT_ATTR_CHECKOUT) {
res = read_attr_from_index(istate, path, flags);
@@ -860,6 +900,7 @@ static void push_stack(struct attr_stack **attr_stack_p,
}
static void bootstrap_attr_stack(struct index_state *istate,
+ const struct object_id *tree_oid,
struct attr_stack **stack)
{
struct attr_stack *e;
@@ -885,7 +926,7 @@ static void bootstrap_attr_stack(struct index_state *istate,
}
/* root directory */
- e = read_attr(istate, GITATTRIBUTES_FILE, flags | READ_ATTR_NOFOLLOW);
+ e = read_attr(istate, tree_oid, GITATTRIBUTES_FILE, flags | READ_ATTR_NOFOLLOW);
push_stack(stack, e, xstrdup(""), 0);
/* info frame */
@@ -899,6 +940,7 @@ static void bootstrap_attr_stack(struct index_state *istate,
}
static void prepare_attr_stack(struct index_state *istate,
+ const struct object_id *tree_oid,
const char *path, int dirlen,
struct attr_stack **stack)
{
@@ -920,7 +962,7 @@ static void prepare_attr_stack(struct index_state *istate,
* .gitattributes in deeper directories to shallower ones,
* and finally use the built-in set as the default.
*/
- bootstrap_attr_stack(istate, stack);
+ bootstrap_attr_stack(istate, tree_oid, stack);
/*
* Pop the "info" one that is always at the top of the stack.
@@ -975,7 +1017,7 @@ static void prepare_attr_stack(struct index_state *istate,
strbuf_add(&pathbuf, path + pathbuf.len, (len - pathbuf.len));
strbuf_addf(&pathbuf, "/%s", GITATTRIBUTES_FILE);
- next = read_attr(istate, pathbuf.buf, READ_ATTR_NOFOLLOW);
+ next = read_attr(istate, tree_oid, pathbuf.buf, READ_ATTR_NOFOLLOW);
/* reset the pathbuf to not include "/.gitattributes" */
strbuf_setlen(&pathbuf, len);
@@ -1095,8 +1137,8 @@ static void determine_macros(struct all_attrs_item *all_attrs,
* Otherwise all attributes are collected.
*/
static void collect_some_attrs(struct index_state *istate,
- const char *path,
- struct attr_check *check)
+ const struct object_id *tree_oid,
+ const char *path, struct attr_check *check)
{
int pathlen, rem, dirlen;
const char *cp, *last_slash = NULL;
@@ -1115,7 +1157,7 @@ static void collect_some_attrs(struct index_state *istate,
dirlen = 0;
}
- prepare_attr_stack(istate, path, dirlen, &check->stack);
+ prepare_attr_stack(istate, tree_oid, path, dirlen, &check->stack);
all_attrs_init(&g_attr_hashmap, check);
determine_macros(check->all_attrs, check->stack);
@@ -1124,12 +1166,12 @@ static void collect_some_attrs(struct index_state *istate,
}
void git_check_attr(struct index_state *istate,
- const char *path,
+ const struct object_id *tree_oid, const char *path,
struct attr_check *check)
{
int i;
- collect_some_attrs(istate, path, check);
+ collect_some_attrs(istate, tree_oid, path, check);
for (i = 0; i < check->nr; i++) {
unsigned int n = check->items[i].attr->attr_nr;
@@ -1140,13 +1182,13 @@ void git_check_attr(struct index_state *istate,
}
}
-void git_all_attrs(struct index_state *istate,
+void git_all_attrs(struct index_state *istate, const struct object_id *tree_oid,
const char *path, struct attr_check *check)
{
int i;
attr_check_reset(check);
- collect_some_attrs(istate, path, check);
+ collect_some_attrs(istate, tree_oid, path, check);
for (i = 0; i < check->all_attrs_nr; i++) {
const char *name = check->all_attrs[i].attr->name;
diff --git a/attr.h b/attr.h
index 2f22dff..9884ea2 100644
--- a/attr.h
+++ b/attr.h
@@ -45,7 +45,7 @@
* const char *path;
*
* setup_check();
- * git_check_attr(path, check);
+ * git_check_attr(&the_index, tree_oid, path, check);
* ------------
*
* - Act on `.value` member of the result, left in `check->items[]`:
@@ -120,6 +120,7 @@
#define ATTR_MAX_FILE_SIZE (100 * 1024 * 1024)
struct index_state;
+struct object_id;
/**
* An attribute is an opaque object that is identified by its name. Pass the
@@ -202,13 +203,14 @@ void attr_check_free(struct attr_check *check);
const char *git_attr_name(const struct git_attr *);
void git_check_attr(struct index_state *istate,
- const char *path, struct attr_check *check);
+ const struct object_id *tree_oid, const char *path,
+ struct attr_check *check);
/*
* Retrieve all attributes that apply to the specified path.
* check holds the attributes and their values.
*/
-void git_all_attrs(struct index_state *istate,
+void git_all_attrs(struct index_state *istate, const struct object_id *tree_oid,
const char *path, struct attr_check *check);
enum git_attr_direction {
diff --git a/bisect.c b/bisect.c
index ec7487e..ef5ee5a 100644
--- a/bisect.c
+++ b/bisect.c
@@ -472,7 +472,6 @@ static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
-static GIT_PATH_FUNC(git_path_head_name, "head-name")
static void read_bisect_paths(struct strvec *array)
{
@@ -1188,8 +1187,6 @@ int bisect_clean_state(void)
unlink_or_warn(git_path_bisect_run());
unlink_or_warn(git_path_bisect_terms());
unlink_or_warn(git_path_bisect_first_parent());
- /* Cleanup head-name if it got left by an old version of git-bisect */
- unlink_or_warn(git_path_head_name());
/*
* Cleanup BISECT_START last to support the --no-checkout option
* introduced in the commit 4796e823a.
diff --git a/branch.c b/branch.c
index d182756..e5614b5 100644
--- a/branch.c
+++ b/branch.c
@@ -756,7 +756,7 @@ void create_branches_recursively(struct repository *r, const char *name,
_("submodule '%s': unable to find submodule"),
submodule_entry_list.entries[i].submodule->name);
if (advice_enabled(ADVICE_SUBMODULES_NOT_UPDATED))
- advise(_("You may try updating the submodules using 'git checkout %s && git submodule update --init'"),
+ advise(_("You may try updating the submodules using 'git checkout --no-recurse-submodules %s && git submodule update --init'"),
start_commitish);
exit(code);
}
diff --git a/builtin.h b/builtin.h
index 8901a34..46cc789 100644
--- a/builtin.h
+++ b/builtin.h
@@ -51,10 +51,6 @@
* on bare repositories.
* This only makes sense when `RUN_SETUP` is also set.
*
- * `SUPPORT_SUPER_PREFIX`:
- *
- * The built-in supports `--super-prefix`.
- *
* `DELAY_PAGER_CONFIG`:
*
* If RUN_SETUP or RUN_SETUP_GENTLY is set, git.c normally handles
@@ -116,7 +112,7 @@ int cmd_am(int argc, const char **argv, const char *prefix);
int cmd_annotate(int argc, const char **argv, const char *prefix);
int cmd_apply(int argc, const char **argv, const char *prefix);
int cmd_archive(int argc, const char **argv, const char *prefix);
-int cmd_bisect__helper(int argc, const char **argv, const char *prefix);
+int cmd_bisect(int argc, const char **argv, const char *prefix);
int cmd_blame(int argc, const char **argv, const char *prefix);
int cmd_branch(int argc, const char **argv, const char *prefix);
int cmd_bugreport(int argc, const char **argv, const char *prefix);
diff --git a/builtin/add.c b/builtin/add.c
index 190d1a6..61dd386 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -238,58 +238,14 @@ static int refresh(int verbose, const struct pathspec *pathspec)
return ret;
}
-int run_add_interactive(const char *revision, const char *patch_mode,
- const struct pathspec *pathspec)
-{
- int i;
- struct child_process cmd = CHILD_PROCESS_INIT;
- int use_builtin_add_i =
- git_env_bool("GIT_TEST_ADD_I_USE_BUILTIN", -1);
-
- if (use_builtin_add_i < 0 &&
- git_config_get_bool("add.interactive.usebuiltin",
- &use_builtin_add_i))
- use_builtin_add_i = 1;
-
- if (use_builtin_add_i != 0) {
- enum add_p_mode mode;
-
- if (!patch_mode)
- return !!run_add_i(the_repository, pathspec);
-
- if (!strcmp(patch_mode, "--patch"))
- mode = ADD_P_ADD;
- else if (!strcmp(patch_mode, "--patch=stash"))
- mode = ADD_P_STASH;
- else if (!strcmp(patch_mode, "--patch=reset"))
- mode = ADD_P_RESET;
- else if (!strcmp(patch_mode, "--patch=checkout"))
- mode = ADD_P_CHECKOUT;
- else if (!strcmp(patch_mode, "--patch=worktree"))
- mode = ADD_P_WORKTREE;
- else
- die("'%s' not supported", patch_mode);
-
- return !!run_add_p(the_repository, mode, revision, pathspec);
- }
-
- strvec_push(&cmd.args, "add--interactive");
- if (patch_mode)
- strvec_push(&cmd.args, patch_mode);
- if (revision)
- strvec_push(&cmd.args, revision);
- strvec_push(&cmd.args, "--");
- for (i = 0; i < pathspec->nr; i++)
- /* pass original pathspec, to be re-parsed */
- strvec_push(&cmd.args, pathspec->items[i].original);
-
- cmd.git_cmd = 1;
- return run_command(&cmd);
-}
-
int interactive_add(const char **argv, const char *prefix, int patch)
{
struct pathspec pathspec;
+ int unused;
+
+ if (!git_config_get_bool("add.interactive.usebuiltin", &unused))
+ warning(_("the add.interactive.useBuiltin setting has been removed!\n"
+ "See its entry in 'git help config' for details."));
parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_FULL |
@@ -297,9 +253,10 @@ int interactive_add(const char **argv, const char *prefix, int patch)
PATHSPEC_PREFIX_ORIGIN,
prefix, argv);
- return run_add_interactive(NULL,
- patch ? "--patch" : NULL,
- &pathspec);
+ if (patch)
+ return !!run_add_p(the_repository, ADD_P_ADD, NULL, &pathspec);
+ else
+ return !!run_add_i(the_repository, &pathspec);
}
static int edit_patch(int argc, const char **argv, const char *prefix)
@@ -695,6 +652,6 @@ int cmd_add(int argc, const char **argv, const char *prefix)
die(_("Unable to write new index file"));
dir_clear(&dir);
- UNLEAK(pathspec);
+ clear_pathspec(&pathspec);
return exit_status;
}
diff --git a/builtin/am.c b/builtin/am.c
index dddf1b9..e0848dd 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -3,7 +3,7 @@
*
* Based on git-am.sh by Junio C Hamano.
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "cache.h"
#include "config.h"
#include "builtin.h"
@@ -117,6 +117,7 @@ struct am_state {
/* various operating modes and command line options */
int interactive;
+ int no_verify;
int threeway;
int quiet;
int signoff; /* enum signoff_type */
@@ -472,10 +473,12 @@ static void am_destroy(const struct am_state *state)
*/
static int run_applypatch_msg_hook(struct am_state *state)
{
- int ret;
+ int ret = 0;
assert(state->msg);
- ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);
+
+ if (!state->no_verify)
+ ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);
if (!ret) {
FREE_AND_NULL(state->msg);
@@ -492,24 +495,12 @@ static int run_applypatch_msg_hook(struct am_state *state)
*/
static int run_post_rewrite_hook(const struct am_state *state)
{
- struct child_process cp = CHILD_PROCESS_INIT;
- const char *hook = find_hook("post-rewrite");
- int ret;
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
- if (!hook)
- return 0;
+ strvec_push(&opt.args, "rebase");
+ opt.path_to_stdin = am_path(state, "rewritten");
- strvec_push(&cp.args, hook);
- strvec_push(&cp.args, "rebase");
-
- cp.in = xopen(am_path(state, "rewritten"), O_RDONLY);
- cp.stdout_to_stderr = 1;
- cp.trace2_hook_name = "post-rewrite";
-
- ret = run_command(&cp);
-
- close(cp.in);
- return ret;
+ return run_hooks_opt("post-rewrite", &opt);
}
/**
@@ -1489,8 +1480,7 @@ static int run_apply(const struct am_state *state, const char *index_file)
* 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);
+ DUP_ARRAY(apply_argv, apply_opts.v, apply_opts.nr);
opts_left = apply_parse_options(apply_opts.nr, apply_argv,
&apply_state, &force_apply, &options,
@@ -1650,10 +1640,10 @@ static void do_commit(const struct am_state *state)
const char *reflog_msg, *author, *committer = NULL;
struct strbuf sb = STRBUF_INIT;
- if (run_hooks("pre-applypatch"))
+ if (!state->no_verify && run_hooks("pre-applypatch"))
exit(1);
- if (write_cache_as_tree(&tree, 0, NULL))
+ if (write_index_as_tree(&tree, &the_index, get_index_file(), 0, NULL))
die(_("git write-tree failed to write a tree"));
if (!get_oid_commit("HEAD", &parent)) {
@@ -2061,7 +2051,7 @@ static int clean_index(const struct object_id *head, const struct object_id *rem
if (fast_forward_to(head_tree, head_tree, 1))
return -1;
- if (write_cache_as_tree(&index, 0, NULL))
+ if (write_index_as_tree(&index, &the_index, get_index_file(), 0, NULL))
return -1;
index_tree = parse_tree_indirect(&index);
@@ -2340,6 +2330,8 @@ int cmd_am(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT_BOOL('i', "interactive", &state.interactive,
N_("run interactively")),
+ OPT_BOOL('n', "no-verify", &state.no_verify,
+ N_("bypass pre-applypatch and applypatch-msg hooks")),
OPT_HIDDEN_BOOL('b', "binary", &binary,
N_("historical option -- no-op")),
OPT_BOOL('3', "3way", &state.threeway,
diff --git a/builtin/bisect--helper.c b/builtin/bisect.c
similarity index 90%
rename from builtin/bisect--helper.c
rename to builtin/bisect.c
index 6e41cbd..7301740 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect.c
@@ -15,23 +15,44 @@ static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
-static GIT_PATH_FUNC(git_path_head_name, "head-name")
static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
-static const char * const git_bisect_helper_usage[] = {
- N_("git bisect--helper --bisect-reset [<commit>]"),
- "git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]",
- N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
- " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
- "git bisect--helper --bisect-next",
- N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
- N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
- N_("git bisect--helper --bisect-replay <filename>"),
- N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
- "git bisect--helper --bisect-visualize",
- N_("git bisect--helper --bisect-run <cmd>..."),
+#define BUILTIN_GIT_BISECT_START_USAGE \
+ N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]" \
+ " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]" \
+ " [<pathspec>...]")
+#define BUILTIN_GIT_BISECT_STATE_USAGE \
+ N_("git bisect (good|bad) [<rev>...]")
+#define BUILTIN_GIT_BISECT_TERMS_USAGE \
+ "git bisect terms [--term-good | --term-bad]"
+#define BUILTIN_GIT_BISECT_SKIP_USAGE \
+ N_("git bisect skip [(<rev>|<range>)...]")
+#define BUILTIN_GIT_BISECT_NEXT_USAGE \
+ "git bisect next"
+#define BUILTIN_GIT_BISECT_RESET_USAGE \
+ N_("git bisect reset [<commit>]")
+#define BUILTIN_GIT_BISECT_VISUALIZE_USAGE \
+ "git bisect visualize"
+#define BUILTIN_GIT_BISECT_REPLAY_USAGE \
+ N_("git bisect replay <logfile>")
+#define BUILTIN_GIT_BISECT_LOG_USAGE \
+ "git bisect log"
+#define BUILTIN_GIT_BISECT_RUN_USAGE \
+ N_("git bisect run <cmd>...")
+
+static const char * const git_bisect_usage[] = {
+ BUILTIN_GIT_BISECT_START_USAGE,
+ BUILTIN_GIT_BISECT_STATE_USAGE,
+ BUILTIN_GIT_BISECT_TERMS_USAGE,
+ BUILTIN_GIT_BISECT_SKIP_USAGE,
+ BUILTIN_GIT_BISECT_NEXT_USAGE,
+ BUILTIN_GIT_BISECT_RESET_USAGE,
+ BUILTIN_GIT_BISECT_VISUALIZE_USAGE,
+ BUILTIN_GIT_BISECT_REPLAY_USAGE,
+ BUILTIN_GIT_BISECT_LOG_USAGE,
+ BUILTIN_GIT_BISECT_RUN_USAGE,
NULL
};
@@ -656,7 +677,8 @@ static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char
return bisect_next(terms, prefix);
}
-static enum bisect_error bisect_start(struct bisect_terms *terms, const char **argv, int argc)
+static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
+ const char **argv)
{
int no_checkout = 0;
int first_parent_only = 0;
@@ -785,13 +807,6 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
strbuf_addstr(&start_head, oid_to_hex(&head_oid));
} else if (!get_oid(head, &head_oid) &&
skip_prefix(head, "refs/heads/", &head)) {
- /*
- * This error message should only be triggered by
- * cogito usage, and cogito users should understand
- * it relates to cg-seek.
- */
- if (!is_empty_or_missing_file(git_path_head_name()))
- return error(_("won't bisect on cg-seek'ed tree"));
strbuf_addstr(&start_head, head);
} else {
return error(_("bad HEAD - strange symbolic ref"));
@@ -886,13 +901,13 @@ static int bisect_autostart(struct bisect_terms *terms)
yesno = git_prompt(_("Do you want me to do it for you "
"[Y/n]? "), PROMPT_ECHO);
res = tolower(*yesno) == 'n' ?
- -1 : bisect_start(terms, empty_strvec, 0);
+ -1 : bisect_start(terms, 0, empty_strvec);
return res;
}
-static enum bisect_error bisect_state(struct bisect_terms *terms, const char **argv,
- int argc)
+static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
+ const char **argv)
{
const char *state;
int i, verify_expected = 1;
@@ -1011,7 +1026,7 @@ static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)
struct strvec argv = STRVEC_INIT;
int res;
sq_dequote_to_strvec(rev, &argv);
- res = bisect_start(terms, argv.v, argv.nr);
+ res = bisect_start(terms, argv.nr, argv.v);
strvec_clear(&argv);
return res;
}
@@ -1061,7 +1076,8 @@ static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *f
return bisect_auto_next(terms, NULL);
}
-static enum bisect_error bisect_skip(struct bisect_terms *terms, const char **argv, int argc)
+static enum bisect_error bisect_skip(struct bisect_terms *terms, int argc,
+ const char **argv)
{
int i;
enum bisect_error res;
@@ -1091,13 +1107,14 @@ static enum bisect_error bisect_skip(struct bisect_terms *terms, const char **ar
strvec_push(&argv_state, argv[i]);
}
}
- res = bisect_state(terms, argv_state.v, argv_state.nr);
+ res = bisect_state(terms, argv_state.nr, argv_state.v);
strvec_clear(&argv_state);
return res;
}
-static int bisect_visualize(struct bisect_terms *terms, const char **argv, int argc)
+static int bisect_visualize(struct bisect_terms *terms, int argc,
+ const char **argv)
{
struct child_process cmd = CHILD_PROCESS_INIT;
struct strbuf sb = STRBUF_INIT;
@@ -1180,7 +1197,7 @@ static int verify_good(const struct bisect_terms *terms, const char *command)
return rc;
}
-static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
+static int bisect_run(struct bisect_terms *terms, int argc, const char **argv)
{
int res = BISECT_OK;
struct strbuf command = STRBUF_INIT;
@@ -1191,13 +1208,13 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
if (bisect_next_check(terms, NULL))
return BISECT_FAILED;
- if (argc)
- sq_quote_argv(&command, argv);
- else {
+ if (!argc) {
error(_("bisect run failed: no command provided."));
return BISECT_FAILED;
}
+ sq_quote_argv(&command, argv);
+ strbuf_ltrim(&command);
while (1) {
res = do_bisect_run(command.buf);
@@ -1211,8 +1228,8 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
if (is_first_run && (res == 126 || res == 127)) {
int rc = verify_good(terms, command.buf);
is_first_run = 0;
- if (rc < 0) {
- error(_("unable to verify '%s' on good"
+ if (rc < 0 || 128 <= rc) {
+ error(_("unable to verify %s on good"
" revision"), command.buf);
res = BISECT_FAILED;
break;
@@ -1227,7 +1244,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
if (res < 0 || 128 <= res) {
error(_("bisect run failed: exit code %d from"
- " '%s' is < 0 or >= 128"), res, command.buf);
+ " %s is < 0 or >= 128"), res, command.buf);
break;
}
@@ -1249,7 +1266,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
saved_stdout = dup(1);
dup2(temporary_stdout_fd, 1);
- res = bisect_state(terms, &new_state, 1);
+ res = bisect_state(terms, 1, &new_state);
fflush(stdout);
dup2(saved_stdout, 1);
@@ -1261,14 +1278,14 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
if (res == BISECT_ONLY_SKIPPED_LEFT)
error(_("bisect run cannot continue any more"));
else if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) {
- printf(_("bisect run success"));
+ puts(_("bisect run success"));
res = BISECT_OK;
} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
- printf(_("bisect found first bad commit"));
+ puts(_("bisect found first bad commit"));
res = BISECT_OK;
} else if (res) {
- error(_("bisect run failed: 'git bisect--helper --bisect-state"
- " %s' exited with error code %d"), new_state, res);
+ error(_("bisect run failed: 'git bisect %s'"
+ " exited with error code %d"), new_state, res);
} else {
continue;
}
@@ -1282,7 +1299,8 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)
{
if (argc > 1)
- return error(_("--bisect-reset requires either no argument or a commit"));
+ return error(_("'%s' requires either no argument or a commit"),
+ "git bisect reset");
return bisect_reset(argc ? argv[0] : NULL);
}
@@ -1292,7 +1310,8 @@ static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNU
struct bisect_terms terms = { 0 };
if (argc > 1)
- return error(_("--bisect-terms requires 0 or 1 argument"));
+ return error(_("'%s' requires 0 or 1 argument"),
+ "git bisect terms");
res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
free_terms(&terms);
return res;
@@ -1304,7 +1323,7 @@ static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNU
struct bisect_terms terms = { 0 };
set_terms(&terms, "bad", "good");
- res = bisect_start(&terms, argv, argc);
+ res = bisect_start(&terms, argc, argv);
free_terms(&terms);
return res;
}
@@ -1315,29 +1334,16 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref
struct bisect_terms terms = { 0 };
if (argc)
- return error(_("--bisect-next requires 0 arguments"));
+ return error(_("'%s' requires 0 arguments"),
+ "git bisect next");
get_terms(&terms);
res = bisect_next(&terms, prefix);
free_terms(&terms);
return res;
}
-static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)
+static int cmd_bisect__log(int argc UNUSED, const char **argv UNUSED, const char *prefix UNUSED)
{
- int res;
- struct bisect_terms terms = { 0 };
-
- set_terms(&terms, "bad", "good");
- get_terms(&terms);
- res = bisect_state(&terms, argv, argc);
- free_terms(&terms);
- return res;
-}
-
-static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)
-{
- if (argc)
- return error(_("--bisect-log requires 0 arguments"));
return bisect_log();
}
@@ -1361,7 +1367,7 @@ static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUS
set_terms(&terms, "bad", "good");
get_terms(&terms);
- res = bisect_skip(&terms, argv, argc);
+ res = bisect_skip(&terms, argc, argv);
free_terms(&terms);
return res;
}
@@ -1372,7 +1378,7 @@ static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix
struct bisect_terms terms = { 0 };
get_terms(&terms);
- res = bisect_visualize(&terms, argv, argc);
+ res = bisect_visualize(&terms, argc, argv);
free_terms(&terms);
return res;
}
@@ -1383,14 +1389,14 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE
struct bisect_terms terms = { 0 };
if (!argc)
- return error(_("bisect run failed: no command provided."));
+ return error(_("'%s' failed: no command provided."), "git bisect run");
get_terms(&terms);
- res = bisect_run(&terms, argv, argc);
+ res = bisect_run(&terms, argc, argv);
free_terms(&terms);
return res;
}
-int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
+int cmd_bisect(int argc, const char **argv, const char *prefix)
{
int res = 0;
parse_opt_subcommand_fn *fn = NULL;
@@ -1399,7 +1405,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
OPT_SUBCOMMAND("terms", &fn, cmd_bisect__terms),
OPT_SUBCOMMAND("start", &fn, cmd_bisect__start),
OPT_SUBCOMMAND("next", &fn, cmd_bisect__next),
- OPT_SUBCOMMAND("state", &fn, cmd_bisect__state),
OPT_SUBCOMMAND("log", &fn, cmd_bisect__log),
OPT_SUBCOMMAND("replay", &fn, cmd_bisect__replay),
OPT_SUBCOMMAND("skip", &fn, cmd_bisect__skip),
@@ -1408,22 +1413,27 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
OPT_SUBCOMMAND("run", &fn, cmd_bisect__run),
OPT_END()
};
- argc = parse_options(argc, argv, prefix, options,
- git_bisect_helper_usage, 0);
+ argc = parse_options(argc, argv, prefix, options, git_bisect_usage,
+ PARSE_OPT_SUBCOMMAND_OPTIONAL);
- if (!fn)
- usage_with_options(git_bisect_helper_usage, options);
- argc--;
- argv++;
+ if (!fn) {
+ struct bisect_terms terms = { 0 };
- res = fn(argc, argv, prefix);
+ if (!argc)
+ usage_msg_opt(_("need a command"), git_bisect_usage, options);
- /*
- * Handle early success
- * From check_merge_bases > check_good_are_ancestors_of_bad > bisect_next_all
- */
- if ((res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) || (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND))
- res = BISECT_OK;
+ set_terms(&terms, "bad", "good");
+ get_terms(&terms);
+ if (check_and_set_terms(&terms, argv[0]))
+ usage_msg_optf(_("unknown command: '%s'"), git_bisect_usage,
+ options, argv[0]);
+ res = bisect_state(&terms, argc, argv);
+ free_terms(&terms);
+ } else {
+ argc--;
+ argv++;
+ res = fn(argc, argv, prefix);
+ }
- return -res;
+ return is_bisect_success(res) ? 0 : -res;
}
diff --git a/builtin/bugreport.c b/builtin/bugreport.c
index 9605254..5bc254b 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -106,6 +106,7 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
const char *user_relative_path = NULL;
char *prefixed_filename;
size_t output_path_len;
+ int ret;
const struct option bugreport_options[] = {
OPT_CALLBACK_F(0, "diagnose", &diagnose, N_("mode"),
@@ -182,7 +183,9 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
user_relative_path);
free(prefixed_filename);
- UNLEAK(buffer);
- UNLEAK(report_path);
- return !!launch_editor(report_path.buf, NULL, NULL);
+ strbuf_release(&buffer);
+
+ ret = !!launch_editor(report_path.buf, NULL, NULL);
+ strbuf_release(&report_path);
+ return ret;
}
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index b3be58b..cc17635 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -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);
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index 0fef10e..d7a40e6 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -9,9 +9,10 @@
static int all_attrs;
static int cached_attrs;
static int stdin_paths;
+static char *source;
static const char * const check_attr_usage[] = {
-N_("git check-attr [-a | --all | <attr>...] [--] <pathname>..."),
-N_("git check-attr --stdin [-z] [-a | --all | <attr>...]"),
+N_("git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] <pathname>..."),
+N_("git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"),
NULL
};
@@ -23,6 +24,7 @@ static const struct option check_attr_options[] = {
OPT_BOOL(0 , "stdin", &stdin_paths, N_("read file names from stdin")),
OPT_BOOL('z', NULL, &nul_term_line,
N_("terminate input and output records by a NUL character")),
+ OPT_STRING(0, "source", &source, N_("<tree-ish>"), N_("which tree-ish to check attributes at")),
OPT_END()
};
@@ -55,27 +57,26 @@ static void output_attr(struct attr_check *check, const char *file)
}
}
-static void check_attr(const char *prefix,
- struct attr_check *check,
- int collect_all,
+static void check_attr(const char *prefix, struct attr_check *check,
+ const struct object_id *tree_oid, int collect_all,
const char *file)
+
{
char *full_path =
prefix_path(prefix, prefix ? strlen(prefix) : 0, file);
if (collect_all) {
- git_all_attrs(&the_index, full_path, check);
+ git_all_attrs(&the_index, tree_oid, full_path, check);
} else {
- git_check_attr(&the_index, full_path, check);
+ git_check_attr(&the_index, tree_oid, full_path, check);
}
output_attr(check, file);
free(full_path);
}
-static void check_attr_stdin_paths(const char *prefix,
- struct attr_check *check,
- int collect_all)
+static void check_attr_stdin_paths(const char *prefix, struct attr_check *check,
+ const struct object_id *tree_oid, int collect_all)
{
struct strbuf buf = STRBUF_INIT;
struct strbuf unquoted = STRBUF_INIT;
@@ -89,7 +90,7 @@ static void check_attr_stdin_paths(const char *prefix,
die("line is badly quoted");
strbuf_swap(&buf, &unquoted);
}
- check_attr(prefix, check, collect_all, buf.buf);
+ check_attr(prefix, check, tree_oid, collect_all, buf.buf);
maybe_flush_or_die(stdout, "attribute to stdout");
}
strbuf_release(&buf);
@@ -105,6 +106,8 @@ static NORETURN void error_with_usage(const char *msg)
int cmd_check_attr(int argc, const char **argv, const char *prefix)
{
struct attr_check *check;
+ struct object_id *tree_oid = NULL;
+ struct object_id initialized_oid;
int cnt, i, doubledash, filei;
if (!is_bare_repository())
@@ -176,11 +179,17 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
}
}
+ if (source) {
+ if (repo_get_oid_tree(the_repository, source, &initialized_oid))
+ die("%s: not a valid tree-ish source", source);
+ tree_oid = &initialized_oid;
+ }
+
if (stdin_paths)
- check_attr_stdin_paths(prefix, check, all_attrs);
+ check_attr_stdin_paths(prefix, check, tree_oid, all_attrs);
else {
for (i = filei; i < argc; i++)
- check_attr(prefix, check, all_attrs, argv[i]);
+ check_attr(prefix, check, tree_oid, all_attrs, argv[i]);
maybe_flush_or_die(stdout, "attribute to stdout");
}
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 3fa29a0..a5155cf 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -29,6 +29,7 @@
#include "xdiff-interface.h"
#include "entry.h"
#include "parallel-checkout.h"
+#include "add-interactive.h"
static const char * const checkout_usage[] = {
N_("git checkout [<options>] <branch>"),
@@ -232,7 +233,7 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
pos++;
}
if (!overlay_mode) {
- unlink_entry(ce);
+ unlink_entry(ce, NULL);
return 0;
}
if (stage == 2)
@@ -499,7 +500,7 @@ static int checkout_paths(const struct checkout_opts *opts,
"--merge", "--conflict", "--staged");
if (opts->patch_mode) {
- const char *patch_mode;
+ enum add_p_mode patch_mode;
const char *rev = new_branch_info->name;
char rev_oid[GIT_MAX_HEXSZ + 1];
@@ -517,15 +518,16 @@ static int checkout_paths(const struct checkout_opts *opts,
rev = oid_to_hex_r(rev_oid, &new_branch_info->commit->object.oid);
if (opts->checkout_index && opts->checkout_worktree)
- patch_mode = "--patch=checkout";
+ patch_mode = ADD_P_CHECKOUT;
else if (opts->checkout_index && !opts->checkout_worktree)
- patch_mode = "--patch=reset";
+ patch_mode = ADD_P_RESET;
else if (!opts->checkout_index && opts->checkout_worktree)
- patch_mode = "--patch=worktree";
+ patch_mode = ADD_P_WORKTREE;
else
BUG("either flag must have been set, worktree=%d, index=%d",
opts->checkout_worktree, opts->checkout_index);
- return run_add_interactive(rev, patch_mode, &opts->pathspec);
+ return !!run_add_p(the_repository, patch_mode, rev,
+ &opts->pathspec);
}
repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
@@ -1270,7 +1272,7 @@ static int parse_branchname_arg(int argc, const char **argv,
* between A and B, A...B names that merge base.
*
* (b) If <something> is _not_ a commit, either "--" is present
- * or <something> is not a path, no -t or -b was given, and
+ * or <something> is not a path, no -t or -b was given,
* and there is a tracking branch whose name is <something>
* in one and only one remote (or if the branch exists on the
* remote named in checkout.defaultRemote), then this is a
@@ -1471,6 +1473,8 @@ static void die_if_some_operation_in_progress(void)
"or \"git worktree add\"."));
if (state.bisect_in_progress)
warning(_("you are switching branch while bisecting"));
+
+ wt_status_state_free_buffers(&state);
}
static int checkout_branch(struct checkout_opts *opts,
diff --git a/builtin/clean.c b/builtin/clean.c
index b2701a2..10aaa8c 100644
--- a/builtin/clean.c
+++ b/builtin/clean.c
@@ -560,7 +560,7 @@ static int parse_choice(struct menu_stuff *menu_stuff,
/*
* Implement a git-add-interactive compatible UI, which is borrowed
- * from git-add--interactive.perl.
+ * from add-interactive.c.
*
* Return value:
*
@@ -1092,5 +1092,6 @@ int cmd_clean(int argc, const char **argv, const char *prefix)
strbuf_release(&buf);
string_list_clear(&del_list, 0);
string_list_clear(&exclude_list, 0);
+ clear_pathspec(&pathspec);
return (errors != 0);
}
diff --git a/builtin/clone.c b/builtin/clone.c
index 9ec500d..399b2d3 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -921,6 +921,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
int is_bundle = 0, is_local;
int reject_shallow = 0;
const char *repo_name, *repo, *work_tree, *git_dir;
+ char *repo_to_free = NULL;
char *path = NULL, *dir, *display_repo = NULL;
int dest_exists, real_dest_exists = 0;
const struct ref *refs, *remote_head;
@@ -978,7 +979,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
path = get_repo_path(repo_name, &is_bundle);
if (path) {
FREE_AND_NULL(path);
- repo = absolute_pathdup(repo_name);
+ repo = repo_to_free = absolute_pathdup(repo_name);
} else if (strchr(repo_name, ':')) {
repo = repo_name;
display_repo = transport_anonymize_url(repo);
@@ -1277,12 +1278,16 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
* data from the --bundle-uri option.
*/
if (bundle_uri) {
+ int has_heuristic = 0;
+
/* 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_uri(the_repository, bundle_uri))
+ else if (fetch_bundle_uri(the_repository, bundle_uri, &has_heuristic))
warning(_("failed to fetch objects from bundle URI '%s'"),
bundle_uri);
+ else if (has_heuristic)
+ git_config_set_gently("fetch.bundleuri", bundle_uri);
}
strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
@@ -1300,6 +1305,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));
@@ -1421,6 +1447,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
free(unborn_head);
free(dir);
free(path);
+ free(repo_to_free);
UNLEAK(repo);
junk_mode = JUNK_LEAVE_ALL;
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
index e8f77f5..93704f9 100644
--- a/builtin/commit-graph.c
+++ b/builtin/commit-graph.c
@@ -67,6 +67,7 @@ static int graph_verify(int argc, const char **argv, const char *prefix)
int fd;
struct stat st;
int flags = 0;
+ int ret;
static struct option builtin_commit_graph_verify_options[] = {
OPT_BOOL(0, "shallow", &opts.shallow,
@@ -111,8 +112,9 @@ static int graph_verify(int argc, const char **argv, const char *prefix)
if (!graph)
return !!open_ok;
- UNLEAK(graph);
- return verify_commit_graph(the_repository, graph, flags);
+ ret = verify_commit_graph(the_repository, graph, flags);
+ free_commit_graph(graph);
+ return ret;
}
extern int read_replace_refs;
@@ -267,8 +269,8 @@ static int graph_write(int argc, const char **argv, const char *prefix)
if (opts.reachable) {
if (write_commit_graph_reachable(odb, flags, &write_opts))
- return 1;
- return 0;
+ result = 1;
+ goto cleanup;
}
if (opts.stdin_packs) {
diff --git a/builtin/commit.c b/builtin/commit.c
index 06b1330..985a044 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -5,7 +5,7 @@
* Based on git-commit.sh by Junio C Hamano and Linus Torvalds
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "cache.h"
#include "config.h"
#include "lockfile.h"
@@ -414,7 +414,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
discard_index(&the_index);
read_index_from(&the_index, get_lock_file_path(&index_lock),
get_git_dir());
- if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) {
+ if (cache_tree_update(&the_index, WRITE_TREE_SILENT) == 0) {
if (reopen_lock_file(&index_lock) < 0)
die(_("unable to write index file"));
if (write_locked_index(&the_index, &index_lock, 0))
@@ -444,7 +444,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
LOCK_DIE_ON_ERROR);
add_files_to_cache(also ? prefix : NULL, &pathspec, 0);
refresh_cache_or_die(refresh_flags);
- update_main_cache_tree(WRITE_TREE_SILENT);
+ cache_tree_update(&the_index, WRITE_TREE_SILENT);
if (write_locked_index(&the_index, &index_lock, 0))
die(_("unable to write new_index file"));
commit_style = COMMIT_NORMAL;
@@ -467,7 +467,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
refresh_cache_or_die(refresh_flags);
if (the_index.cache_changed
|| !cache_tree_fully_valid(the_index.cache_tree))
- update_main_cache_tree(WRITE_TREE_SILENT);
+ cache_tree_update(&the_index, WRITE_TREE_SILENT);
if (write_locked_index(&the_index, &index_lock,
COMMIT_LOCK | SKIP_IF_UNCHANGED))
die(_("unable to write new_index file"));
@@ -516,7 +516,7 @@ static const char *prepare_index(const char **argv, const char *prefix,
repo_hold_locked_index(the_repository, &index_lock, LOCK_DIE_ON_ERROR);
add_remove_files(&partial);
refresh_index(&the_index, REFRESH_QUIET, NULL, NULL, NULL);
- update_main_cache_tree(WRITE_TREE_SILENT);
+ cache_tree_update(&the_index, WRITE_TREE_SILENT);
if (write_locked_index(&the_index, &index_lock, 0))
die(_("unable to write new_index file"));
@@ -991,8 +991,11 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
struct object_id oid;
const char *parent = "HEAD";
- if (!active_nr && read_cache() < 0)
- die(_("Cannot read index"));
+ if (!the_index.cache_nr) {
+ discard_index(&the_index);
+ if (repo_read_index(the_repository) < 0)
+ die(_("Cannot read index"));
+ }
if (amend)
parent = "HEAD^1";
@@ -1076,7 +1079,7 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
}
read_index_from(&the_index, index_file, get_git_dir());
- if (update_main_cache_tree(0)) {
+ if (cache_tree_update(&the_index, 0)) {
error(_("Error building trees"));
return 0;
}
@@ -1875,8 +1878,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
apply_autostash(git_path_merge_autostash(the_repository));
cleanup:
- UNLEAK(author_ident);
- UNLEAK(err);
- UNLEAK(sb);
+ strbuf_release(&author_ident);
+ strbuf_release(&err);
+ strbuf_release(&sb);
return ret;
}
diff --git a/builtin/config.c b/builtin/config.c
index 753e5fa..060cf9f 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -639,8 +639,9 @@ static char *default_user_config(void)
int cmd_config(int argc, const char **argv, const char *prefix)
{
int nongit = !startup_info->have_repository;
- char *value;
+ char *value = NULL;
int flags = 0;
+ int ret = 0;
given_config_source.file = xstrdup_or_null(getenv(CONFIG_ENVIRONMENT));
@@ -856,44 +857,38 @@ int cmd_config(int argc, const char **argv, const char *prefix)
free(config_file);
}
else if (actions == ACTION_SET) {
- int ret;
check_write();
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1]);
- UNLEAK(value);
ret = git_config_set_in_file_gently(given_config_source.file, argv[0], value);
if (ret == CONFIG_NOTHING_SET)
error(_("cannot overwrite multiple values with a single value\n"
" Use a regexp, --add or --replace-all to change %s."), argv[0]);
- return ret;
}
else if (actions == ACTION_SET_ALL) {
check_write();
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1]);
- UNLEAK(value);
- return git_config_set_multivar_in_file_gently(given_config_source.file,
- argv[0], value, argv[2],
- flags);
+ ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+ argv[0], value, argv[2],
+ flags);
}
else if (actions == ACTION_ADD) {
check_write();
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1]);
- UNLEAK(value);
- return git_config_set_multivar_in_file_gently(given_config_source.file,
- argv[0], value,
- CONFIG_REGEX_NONE,
- flags);
+ ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+ argv[0], value,
+ CONFIG_REGEX_NONE,
+ flags);
}
else if (actions == ACTION_REPLACE_ALL) {
check_write();
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1]);
- UNLEAK(value);
- return git_config_set_multivar_in_file_gently(given_config_source.file,
- argv[0], value, argv[2],
- flags | CONFIG_FLAGS_MULTI_REPLACE);
+ ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+ argv[0], value, argv[2],
+ flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_GET) {
check_argc(argc, 1, 2);
@@ -934,26 +929,28 @@ int cmd_config(int argc, const char **argv, const char *prefix)
flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_RENAME_SECTION) {
- int ret;
check_write();
check_argc(argc, 2, 2);
ret = git_config_rename_section_in_file(given_config_source.file,
argv[0], argv[1]);
if (ret < 0)
return ret;
- if (ret == 0)
+ else if (!ret)
die(_("no such section: %s"), argv[0]);
+ else
+ ret = 0;
}
else if (actions == ACTION_REMOVE_SECTION) {
- int ret;
check_write();
check_argc(argc, 1, 1);
ret = git_config_rename_section_in_file(given_config_source.file,
argv[0], NULL);
if (ret < 0)
return ret;
- if (ret == 0)
+ else if (!ret)
die(_("no such section: %s"), argv[0]);
+ else
+ ret = 0;
}
else if (actions == ACTION_GET_COLOR) {
check_argc(argc, 1, 2);
@@ -966,5 +963,6 @@ int cmd_config(int argc, const char **argv, const char *prefix)
return get_colorbool(argv[0], argc == 2);
}
- return 0;
+ free(value);
+ return ret;
}
diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
index f3c8983..338058b 100644
--- a/builtin/credential-cache--daemon.c
+++ b/builtin/credential-cache--daemon.c
@@ -127,6 +127,9 @@ static void serve_one_client(FILE *in, FILE *out)
if (e) {
fprintf(out, "username=%s\n", e->item.username);
fprintf(out, "password=%s\n", e->item.password);
+ if (e->item.password_expiry_utc != TIME_MAX)
+ fprintf(out, "password_expiry_utc=%"PRItime"\n",
+ e->item.password_expiry_utc);
}
}
else if (!strcmp(action.buf, "exit")) {
diff --git a/builtin/diff.c b/builtin/diff.c
index 163f2c6..26f1e53 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -612,7 +612,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
if (1 < rev.diffopt.skip_stat_unmatch)
refresh_index_quietly();
release_revisions(&rev);
- UNLEAK(ent);
+ object_array_clear(&ent);
UNLEAK(blob);
return result;
}
diff --git a/builtin/difftool.c b/builtin/difftool.c
index d9b7622..dbbfb19 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -361,7 +361,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
struct hashmap symlinks2 = HASHMAP_INIT(pair_cmp, NULL);
struct hashmap_iter iter;
struct pair_entry *entry;
- struct index_state wtindex;
+ struct index_state wtindex = INDEX_STATE_INIT(the_repository);
struct checkout lstate, rstate;
int err = 0;
struct child_process cmd = CHILD_PROCESS_INIT;
@@ -387,8 +387,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
mkdir(ldir.buf, 0700);
mkdir(rdir.buf, 0700);
- memset(&wtindex, 0, sizeof(wtindex));
-
memset(&lstate, 0, sizeof(lstate));
lstate.base_dir = lbase_dir = xstrdup(ldir.buf);
lstate.base_dir_len = ldir.len;
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 7378caf..a09606b 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -29,6 +29,7 @@
#include "commit-graph.h"
#include "shallow.h"
#include "worktree.h"
+#include "bundle-uri.h"
#define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
@@ -2109,6 +2110,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv,
int cmd_fetch(int argc, const char **argv, const char *prefix)
{
int i;
+ const char *bundle_uri;
struct string_list list = STRING_LIST_INIT_DUP;
struct remote *remote = NULL;
int result = 0;
@@ -2194,6 +2196,13 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
if (dry_run)
write_fetch_head = 0;
+ if (!max_jobs)
+ max_jobs = online_cpus();
+
+ if (!git_config_get_string_tmp("fetch.bundleuri", &bundle_uri) &&
+ fetch_bundle_uri(the_repository, bundle_uri, NULL))
+ warning(_("failed to fetch bundles from '%s'"), bundle_uri);
+
if (all) {
if (argc == 1)
die(_("fetch --all does not take a repository argument"));
@@ -2228,6 +2237,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix)
argv++;
}
}
+ string_list_remove_duplicates(&list, 0);
if (negotiate_only) {
struct oidset acked_commits = OIDSET_INIT;
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 6f30a4f..0feef8c 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -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;
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index b506381..44db83f 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -27,6 +27,7 @@ static int hash_literally(struct object_id *oid, int fd, const char *type, unsig
else
ret = write_object_file_literally(buf.buf, buf.len, type, oid,
flags);
+ close(fd);
strbuf_release(&buf);
return ret;
}
diff --git a/builtin/hook.c b/builtin/hook.c
index b6530d1..f95b796 100644
--- a/builtin/hook.c
+++ b/builtin/hook.c
@@ -7,7 +7,7 @@
#include "strvec.h"
#define BUILTIN_HOOK_RUN_USAGE \
- N_("git hook run [--ignore-missing] <hook-name> [-- <hook-args>]")
+ N_("git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-args>]")
static const char * const builtin_hook_usage[] = {
BUILTIN_HOOK_RUN_USAGE,
@@ -28,6 +28,8 @@ static int run(int argc, const char **argv, const char *prefix)
struct option run_options[] = {
OPT_BOOL(0, "ignore-missing", &ignore_missing,
N_("silently ignore missing requested <hook-name>")),
+ OPT_STRING(0, "to-stdin", &opt.path_to_stdin, N_("path"),
+ N_("file to read into hooks' stdin")),
OPT_END(),
};
int ret;
diff --git a/builtin/log.c b/builtin/log.c
index 89447a5..a70fba1 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -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;
@@ -1006,6 +1007,8 @@ static int git_format_config(const char *var, const char *value, void *cb)
if (!strcmp(var, "format.attach")) {
if (value && *value)
default_attach = xstrdup(value);
+ else if (value && !*value)
+ FREE_AND_NULL(default_attach);
else
default_attach = xstrdup(git_version_string);
return 0;
@@ -1077,6 +1080,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);
}
@@ -1870,6 +1877,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
struct strbuf rdiff1 = STRBUF_INIT;
struct strbuf rdiff2 = STRBUF_INIT;
struct strbuf rdiff_title = STRBUF_INIT;
+ struct strbuf sprefix = STRBUF_INIT;
int creation_factor = -1;
const struct option builtin_format_patch_options[] = {
@@ -2010,12 +2018,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
if (reroll_count) {
- struct strbuf sprefix = STRBUF_INIT;
-
strbuf_addf(&sprefix, "%s v%s",
rev.subject_prefix, reroll_count);
rev.reroll_count = reroll_count;
- rev.subject_prefix = strbuf_detach(&sprefix, NULL);
+ rev.subject_prefix = sprefix.buf;
}
for (i = 0; i < extra_hdr.nr; i++) {
@@ -2105,6 +2111,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) {
@@ -2376,6 +2385,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
strbuf_release(&rdiff1);
strbuf_release(&rdiff2);
strbuf_release(&rdiff_title);
+ strbuf_release(&sprefix);
free(to_free);
if (rev.ref_message_ids)
string_list_clear(rev.ref_message_ids, 0);
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 4cf8a23..a03b559 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -613,6 +613,7 @@ void overlay_tree_on_index(struct index_state *istate,
if (!fn)
fn = read_one_entry_quick;
err = read_tree(the_repository, tree, &pathspec, fn, istate);
+ clear_pathspec(&pathspec);
if (err)
die("unable to read tree entries %s", tree_name);
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
index 5d5ac03..6516177 100644
--- a/builtin/ls-remote.c
+++ b/builtin/ls-remote.c
@@ -8,7 +8,7 @@
static const char * const ls_remote_usage[] = {
N_("git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
" [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
- " [--symref] [<repository> [<refs>...]]"),
+ " [--symref] [<repository> [<patterns>...]]"),
NULL
};
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index b1f69fb..8cc8c99 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -14,37 +14,11 @@
#include "parse-options.h"
#include "pathspec.h"
-static int line_termination = '\n';
-#define LS_RECURSIVE 1
-#define LS_TREE_ONLY (1 << 1)
-#define LS_SHOW_TREES (1 << 2)
-static int abbrev;
-static int ls_options;
-static struct pathspec pathspec;
-static int chomp_prefix;
-static const char *ls_tree_prefix;
-static const char *format;
-struct show_tree_data {
- unsigned mode;
- enum object_type type;
- const struct object_id *oid;
- const char *pathname;
- struct strbuf *base;
-};
-
-static const char * const ls_tree_usage[] = {
+static const char * const ls_tree_usage[] = {
N_("git ls-tree [<options>] <tree-ish> [<path>...]"),
NULL
};
-static enum ls_tree_cmdmode {
- MODE_DEFAULT = 0,
- MODE_LONG,
- MODE_NAME_ONLY,
- MODE_NAME_STATUS,
- MODE_OBJECT_ONLY,
-} cmdmode;
-
static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
const enum object_type type, unsigned int padded)
{
@@ -64,10 +38,34 @@ static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
}
}
+struct ls_tree_options {
+ unsigned null_termination:1;
+ int abbrev;
+ enum ls_tree_path_options {
+ LS_RECURSIVE = 1 << 0,
+ LS_TREE_ONLY = 1 << 1,
+ LS_SHOW_TREES = 1 << 2,
+ } ls_options;
+ struct pathspec pathspec;
+ int chomp_prefix;
+ const char *ls_tree_prefix;
+ const char *format;
+};
+
+struct show_tree_data {
+ struct ls_tree_options *options;
+ unsigned mode;
+ enum object_type type;
+ const struct object_id *oid;
+ const char *pathname;
+ struct strbuf *base;
+};
+
static size_t expand_show_tree(struct strbuf *sb, const char *start,
void *context)
{
struct show_tree_data *data = context;
+ struct ls_tree_options *options = data->options;
const char *end;
const char *p;
unsigned int errlen;
@@ -92,10 +90,10 @@ static size_t expand_show_tree(struct strbuf *sb, const char *start,
} else if (skip_prefix(start, "(objectsize)", &p)) {
expand_objectsize(sb, data->oid, data->type, 0);
} else if (skip_prefix(start, "(objectname)", &p)) {
- strbuf_add_unique_abbrev(sb, data->oid, abbrev);
+ strbuf_add_unique_abbrev(sb, data->oid, options->abbrev);
} else if (skip_prefix(start, "(path)", &p)) {
- const char *name;
- const char *prefix = chomp_prefix ? ls_tree_prefix : NULL;
+ const char *name = data->base->buf;
+ const char *prefix = options->chomp_prefix ? options->ls_tree_prefix : NULL;
struct strbuf sbuf = STRBUF_INIT;
size_t baselen = data->base->len;
@@ -111,18 +109,19 @@ static size_t expand_show_tree(struct strbuf *sb, const char *start,
return len;
}
-static int show_recursive(const char *base, size_t baselen, const char *pathname)
+static int show_recursive(struct ls_tree_options *options, const char *base,
+ size_t baselen, const char *pathname)
{
int i;
- if (ls_options & LS_RECURSIVE)
+ if (options->ls_options & LS_RECURSIVE)
return 1;
- if (!pathspec.nr)
+ if (!options->pathspec.nr)
return 0;
- for (i = 0; i < pathspec.nr; i++) {
- const char *spec = pathspec.items[i].match;
+ for (i = 0; i < options->pathspec.nr; i++) {
+ const char *spec = options->pathspec.items[i].match;
size_t len, speclen;
if (strncmp(base, spec, baselen))
@@ -142,13 +141,14 @@ static int show_recursive(const char *base, size_t baselen, const char *pathname
}
static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
- const char *pathname, unsigned mode, void *context UNUSED)
+ const char *pathname, unsigned mode, void *context)
{
+ struct ls_tree_options *options = context;
int recurse = 0;
struct strbuf sb = STRBUF_INIT;
enum object_type type = object_type(mode);
-
- struct show_tree_data data = {
+ struct show_tree_data cb_data = {
+ .options = options,
.mode = mode,
.type = type,
.oid = oid,
@@ -156,92 +156,100 @@ static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
.base = base,
};
- if (type == OBJ_TREE && show_recursive(base->buf, base->len, pathname))
+ if (type == OBJ_TREE && show_recursive(options, base->buf, base->len, pathname))
recurse = READ_TREE_RECURSIVE;
- if (type == OBJ_TREE && recurse && !(ls_options & LS_SHOW_TREES))
+ if (type == OBJ_TREE && recurse && !(options->ls_options & LS_SHOW_TREES))
return recurse;
- if (type == OBJ_BLOB && (ls_options & LS_TREE_ONLY))
+ if (type == OBJ_BLOB && (options->ls_options & LS_TREE_ONLY))
return 0;
- strbuf_expand(&sb, format, expand_show_tree, &data);
- strbuf_addch(&sb, line_termination);
+ strbuf_expand(&sb, options->format, expand_show_tree, &cb_data);
+ strbuf_addch(&sb, options->null_termination ? '\0' : '\n');
fwrite(sb.buf, sb.len, 1, stdout);
strbuf_release(&sb);
return recurse;
}
-static int show_tree_common(struct show_tree_data *data, int *recurse,
- const struct object_id *oid, struct strbuf *base,
- const char *pathname, unsigned mode)
+static int show_tree_common(struct ls_tree_options *options, int *recurse,
+ struct strbuf *base, const char *pathname,
+ enum object_type type)
{
- enum object_type type = object_type(mode);
int ret = -1;
-
*recurse = 0;
- data->mode = mode;
- data->type = type;
- data->oid = oid;
- data->pathname = pathname;
- data->base = base;
if (type == OBJ_BLOB) {
- if (ls_options & LS_TREE_ONLY)
+ if (options->ls_options & LS_TREE_ONLY)
ret = 0;
} else if (type == OBJ_TREE &&
- show_recursive(base->buf, base->len, pathname)) {
+ show_recursive(options, base->buf, base->len, pathname)) {
*recurse = READ_TREE_RECURSIVE;
- if (!(ls_options & LS_SHOW_TREES))
+ if (!(options->ls_options & LS_SHOW_TREES))
ret = *recurse;
}
return ret;
}
-static void show_tree_common_default_long(struct strbuf *base,
+static void show_tree_common_default_long(struct ls_tree_options *options,
+ struct strbuf *base,
const char *pathname,
const size_t baselen)
{
+ const char *prefix = options->chomp_prefix ? options->ls_tree_prefix : NULL;
+
strbuf_addstr(base, pathname);
- write_name_quoted_relative(base->buf,
- chomp_prefix ? ls_tree_prefix : NULL, stdout,
- line_termination);
+
+ if (options->null_termination) {
+ struct strbuf sb = STRBUF_INIT;
+ const char *name = relative_path(base->buf, prefix, &sb);
+
+ fputs(name, stdout);
+ fputc('\0', stdout);
+
+ strbuf_release(&sb);
+ } else {
+ write_name_quoted_relative(base->buf, prefix, stdout, '\n');
+ }
+
strbuf_setlen(base, baselen);
}
static int show_tree_default(const struct object_id *oid, struct strbuf *base,
const char *pathname, unsigned mode,
- void *context UNUSED)
+ void *context)
{
+ struct ls_tree_options *options = context;
int early;
int recurse;
- struct show_tree_data data = { 0 };
+ enum object_type type = object_type(mode);
- early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ early = show_tree_common(options, &recurse, base, pathname, type);
if (early >= 0)
return early;
- printf("%06o %s %s\t", data.mode, type_name(data.type),
- find_unique_abbrev(data.oid, abbrev));
- show_tree_common_default_long(base, pathname, data.base->len);
+ printf("%06o %s %s\t", mode, type_name(object_type(mode)),
+ find_unique_abbrev(oid, options->abbrev));
+ show_tree_common_default_long(options, base, pathname, base->len);
return recurse;
}
static int show_tree_long(const struct object_id *oid, struct strbuf *base,
const char *pathname, unsigned mode,
- void *context UNUSED)
+ void *context)
{
+ struct ls_tree_options *options = context;
int early;
int recurse;
- struct show_tree_data data = { 0 };
char size_text[24];
+ enum object_type type = object_type(mode);
- early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ early = show_tree_common(options, &recurse, base, pathname, type);
if (early >= 0)
return early;
- if (data.type == OBJ_BLOB) {
+ if (type == OBJ_BLOB) {
unsigned long size;
- if (oid_object_info(the_repository, data.oid, &size) == OBJ_BAD)
+ if (oid_object_info(the_repository, oid, &size) == OBJ_BAD)
xsnprintf(size_text, sizeof(size_text), "BAD");
else
xsnprintf(size_text, sizeof(size_text),
@@ -250,49 +258,76 @@ static int show_tree_long(const struct object_id *oid, struct strbuf *base,
xsnprintf(size_text, sizeof(size_text), "-");
}
- printf("%06o %s %s %7s\t", data.mode, type_name(data.type),
- find_unique_abbrev(data.oid, abbrev), size_text);
- show_tree_common_default_long(base, pathname, data.base->len);
+ printf("%06o %s %s %7s\t", mode, type_name(type),
+ find_unique_abbrev(oid, options->abbrev), size_text);
+ show_tree_common_default_long(options, base, pathname, base->len);
return recurse;
}
static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
const char *pathname, unsigned mode,
- void *context UNUSED)
+ void *context)
{
+ struct ls_tree_options *options = context;
int early;
int recurse;
const size_t baselen = base->len;
- struct show_tree_data data = { 0 };
+ enum object_type type = object_type(mode);
+ const char *prefix;
- early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ early = show_tree_common(options, &recurse, base, pathname, type);
if (early >= 0)
return early;
+ prefix = options->chomp_prefix ? options->ls_tree_prefix : NULL;
strbuf_addstr(base, pathname);
- write_name_quoted_relative(base->buf,
- chomp_prefix ? ls_tree_prefix : NULL,
- stdout, line_termination);
+ if (options->null_termination) {
+ struct strbuf sb = STRBUF_INIT;
+ const char *name = relative_path(base->buf, prefix, &sb);
+
+ fputs(name, stdout);
+ fputc('\0', stdout);
+
+ strbuf_release(&sb);
+ } else {
+ write_name_quoted_relative(base->buf, prefix, stdout, '\n');
+ }
strbuf_setlen(base, baselen);
return recurse;
}
static int show_tree_object(const struct object_id *oid, struct strbuf *base,
const char *pathname, unsigned mode,
- void *context UNUSED)
+ void *context)
{
+ struct ls_tree_options *options = context;
int early;
int recurse;
- struct show_tree_data data = { 0 };
+ enum object_type type = object_type(mode);
+ const char *str;
- early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ early = show_tree_common(options, &recurse, base, pathname, type);
if (early >= 0)
return early;
- printf("%s%c", find_unique_abbrev(oid, abbrev), line_termination);
+ str = find_unique_abbrev(oid, options->abbrev);
+ if (options->null_termination) {
+ fputs(str, stdout);
+ fputc('\0', stdout);
+ } else {
+ puts(str);
+ }
return recurse;
}
+enum ls_tree_cmdmode {
+ MODE_DEFAULT = 0,
+ MODE_LONG,
+ MODE_NAME_ONLY,
+ MODE_NAME_STATUS,
+ MODE_OBJECT_ONLY,
+};
+
struct ls_tree_cmdmode_to_fmt {
enum ls_tree_cmdmode mode;
const char *const fmt;
@@ -332,15 +367,18 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
struct tree *tree;
int i, full_tree = 0;
read_tree_fn_t fn = NULL;
+ enum ls_tree_cmdmode cmdmode = MODE_DEFAULT;
+ int null_termination = 0;
+ struct ls_tree_options options = { 0 };
const struct option ls_tree_options[] = {
- OPT_BIT('d', NULL, &ls_options, N_("only show trees"),
+ OPT_BIT('d', NULL, &options.ls_options, N_("only show trees"),
LS_TREE_ONLY),
- OPT_BIT('r', NULL, &ls_options, N_("recurse into subtrees"),
+ OPT_BIT('r', NULL, &options.ls_options, N_("recurse into subtrees"),
LS_RECURSIVE),
- OPT_BIT('t', NULL, &ls_options, N_("show trees when recursing"),
+ OPT_BIT('t', NULL, &options.ls_options, N_("show trees when recursing"),
LS_SHOW_TREES),
- OPT_SET_INT('z', NULL, &line_termination,
- N_("terminate entries with NUL byte"), 0),
+ OPT_BOOL('z', NULL, &null_termination,
+ N_("terminate entries with NUL byte")),
OPT_CMDMODE('l', "long", &cmdmode, N_("include object size"),
MODE_LONG),
OPT_CMDMODE(0, "name-only", &cmdmode, N_("list only filenames"),
@@ -349,29 +387,32 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
MODE_NAME_STATUS),
OPT_CMDMODE(0, "object-only", &cmdmode, N_("list only objects"),
MODE_OBJECT_ONLY),
- OPT_SET_INT(0, "full-name", &chomp_prefix,
+ OPT_SET_INT(0, "full-name", &options.chomp_prefix,
N_("use full path names"), 0),
OPT_BOOL(0, "full-tree", &full_tree,
N_("list entire tree; not just current directory "
"(implies --full-name)")),
- OPT_STRING_F(0, "format", &format, N_("format"),
+ OPT_STRING_F(0, "format", &options.format, N_("format"),
N_("format to use for the output"),
PARSE_OPT_NONEG),
- OPT__ABBREV(&abbrev),
+ OPT__ABBREV(&options.abbrev),
OPT_END()
};
struct ls_tree_cmdmode_to_fmt *m2f = ls_tree_cmdmode_format;
+ int ret;
git_config(git_default_config, NULL);
- ls_tree_prefix = prefix;
+ options.ls_tree_prefix = prefix;
if (prefix)
- chomp_prefix = strlen(prefix);
+ options.chomp_prefix = strlen(prefix);
argc = parse_options(argc, argv, prefix, ls_tree_options,
ls_tree_usage, 0);
+ options.null_termination = null_termination;
+
if (full_tree) {
- ls_tree_prefix = prefix = NULL;
- chomp_prefix = 0;
+ options.ls_tree_prefix = prefix = NULL;
+ options.chomp_prefix = 0;
}
/*
* We wanted to detect conflicts between --name-only and
@@ -383,10 +424,10 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
/* -d -r should imply -t, but -d by itself should not have to. */
if ( (LS_TREE_ONLY|LS_RECURSIVE) ==
- ((LS_TREE_ONLY|LS_RECURSIVE) & ls_options))
- ls_options |= LS_SHOW_TREES;
+ ((LS_TREE_ONLY|LS_RECURSIVE) & options.ls_options))
+ options.ls_options |= LS_SHOW_TREES;
- if (format && cmdmode)
+ if (options.format && cmdmode)
usage_msg_opt(
_("--format can't be combined with other format-altering options"),
ls_tree_usage, ls_tree_options);
@@ -401,13 +442,13 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
* cannot be lifted until it is converted to use
* match_pathspec() or tree_entry_interesting()
*/
- parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC &
- ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
+ parse_pathspec(&options.pathspec, PATHSPEC_ALL_MAGIC &
+ ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
PATHSPEC_PREFER_CWD,
prefix, argv + 1);
- for (i = 0; i < pathspec.nr; i++)
- pathspec.items[i].nowildcard_len = pathspec.items[i].len;
- pathspec.has_wildcard = 0;
+ for (i = 0; i < options.pathspec.nr; i++)
+ options.pathspec.items[i].nowildcard_len = options.pathspec.items[i].len;
+ options.pathspec.has_wildcard = 0;
tree = parse_tree_indirect(&oid);
if (!tree)
die("not a tree object");
@@ -417,11 +458,11 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
*/
while (m2f) {
if (!m2f->fmt) {
- fn = format ? show_tree_fmt : show_tree_default;
- } else if (format && !strcmp(format, m2f->fmt)) {
+ fn = options.format ? show_tree_fmt : show_tree_default;
+ } else if (options.format && !strcmp(options.format, m2f->fmt)) {
cmdmode = m2f->mode;
fn = m2f->fn;
- } else if (!format && cmdmode == m2f->mode) {
+ } else if (!options.format && cmdmode == m2f->mode) {
fn = m2f->fn;
} else {
m2f++;
@@ -430,5 +471,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
break;
}
- return !!read_tree(the_repository, tree, &pathspec, fn, NULL);
+ ret = !!read_tree(the_repository, tree, &options.pathspec, fn, &options);
+ clear_pathspec(&options.pathspec);
+ return ret;
}
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index ae2c011..828dc81 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -3,6 +3,7 @@
#include "tree-walk.h"
#include "xdiff-interface.h"
#include "help.h"
+#include "commit.h"
#include "commit-reach.h"
#include "merge-ort.h"
#include "object-store.h"
@@ -406,6 +407,7 @@ struct merge_tree_options {
};
static int real_merge(struct merge_tree_options *o,
+ const char *merge_base,
const char *branch1, const char *branch2,
const char *prefix)
{
@@ -432,16 +434,31 @@ static int real_merge(struct merge_tree_options *o,
opt.branch1 = branch1;
opt.branch2 = branch2;
- /*
- * Get the merge bases, in reverse order; see comment above
- * merge_incore_recursive in merge-ort.h
- */
- merge_bases = get_merge_bases(parent1, parent2);
- if (!merge_bases && !o->allow_unrelated_histories)
- die(_("refusing to merge unrelated histories"));
- merge_bases = reverse_commit_list(merge_bases);
+ if (merge_base) {
+ struct commit *base_commit;
+ struct tree *base_tree, *parent1_tree, *parent2_tree;
- merge_incore_recursive(&opt, merge_bases, parent1, parent2, &result);
+ base_commit = lookup_commit_reference_by_name(merge_base);
+ if (!base_commit)
+ die(_("could not lookup commit %s"), merge_base);
+
+ opt.ancestor = merge_base;
+ base_tree = get_commit_tree(base_commit);
+ parent1_tree = get_commit_tree(parent1);
+ parent2_tree = get_commit_tree(parent2);
+ merge_incore_nonrecursive(&opt, base_tree, parent1_tree, parent2_tree, &result);
+ } else {
+ /*
+ * Get the merge bases, in reverse order; see comment above
+ * merge_incore_recursive in merge-ort.h
+ */
+ merge_bases = get_merge_bases(parent1, parent2);
+ if (!merge_bases && !o->allow_unrelated_histories)
+ die(_("refusing to merge unrelated histories"));
+ merge_bases = reverse_commit_list(merge_bases);
+ merge_incore_recursive(&opt, merge_bases, parent1, parent2, &result);
+ }
+
if (result.clean < 0)
die(_("failure to merge"));
@@ -487,6 +504,7 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
struct merge_tree_options o = { .show_messages = -1 };
int expected_remaining_argc;
int original_argc;
+ const char *merge_base = NULL;
const char * const merge_tree_usage[] = {
N_("git merge-tree [--write-tree] [<options>] <branch1> <branch2>"),
@@ -515,6 +533,10 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
&o.use_stdin,
N_("perform multiple merges, one per line of input"),
PARSE_OPT_NONEG),
+ OPT_STRING(0, "merge-base",
+ &merge_base,
+ N_("commit"),
+ N_("specify a merge-base for the merge")),
OPT_END()
};
@@ -529,16 +551,35 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
if (o.mode == MODE_TRIVIAL)
die(_("--trivial-merge is incompatible with all other options"));
+ if (merge_base)
+ die(_("--merge-base is incompatible with --stdin"));
line_termination = '\0';
while (strbuf_getline_lf(&buf, stdin) != EOF) {
struct strbuf **split;
int result;
+ const char *input_merge_base = NULL;
split = strbuf_split(&buf, ' ');
- if (!split[0] || !split[1] || split[2])
+ if (!split[0] || !split[1])
die(_("malformed input line: '%s'."), buf.buf);
strbuf_rtrim(split[0]);
- result = real_merge(&o, split[0]->buf, split[1]->buf, prefix);
+ strbuf_rtrim(split[1]);
+
+ /* parse the merge-base */
+ if (!strcmp(split[1]->buf, "--")) {
+ input_merge_base = split[0]->buf;
+ }
+
+ if (input_merge_base && split[2] && split[3] && !split[4]) {
+ strbuf_rtrim(split[2]);
+ strbuf_rtrim(split[3]);
+ result = real_merge(&o, input_merge_base, split[2]->buf, split[3]->buf, prefix);
+ } else if (!input_merge_base && !split[2]) {
+ result = real_merge(&o, NULL, split[0]->buf, split[1]->buf, prefix);
+ } else {
+ die(_("malformed input line: '%s'."), buf.buf);
+ }
+
if (result < 0)
die(_("merging cannot continue; got unclean result of %d"), result);
strbuf_list_free(split);
@@ -581,7 +622,7 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
/* Do the relevant type of merge */
if (o.mode == MODE_REAL)
- return real_merge(&o, argv[0], argv[1], prefix);
+ return real_merge(&o, merge_base, argv[0], argv[1], prefix);
else
return trivial_merge(argv[0], argv[1], argv[2]);
}
diff --git a/builtin/merge.c b/builtin/merge.c
index 17b41fb..0a3c10a 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -6,7 +6,7 @@
* Based on git-merge.sh by Junio C Hamano.
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "cache.h"
#include "config.h"
#include "parse-options.h"
@@ -188,7 +188,7 @@ static struct strategy *get_strategy(const char *name)
for (i = 0; i < main_cmds.cnt; i++) {
int j, found = 0;
struct cmdname *ent = main_cmds.names[i];
- for (j = 0; j < ARRAY_SIZE(all_strategy); j++)
+ for (j = 0; !found && j < ARRAY_SIZE(all_strategy); j++)
if (!strncmp(ent->name, all_strategy[j].name, ent->len)
&& !all_strategy[j].name[ent->len])
found = 1;
@@ -390,8 +390,8 @@ static void restore_state(const struct object_id *head,
run_command(&cmd);
refresh_cache:
- discard_cache();
- if (read_cache() < 0)
+ discard_index(&the_index);
+ if (repo_read_index(the_repository) < 0)
die(_("could not read index"));
}
@@ -706,7 +706,7 @@ static int read_tree_trivial(struct object_id *common, struct object_id *head,
static void write_tree_trivial(struct object_id *oid)
{
- if (write_cache_as_tree(oid, 0, NULL))
+ if (write_index_as_tree(oid, &the_index, get_index_file(), 0, NULL))
die(_("git write-tree failed to write a tree"));
}
@@ -1560,7 +1560,9 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
!common->next &&
oideq(&common->item->object.oid, &head_commit->object.oid)) {
/* Again the most common case of merging one remote. */
- struct strbuf msg = STRBUF_INIT;
+ const char *msg = have_message ?
+ "Fast-forward (no commit created; -m option ignored)" :
+ "Fast-forward";
struct commit *commit;
if (verbosity >= 0) {
@@ -1570,10 +1572,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
find_unique_abbrev(&remoteheads->item->object.oid,
DEFAULT_ABBREV));
}
- strbuf_addstr(&msg, "Fast-forward");
- if (have_message)
- strbuf_addstr(&msg,
- " (no commit created; -m option ignored)");
commit = remoteheads->item;
if (!commit) {
ret = 1;
@@ -1592,9 +1590,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
goto done;
}
- finish(head_commit, remoteheads, &commit->object.oid, msg.buf);
+ finish(head_commit, remoteheads, &commit->object.oid, msg);
remove_merge_branch_state(the_repository);
- strbuf_release(&msg);
goto done;
} else if (!remoteheads->next && common->next)
;
@@ -1621,7 +1618,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
error(_("Your local changes to the following files would be overwritten by merge:\n %s"),
sb.buf);
strbuf_release(&sb);
- return 2;
+ ret = 2;
+ goto done;
}
/* See if it is really trivial. */
@@ -1789,5 +1787,6 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
}
strbuf_release(&buf);
free(branch_to_free);
+ discard_index(&the_index);
return ret;
}
diff --git a/builtin/mv.c b/builtin/mv.c
index 19790ce..edd7b93 100644
--- a/builtin/mv.c
+++ b/builtin/mv.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2006 Johannes Schindelin
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "config.h"
#include "pathspec.h"
@@ -489,7 +489,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
if ((mode & SPARSE) &&
path_in_sparse_checkout(dst, &the_index)) {
/* from out-of-cone to in-cone */
- int dst_pos = cache_name_pos(dst, strlen(dst));
+ int dst_pos = index_name_pos(&the_index, dst,
+ strlen(dst));
struct cache_entry *dst_ce = the_index.cache[dst_pos];
dst_ce->ce_flags &= ~CE_SKIP_WORKTREE;
@@ -500,7 +501,8 @@ int cmd_mv(int argc, const char **argv, const char *prefix)
!(mode & SPARSE) &&
!path_in_sparse_checkout(dst, &the_index)) {
/* from in-cone to out-of-cone */
- int dst_pos = cache_name_pos(dst, strlen(dst));
+ int dst_pos = index_name_pos(&the_index, dst,
+ strlen(dst));
struct cache_entry *dst_ce = the_index.cache[dst_pos];
/*
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 15535e9..97959bf 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -108,19 +108,11 @@ static int is_better_name(struct rev_name *name,
int name_distance = effective_distance(name->distance, name->generation);
int new_distance = effective_distance(distance, generation);
- /*
- * When comparing names based on tags, prefer names
- * based on the older tag, even if it is farther away.
- */
+ /* If both are tags, we prefer the nearer one. */
if (from_tag && name->from_tag)
- return (name->taggerdate > taggerdate ||
- (name->taggerdate == taggerdate &&
- name_distance > new_distance));
+ return name_distance > new_distance;
- /*
- * We know that at least one of them is a non-tag at this point.
- * favor a tag over a non-tag.
- */
+ /* Favor a tag over a non-tag. */
if (name->from_tag != from_tag)
return from_tag;
@@ -273,17 +265,6 @@ static int subpath_matches(const char *path, const char *filter)
return -1;
}
-static const char *name_ref_abbrev(const char *refname, int shorten_unambiguous)
-{
- if (shorten_unambiguous)
- refname = shorten_unambiguous_ref(refname, 0);
- else if (skip_prefix(refname, "refs/heads/", &refname))
- ; /* refname already advanced */
- else
- skip_prefix(refname, "refs/", &refname);
- return refname;
-}
-
struct name_ref_data {
int tags_only;
int name_only;
@@ -309,11 +290,19 @@ static void add_to_tip_table(const struct object_id *oid, const char *refname,
int shorten_unambiguous, struct commit *commit,
timestamp_t taggerdate, int from_tag, int deref)
{
- refname = name_ref_abbrev(refname, shorten_unambiguous);
+ char *short_refname = NULL;
+
+ if (shorten_unambiguous)
+ short_refname = shorten_unambiguous_ref(refname, 0);
+ else if (skip_prefix(refname, "refs/heads/", &refname))
+ ; /* refname already advanced */
+ else
+ skip_prefix(refname, "refs/", &refname);
ALLOC_GROW(tip_table.table, tip_table.nr + 1, tip_table.alloc);
oidcpy(&tip_table.table[tip_table.nr].oid, oid);
- tip_table.table[tip_table.nr].refname = xstrdup(refname);
+ tip_table.table[tip_table.nr].refname = short_refname ?
+ short_refname : xstrdup(refname);
tip_table.table[tip_table.nr].commit = commit;
tip_table.table[tip_table.nr].taggerdate = taggerdate;
tip_table.table[tip_table.nr].from_tag = from_tag;
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 573d0b2..74a167a 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -929,8 +929,10 @@ static struct object_entry **compute_write_order(void)
*/
for_each_tag_ref(mark_tagged, NULL);
- if (use_delta_islands)
+ if (use_delta_islands) {
max_layers = compute_pack_layers(&to_pack);
+ free_island_marks();
+ }
ALLOC_ARRAY(wo, to_pack.nr_objects);
wo_end = 0;
@@ -1318,7 +1320,7 @@ static int no_try_delta(const char *path)
if (!check)
check = attr_check_initl("delta", NULL);
- git_check_attr(the_repository->index, path, check);
+ git_check_attr(the_repository->index, NULL, path, check);
if (ATTR_FALSE(check->items[0].value))
return 1;
return 0;
@@ -1708,17 +1710,14 @@ static void pbase_tree_put(struct pbase_tree_cache *cache)
free(cache);
}
-static int name_cmp_len(const char *name)
+static size_t name_cmp_len(const char *name)
{
- int i;
- for (i = 0; name[i] && name[i] != '\n' && name[i] != '/'; i++)
- ;
- return i;
+ return strcspn(name, "\n/");
}
static void add_pbase_object(struct tree_desc *tree,
const char *name,
- int cmplen,
+ size_t cmplen,
const char *fullname)
{
struct name_entry entry;
@@ -1743,7 +1742,7 @@ static void add_pbase_object(struct tree_desc *tree,
struct tree_desc sub;
struct pbase_tree_cache *tree;
const char *down = name+cmplen+1;
- int downlen = name_cmp_len(down);
+ size_t downlen = name_cmp_len(down);
tree = pbase_tree_get(&entry.oid);
if (!tree)
@@ -1795,7 +1794,7 @@ static int check_pbase_path(unsigned hash)
static void add_preferred_base_object(const char *name)
{
struct pbase_tree *it;
- int cmplen;
+ size_t cmplen;
unsigned hash = pack_name_hash(name);
if (!num_preferred_base || check_pbase_path(hash))
@@ -4149,21 +4148,6 @@ static int option_parse_cruft_expiration(const struct option *opt,
return 0;
}
-struct po_filter_data {
- unsigned have_revs:1;
- struct rev_info revs;
-};
-
-static struct list_objects_filter_options *po_filter_revs_init(void *value)
-{
- struct po_filter_data *data = value;
-
- repo_init_revisions(the_repository, &data->revs, NULL);
- data->have_revs = 1;
-
- return &data->revs.filter;
-}
-
int cmd_pack_objects(int argc, const char **argv, const char *prefix)
{
int use_internal_rev_list = 0;
@@ -4174,7 +4158,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
int rev_list_index = 0;
int stdin_packs = 0;
struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
- struct po_filter_data pfd = { .have_revs = 0 };
+ struct list_objects_filter_options filter_options =
+ LIST_OBJECTS_FILTER_INIT;
struct option pack_objects_options[] = {
OPT_SET_INT('q', "quiet", &progress,
@@ -4265,7 +4250,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
&write_bitmap_index,
N_("write a bitmap index if possible"),
WRITE_BITMAP_QUIET, PARSE_OPT_HIDDEN),
- OPT_PARSE_LIST_OBJECTS_FILTER_INIT(&pfd, po_filter_revs_init),
+ OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
OPT_CALLBACK_F(0, "missing", NULL, N_("action"),
N_("handling for missing objects"), PARSE_OPT_NONEG,
option_parse_missing_action),
@@ -4385,7 +4370,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (!rev_list_all || !rev_list_reflog || !rev_list_index)
unpack_unreachable_expiration = 0;
- if (pfd.have_revs && pfd.revs.filter.choice) {
+ if (filter_options.choice) {
if (!pack_to_stdout)
die(_("cannot use --filter without --stdout"));
if (stdin_packs)
@@ -4472,13 +4457,11 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
read_cruft_objects();
} else if (!use_internal_rev_list) {
read_object_list_from_stdin();
- } else if (pfd.have_revs) {
- get_object_list(&pfd.revs, rp.nr, rp.v);
- release_revisions(&pfd.revs);
} else {
struct rev_info revs;
repo_init_revisions(the_repository, &revs, NULL);
+ list_objects_filter_copy(&revs.filter, &filter_options);
get_object_list(&revs, rp.nr, rp.v);
release_revisions(&revs);
}
@@ -4513,6 +4496,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
reuse_packfile_objects);
cleanup:
+ list_objects_filter_release(&filter_options);
strvec_clear(&rp);
return 0;
diff --git a/builtin/push.c b/builtin/push.c
index 60ac801..8f7d326 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -63,16 +63,9 @@ static struct refspec rs = REFSPEC_INIT_PUSH;
static struct string_list push_options_config = STRING_LIST_INIT_DUP;
static void refspec_append_mapped(struct refspec *refspec, const char *ref,
- struct remote *remote, struct ref *local_refs)
+ struct remote *remote, struct ref *matched)
{
const char *branch_name;
- struct ref *matched = NULL;
-
- /* Does "ref" uniquely name our ref? */
- if (count_refspec_match(ref, local_refs, &matched) != 1) {
- refspec_append(refspec, ref);
- return;
- }
if (remote->push.nr) {
struct refspec_item query;
@@ -120,15 +113,28 @@ static void set_refspecs(const char **refs, int nr, const char *repo)
die(_("--delete only accepts plain target ref names"));
refspec_appendf(&rs, ":%s", ref);
} else if (!strchr(ref, ':')) {
- if (!remote) {
- /* lazily grab remote and local_refs */
- remote = remote_get(repo);
+ struct ref *matched = NULL;
+
+ /* lazily grab local_refs */
+ if (!local_refs)
local_refs = get_local_heads();
+
+ /* Does "ref" uniquely name our ref? */
+ if (count_refspec_match(ref, local_refs, &matched) != 1) {
+ refspec_append(&rs, ref);
+ } else {
+ /* lazily grab remote */
+ if (!remote)
+ remote = remote_get(repo);
+ if (!remote)
+ BUG("must get a remote for repo '%s'", repo);
+
+ refspec_append_mapped(&rs, ref, remote, matched);
}
- refspec_append_mapped(&rs, ref, remote, local_refs);
} else
refspec_append(&rs, ref);
}
+ free_refs(local_refs);
}
static int push_url_of_remote(struct remote *remote, const char ***url_p)
diff --git a/builtin/range-diff.c b/builtin/range-diff.c
index e2a74ef..aecfae1 100644
--- a/builtin/range-diff.c
+++ b/builtin/range-diff.c
@@ -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);
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index f702f9d..3ce7541 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -114,6 +114,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
int prefix_set = 0;
struct lock_file lock_file = LOCK_INIT;
const struct option read_tree_options[] = {
+ OPT__SUPER_PREFIX(&opts.super_prefix),
OPT_CALLBACK_F(0, "index-output", NULL, N_("file"),
N_("write resulting index to <file>"),
PARSE_OPT_NONEG, index_output_cb),
diff --git a/builtin/rebase.c b/builtin/rebase.c
index b22768c..6635f10 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -113,7 +113,7 @@ struct rebase_options {
int autostash;
int committer_date_is_author_date;
int ignore_date;
- char *cmd;
+ struct string_list exec;
int allow_empty_message;
int rebase_merges, rebase_cousins;
char *strategy, *strategy_opts;
@@ -122,6 +122,8 @@ struct rebase_options {
int reapply_cherry_picks;
int fork_point;
int update_refs;
+ int config_autosquash;
+ int config_update_refs;
};
#define REBASE_OPTIONS_INIT { \
@@ -131,8 +133,15 @@ struct rebase_options {
.default_backend = "merge", \
.flags = REBASE_NO_QUIET, \
.git_am_opts = STRVEC_INIT, \
+ .exec = STRING_LIST_INIT_NODUP, \
.git_format_patch_opt = STRBUF_INIT, \
.fork_point = -1, \
+ .reapply_cherry_picks = -1, \
+ .allow_empty_message = 1, \
+ .autosquash = -1, \
+ .config_autosquash = -1, \
+ .update_refs = -1, \
+ .config_update_refs = -1, \
}
static struct replay_opts get_replay_opts(const struct rebase_options *opts)
@@ -243,38 +252,22 @@ static int init_basic_state(struct replay_opts *opts, const char *head_name,
return write_basic_state(opts, head_name, onto, orig_head);
}
-static void split_exec_commands(const char *cmd, struct string_list *commands)
-{
- if (cmd && *cmd) {
- string_list_split(commands, cmd, '\n', -1);
-
- /* rebase.c adds a new line to cmd after every command,
- * so here the last command is always empty */
- string_list_remove_empty_items(commands, 0);
- }
-}
-
static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
{
- int ret;
+ int ret = -1;
char *revisions = NULL, *shortrevisions = NULL;
struct strvec make_script_args = STRVEC_INIT;
struct todo_list todo_list = TODO_LIST_INIT;
struct replay_opts replay = get_replay_opts(opts);
- struct string_list commands = STRING_LIST_INIT_DUP;
if (get_revision_ranges(opts->upstream, opts->onto, &opts->orig_head->object.oid,
&revisions, &shortrevisions))
- return -1;
+ goto cleanup;
if (init_basic_state(&replay,
opts->head_name ? opts->head_name : "detached HEAD",
- opts->onto, &opts->orig_head->object.oid)) {
- free(revisions);
- free(shortrevisions);
-
- return -1;
- }
+ opts->onto, &opts->orig_head->object.oid))
+ goto cleanup;
if (!opts->upstream && opts->squash_onto)
write_file(path_squash_onto(), "%s\n",
@@ -297,14 +290,14 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
&todo_list))
BUG("unusable todo list");
- split_exec_commands(opts->cmd, &commands);
ret = complete_action(the_repository, &replay, flags,
shortrevisions, opts->onto_name, opts->onto,
- &opts->orig_head->object.oid, &commands,
+ &opts->orig_head->object.oid, &opts->exec,
opts->autosquash, opts->update_refs, &todo_list);
}
- string_list_clear(&commands, 0);
+cleanup:
+ replay_opts_release(&replay);
free(revisions);
free(shortrevisions);
todo_list_release(&todo_list);
@@ -346,6 +339,7 @@ static int run_sequencer_rebase(struct rebase_options *opts)
struct replay_opts replay_opts = get_replay_opts(opts);
ret = sequencer_continue(the_repository, &replay_opts);
+ replay_opts_release(&replay_opts);
break;
}
case ACTION_EDIT_TODO:
@@ -561,6 +555,7 @@ static int finish_rebase(struct rebase_options *opts)
replay.action = REPLAY_INTERACTIVE_REBASE;
ret = sequencer_remove_state(&replay);
+ replay_opts_release(&replay);
} else {
strbuf_addstr(&dir, opts->state_dir);
if (remove_dir_recursively(&dir, 0))
@@ -789,7 +784,7 @@ static int rebase_config(const char *var, const char *value, void *data)
}
if (!strcmp(var, "rebase.autosquash")) {
- opts->autosquash = git_config_bool(var, value);
+ opts->config_autosquash = git_config_bool(var, value);
return 0;
}
@@ -806,7 +801,7 @@ static int rebase_config(const char *var, const char *value, void *data)
}
if (!strcmp(var, "rebase.updaterefs")) {
- opts->update_refs = git_config_bool(var, value);
+ opts->config_update_refs = git_config_bool(var, value);
return 0;
}
@@ -920,6 +915,9 @@ static int parse_opt_am(const struct option *opt, const char *arg, int unset)
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
+ if (opts->type != REBASE_UNSPECIFIED && opts->type != REBASE_APPLY)
+ die(_("apply options and merge options cannot be used together"));
+
opts->type = REBASE_APPLY;
return 0;
@@ -933,8 +931,10 @@ static int parse_opt_merge(const struct option *opt, const char *arg, int unset)
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
- if (!is_merge(opts))
- opts->type = REBASE_MERGE;
+ if (opts->type != REBASE_UNSPECIFIED && opts->type != REBASE_MERGE)
+ die(_("apply options and merge options cannot be used together"));
+
+ opts->type = REBASE_MERGE;
return 0;
}
@@ -948,6 +948,9 @@ static int parse_opt_interactive(const struct option *opt, const char *arg,
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
+ if (opts->type != REBASE_UNSPECIFIED && opts->type != REBASE_MERGE)
+ die(_("apply options and merge options cannot be used together"));
+
opts->type = REBASE_MERGE;
opts->flags |= REBASE_INTERACTIVE_EXPLICIT;
@@ -1032,11 +1035,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
struct object_id branch_base;
int ignore_whitespace = 0;
const char *gpg_sign = NULL;
- struct string_list exec = STRING_LIST_INIT_NODUP;
const char *rebase_merges = NULL;
struct string_list strategy_options = STRING_LIST_INIT_NODUP;
struct object_id squash_onto;
char *squash_onto_name = NULL;
+ char *keep_base_onto_name = NULL;
int reschedule_failed_exec = -1;
int allow_preemptive_ff = 1;
int preserve_merges_selected = 0;
@@ -1127,7 +1130,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
N_("GPG-sign commits"),
PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
OPT_AUTOSTASH(&options.autostash),
- OPT_STRING_LIST('x', "exec", &exec, N_("exec"),
+ OPT_STRING_LIST('x', "exec", &options.exec, N_("exec"),
N_("add exec lines after each commit of the "
"editable list")),
OPT_BOOL_F(0, "allow-empty-message",
@@ -1164,8 +1167,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
- options.reapply_cherry_picks = -1;
- options.allow_empty_message = 1;
git_config(rebase_config, &options);
/* options.gpg_sign_opt will be either "-S" or NULL */
gpg_sign = options.gpg_sign_opt ? "" : NULL;
@@ -1230,13 +1231,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (options.fork_point < 0)
options.fork_point = 0;
}
- /*
- * --keep-base defaults to --reapply-cherry-picks to avoid losing
- * commits when using this option.
- */
- if (options.reapply_cherry_picks < 0)
- options.reapply_cherry_picks = keep_base;
-
if (options.root && options.fork_point > 0)
die(_("options '%s' and '%s' cannot be used together"), "--root", "--fork-point");
@@ -1250,7 +1244,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (trace2_is_enabled()) {
if (is_merge(&options))
trace2_cmd_mode("interactive");
- else if (exec.nr)
+ else if (options.exec.nr)
trace2_cmd_mode("interactive-exec");
else
trace2_cmd_mode(action_names[options.action]);
@@ -1322,6 +1316,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (reset_head(the_repository, &ropts) < 0)
die(_("could not move back to %s"),
oid_to_hex(&options.orig_head->object.oid));
+ strbuf_release(&head_msg);
remove_branch_state(the_repository, 0);
ret = finish_rebase(&options);
goto cleanup;
@@ -1333,6 +1328,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
replay.action = REPLAY_INTERACTIVE_REBASE;
ret = sequencer_remove_state(&replay);
+ replay_opts_release(&replay);
} else {
strbuf_reset(&buf);
strbuf_addstr(&buf, options.state_dir);
@@ -1377,8 +1373,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if ((options.flags & REBASE_INTERACTIVE_EXPLICIT) ||
(options.action != ACTION_NONE) ||
- (exec.nr > 0) ||
- options.autosquash) {
+ (options.exec.nr > 0) ||
+ (options.autosquash == -1 && options.config_autosquash == 1) ||
+ options.autosquash == 1) {
allow_preemptive_ff = 0;
}
if (options.committer_date_is_author_date || options.ignore_date)
@@ -1401,8 +1398,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
}
}
- for (i = 0; i < exec.nr; i++)
- if (check_exec_cmd(exec.items[i].string))
+ for (i = 0; i < options.exec.nr; i++)
+ if (check_exec_cmd(options.exec.items[i].string))
exit(1);
if (!(options.flags & REBASE_NO_QUIET))
@@ -1411,27 +1408,34 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (options.empty != EMPTY_UNSPECIFIED)
imply_merge(&options, "--empty");
- /*
- * --keep-base implements --reapply-cherry-picks by altering upstream so
- * it works with both backends.
- */
- if (options.reapply_cherry_picks && !keep_base)
- imply_merge(&options, "--reapply-cherry-picks");
+ if (options.reapply_cherry_picks < 0)
+ /*
+ * We default to --no-reapply-cherry-picks unless
+ * --keep-base is given; when --keep-base is given, we want
+ * to default to --reapply-cherry-picks.
+ */
+ options.reapply_cherry_picks = keep_base;
+ else if (!keep_base)
+ /*
+ * The apply backend always searches for and drops cherry
+ * picks. This is often not wanted with --keep-base, so
+ * --keep-base allows --reapply-cherry-picks to be
+ * simulated by altering the upstream such that
+ * cherry-picks cannot be detected and thus all commits are
+ * reapplied. Thus, --[no-]reapply-cherry-picks is
+ * supported when --keep-base is specified, but not when
+ * --keep-base is left out.
+ */
+ imply_merge(&options, options.reapply_cherry_picks ?
+ "--reapply-cherry-picks" :
+ "--no-reapply-cherry-picks");
if (gpg_sign)
options.gpg_sign_opt = xstrfmt("-S%s", gpg_sign);
- if (exec.nr) {
- int i;
-
+ if (options.exec.nr)
imply_merge(&options, "--exec");
- strbuf_reset(&buf);
- for (i = 0; i < exec.nr; i++)
- strbuf_addf(&buf, "exec %s\n", exec.items[i].string);
- options.cmd = xstrdup(buf.buf);
- }
-
if (rebase_merges) {
if (!*rebase_merges)
; /* default mode; do nothing */
@@ -1504,15 +1508,29 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (strcmp(options.git_am_opts.v[i], "-q"))
break;
- if (i >= 0) {
+ if (i >= 0 || options.type == REBASE_APPLY) {
if (is_merge(&options))
die(_("apply options and merge options "
"cannot be used together"));
+ else if (options.autosquash == -1 && options.config_autosquash == 1)
+ die(_("apply options are incompatible with rebase.autosquash. Consider adding --no-autosquash"));
+ else if (options.update_refs == -1 && options.config_update_refs == 1)
+ die(_("apply options are incompatible with rebase.updateRefs. Consider adding --no-update-refs"));
else
options.type = REBASE_APPLY;
}
}
+ if (options.update_refs == 1)
+ imply_merge(&options, "--update-refs");
+ options.update_refs = (options.update_refs >= 0) ? options.update_refs :
+ ((options.config_update_refs >= 0) ? options.config_update_refs : 0);
+
+ if (options.autosquash == 1)
+ imply_merge(&options, "--autosquash");
+ options.autosquash = (options.autosquash >= 0) ? options.autosquash :
+ ((options.config_autosquash >= 0) ? options.config_autosquash : 0);
+
if (options.type == REBASE_UNSPECIFIED) {
if (!strcmp(options.default_backend, "merge"))
imply_merge(&options, "--merge");
@@ -1542,7 +1560,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (options.empty == EMPTY_UNSPECIFIED) {
if (options.flags & REBASE_INTERACTIVE_EXPLICIT)
options.empty = EMPTY_ASK;
- else if (exec.nr > 0)
+ else if (options.exec.nr > 0)
options.empty = EMPTY_KEEP;
else
options.empty = EMPTY_DROP;
@@ -1658,7 +1676,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
strbuf_addstr(&buf, options.upstream_name);
strbuf_addstr(&buf, "...");
strbuf_addstr(&buf, branch_name);
- options.onto_name = xstrdup(buf.buf);
+ options.onto_name = keep_base_onto_name = xstrdup(buf.buf);
} else if (!options.onto_name)
options.onto_name = options.upstream_name;
if (strstr(options.onto_name, "...")) {
@@ -1828,10 +1846,14 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
strbuf_release(&revisions);
free(options.reflog_action);
free(options.head_name);
+ strvec_clear(&options.git_am_opts);
free(options.gpg_sign_opt);
- free(options.cmd);
+ string_list_clear(&options.exec, 0);
free(options.strategy);
+ free(options.strategy_opts);
strbuf_release(&options.git_format_patch_opt);
free(squash_onto_name);
+ free(keep_base_onto_name);
+ string_list_clear(&strategy_options, 0);
return !!ret;
}
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index a90af30..cd5c7a2 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -2032,6 +2032,16 @@ static struct command **queue_command(struct command **tail,
return &cmd->next;
}
+static void free_commands(struct command *commands)
+{
+ while (commands) {
+ struct command *next = commands->next;
+
+ free(commands);
+ commands = next;
+ }
+}
+
static void queue_commands_from_cert(struct command **tail,
struct strbuf *push_cert)
{
@@ -2569,6 +2579,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
run_receive_hook(commands, "post-receive", 1,
&push_options);
run_update_post_hook(commands);
+ free_commands(commands);
string_list_clear(&push_options, 0);
if (auto_gc) {
struct child_process proc = CHILD_PROCESS_INIT;
diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c
index fd3538d..ee338bf 100644
--- a/builtin/remote-ext.c
+++ b/builtin/remote-ext.c
@@ -169,6 +169,8 @@ static int command_loop(const char *child)
while (1) {
size_t i;
+ const char *arg;
+
if (!fgets(buffer, MAXCOMMAND - 1, stdin)) {
if (ferror(stdin))
die("Command input error");
@@ -182,10 +184,10 @@ static int command_loop(const char *child)
if (!strcmp(buffer, "capabilities")) {
printf("*connect\n\n");
fflush(stdout);
- } else if (!strncmp(buffer, "connect ", 8)) {
+ } else if (skip_prefix(buffer, "connect ", &arg)) {
printf("\n");
fflush(stdout);
- return run_child(child, buffer + 8);
+ return run_child(child, arg);
} else {
fprintf(stderr, "Bad command");
return 1;
diff --git a/builtin/remote-fd.c b/builtin/remote-fd.c
index 91dfe07..b2a3980 100644
--- a/builtin/remote-fd.c
+++ b/builtin/remote-fd.c
@@ -40,7 +40,7 @@ static void command_loop(int input_fd, int output_fd)
if (!strcmp(buffer, "capabilities")) {
printf("*connect\n\n");
fflush(stdout);
- } else if (!strncmp(buffer, "connect ", 8)) {
+ } else if (starts_with(buffer, "connect ")) {
printf("\n");
fflush(stdout);
if (bidirectional_transfer_loop(input_fd,
diff --git a/builtin/repack.c b/builtin/repack.c
index 65eb1b8..f649379 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -948,7 +948,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
ret = start_command(&cmd);
if (ret)
- return ret;
+ goto cleanup;
if (geometry) {
FILE *in = xfdopen(cmd.in, "w");
@@ -973,10 +973,11 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
item = string_list_append(&names, line.buf);
item->util = populate_pack_exts(item->string);
}
+ strbuf_release(&line);
fclose(out);
ret = finish_command(&cmd);
if (ret)
- return ret;
+ goto cleanup;
if (!names.nr && !po_args.quiet)
printf_ln(_("Nothing new to pack."));
@@ -1006,7 +1007,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
&existing_nonkept_packs,
&existing_kept_packs);
if (ret)
- return ret;
+ goto cleanup;
if (delete_redundant && expire_to) {
/*
@@ -1038,7 +1039,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
&existing_nonkept_packs,
&existing_kept_packs);
if (ret)
- return ret;
+ goto cleanup;
}
}
@@ -1114,7 +1115,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
string_list_clear(&include, 0);
if (ret)
- return ret;
+ goto cleanup;
}
reprepare_packed_git(the_repository);
@@ -1171,11 +1172,11 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
write_midx_file(get_object_directory(), NULL, NULL, flags);
}
+cleanup:
string_list_clear(&names, 1);
string_list_clear(&existing_nonkept_packs, 0);
string_list_clear(&existing_kept_packs, 0);
clear_pack_geometry(geometry);
- strbuf_release(&line);
- return 0;
+ return ret;
}
diff --git a/builtin/reset.c b/builtin/reset.c
index d2e0185..0697fa8 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -26,6 +26,7 @@
#include "submodule.h"
#include "submodule-config.h"
#include "dir.h"
+#include "add-interactive.h"
#define REFRESH_INDEX_DELAY_WARNING_IN_MS (2 * 1000)
@@ -390,7 +391,9 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (reset_type != NONE)
die(_("options '%s' and '%s' cannot be used together"), "--patch", "--{hard,mixed,soft}");
trace2_cmd_mode("patch-interactive");
- return run_add_interactive(rev, "--patch=reset", &pathspec);
+ update_ref_status = !!run_add_p(the_repository, ADD_P_RESET, rev,
+ &pathspec);
+ goto cleanup;
}
/* git reset tree [--] paths... can be used to
@@ -439,8 +442,10 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
LOCK_DIE_ON_ERROR);
if (reset_type == MIXED) {
int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
- if (read_from_tree(&pathspec, &oid, intent_to_add))
- return 1;
+ if (read_from_tree(&pathspec, &oid, intent_to_add)) {
+ update_ref_status = 1;
+ goto cleanup;
+ }
the_index.updated_skipworktree = 1;
if (!no_refresh && get_git_work_tree()) {
uint64_t t_begin, t_delta_in_ms;
@@ -486,5 +491,9 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (!pathspec.nr)
remove_branch_state(the_repository, 0);
+ discard_index(&the_index);
+
+cleanup:
+ clear_pathspec(&pathspec);
return update_ref_status;
}
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 1c344d7..e67999e 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -530,6 +530,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
strbuf_addstr(&parsed, " --");
sq_quote_argv(&parsed, argv);
puts(parsed.buf);
+ strbuf_release(&parsed);
return 0;
}
diff --git a/builtin/revert.c b/builtin/revert.c
index 6a9b550..77d2035 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -221,6 +221,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
opts->strategy = xstrdup_or_null(opts->strategy);
if (!opts->strategy && getenv("GIT_TEST_MERGE_ALGORITHM"))
opts->strategy = xstrdup(getenv("GIT_TEST_MERGE_ALGORITHM"));
+ free(options);
if (cmd == 'q') {
int ret = sequencer_remove_state(opts);
@@ -247,9 +248,7 @@ int cmd_revert(int argc, const char **argv, const char *prefix)
res = run_sequencer(argc, argv, &opts);
if (res < 0)
die(_("revert failed"));
- if (opts.revs)
- release_revisions(opts.revs);
- free(opts.revs);
+ replay_opts_release(&opts);
return res;
}
@@ -263,5 +262,6 @@ int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
res = run_sequencer(argc, argv, &opts);
if (res < 0)
die(_("cherry-pick failed"));
+ replay_opts_release(&opts);
return res;
}
diff --git a/builtin/rm.c b/builtin/rm.c
index d4989d4..8844f90 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -3,7 +3,7 @@
*
* Copyright (C) Linus Torvalds 2006
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "advice.h"
#include "config.h"
@@ -86,7 +86,7 @@ static void submodules_absorb_gitdir_if_needed(void)
continue;
if (!submodule_uses_gitfile(name))
- absorb_git_dir_into_superproject(name);
+ absorb_git_dir_into_superproject(name, NULL);
}
}
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index c013aba..358ac3e 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -956,5 +956,6 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
if (shown_merge_point && --extra < 0)
break;
}
+ free(head);
return 0;
}
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 58a2250..c373815 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -217,6 +217,7 @@ static int update_working_directory(struct pattern_list *pl)
o.head_idx = -1;
o.src_index = r->index;
o.dst_index = r->index;
+ index_state_init(&o.result, r);
o.skip_sparse_checkout = 0;
o.pl = pl;
diff --git a/builtin/stash.c b/builtin/stash.c
index 62e3671..3a4f9fd 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -1,4 +1,4 @@
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "config.h"
#include "parse-options.h"
@@ -18,6 +18,7 @@
#include "diffcore.h"
#include "exec-cmd.h"
#include "reflog.h"
+#include "add-interactive.h"
#define INCLUDE_ALL_FILES 2
@@ -528,7 +529,8 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
NULL, NULL, NULL))
return -1;
- if (write_cache_as_tree(&c_tree, 0, NULL))
+ if (write_index_as_tree(&c_tree, &the_index, get_index_file(), 0,
+ NULL))
return error(_("cannot apply a stash in the middle of a merge"));
if (index) {
@@ -552,7 +554,8 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,
discard_index(&the_index);
repo_read_index(the_repository);
- if (write_cache_as_tree(&index_tree, 0, NULL))
+ if (write_index_as_tree(&index_tree, &the_index,
+ get_index_file(), 0, NULL))
return error(_("could not save index tree"));
reset_head();
@@ -1137,7 +1140,7 @@ static int save_untracked_files(struct stash_info *info, struct strbuf *msg,
int ret = 0;
struct strbuf untracked_msg = STRBUF_INIT;
struct child_process cp_upd_index = CHILD_PROCESS_INIT;
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT(the_repository);
cp_upd_index.git_cmd = 1;
strvec_pushl(&cp_upd_index.args, "update-index", "-z", "--add",
@@ -1165,7 +1168,7 @@ static int save_untracked_files(struct stash_info *info, struct strbuf *msg,
}
done:
- discard_index(&istate);
+ release_index(&istate);
strbuf_release(&untracked_msg);
remove_path(stash_index_path.buf);
return ret;
@@ -1176,7 +1179,7 @@ static int stash_staged(struct stash_info *info, struct strbuf *out_patch,
{
int ret = 0;
struct child_process cp_diff_tree = CHILD_PROCESS_INIT;
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT(the_repository);
if (write_index_as_tree(&info->w_tree, &istate, the_repository->index_file,
0, NULL)) {
@@ -1199,7 +1202,7 @@ static int stash_staged(struct stash_info *info, struct strbuf *out_patch,
}
done:
- discard_index(&istate);
+ release_index(&istate);
return ret;
}
@@ -1209,7 +1212,7 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps,
int ret = 0;
struct child_process cp_read_tree = CHILD_PROCESS_INIT;
struct child_process cp_diff_tree = CHILD_PROCESS_INIT;
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT(the_repository);
char *old_index_env = NULL, *old_repo_index_file;
remove_path(stash_index_path.buf);
@@ -1229,7 +1232,7 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps,
old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT));
setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1);
- ret = run_add_interactive(NULL, "--patch=stash", ps);
+ ret = !!run_add_p(the_repository, ADD_P_STASH, NULL, ps);
the_repository->index_file = old_repo_index_file;
if (old_index_env && *old_index_env)
@@ -1260,7 +1263,7 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps,
}
done:
- discard_index(&istate);
+ release_index(&istate);
remove_path(stash_index_path.buf);
return ret;
}
@@ -1271,7 +1274,7 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
struct rev_info rev;
struct child_process cp_upd_index = CHILD_PROCESS_INIT;
struct strbuf diff_output = STRBUF_INIT;
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT(the_repository);
init_revisions(&rev, NULL);
copy_pathspec(&rev.prune_data, ps);
@@ -1319,7 +1322,7 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
}
done:
- discard_index(&istate);
+ release_index(&istate);
release_revisions(&rev);
strbuf_release(&diff_output);
remove_path(stash_index_path.buf);
@@ -1377,7 +1380,8 @@ static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_b
strbuf_addf(&commit_tree_label, "index on %s\n", msg.buf);
commit_list_insert(head_commit, &parents);
- if (write_cache_as_tree(&info->i_tree, 0, NULL) ||
+ if (write_index_as_tree(&info->i_tree, &the_index, get_index_file(), 0,
+ NULL) ||
commit_tree(commit_tree_label.buf, commit_tree_label.len,
&info->i_tree, parents, &info->i_commit, NULL, NULL)) {
if (!quiet)
@@ -1689,8 +1693,10 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
}
done:
+ strbuf_release(&patch);
free_stash_info(&info);
strbuf_release(&stash_msg_buf);
+ strbuf_release(&untracked_files);
return ret;
}
@@ -1725,6 +1731,7 @@ static int push_stash(int argc, const char **argv, const char *prefix,
OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
OPT_END()
};
+ int ret;
if (argc) {
force_assume = !strcmp(argv[0], "-p");
@@ -1764,8 +1771,10 @@ static int push_stash(int argc, const char **argv, const char *prefix,
die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file");
}
- return do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode,
- include_untracked, only_staged);
+ ret = do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode,
+ include_untracked, only_staged);
+ clear_pathspec(&ps);
+ return ret;
}
static int push_stash_unassumed(int argc, const char **argv, const char *prefix)
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 941afe1..74a2375 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -113,10 +113,9 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int
}
/* the result should be freed by the caller. */
-static char *get_submodule_displaypath(const char *path, const char *prefix)
+static char *get_submodule_displaypath(const char *path, const char *prefix,
+ const char *super_prefix)
{
- const char *super_prefix = get_super_prefix();
-
if (prefix && super_prefix) {
BUG("cannot have prefix '%s' and superprefix '%s'",
prefix, super_prefix);
@@ -279,6 +278,7 @@ struct foreach_cb {
int argc;
const char **argv;
const char *prefix;
+ const char *super_prefix;
int quiet;
int recursive;
};
@@ -297,7 +297,8 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
if (validate_submodule_path(path) < 0)
exit(128);
- displaypath = get_submodule_displaypath(path, info->prefix);
+ displaypath = get_submodule_displaypath(path, info->prefix,
+ info->super_prefix);
sub = submodule_from_path(the_repository, null_oid(), path);
@@ -367,10 +368,10 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
cpr.dir = path;
prepare_submodule_repo_env(&cpr.env);
- strvec_pushl(&cpr.args, "--super-prefix", NULL);
- strvec_pushf(&cpr.args, "%s/", displaypath);
strvec_pushl(&cpr.args, "submodule--helper", "foreach", "--recursive",
NULL);
+ strvec_pushl(&cpr.args, "--super-prefix", NULL);
+ strvec_pushf(&cpr.args, "%s/", displaypath);
if (info->quiet)
strvec_push(&cpr.args, "--quiet");
@@ -394,6 +395,7 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
struct pathspec pathspec = { 0 };
struct module_list list = MODULE_LIST_INIT;
struct option module_foreach_options[] = {
+ OPT__SUPER_PREFIX(&info.super_prefix),
OPT__QUIET(&info.quiet, N_("suppress output of entering each submodule command")),
OPT_BOOL(0, "recursive", &info.recursive,
N_("recurse into nested submodules")),
@@ -438,11 +440,13 @@ static int starts_with_dot_dot_slash(const char *const path)
struct init_cb {
const char *prefix;
+ const char *super_prefix;
unsigned int flags;
};
#define INIT_CB_INIT { 0 }
static void init_submodule(const char *path, const char *prefix,
+ const char *super_prefix,
unsigned int flags)
{
const struct submodule *sub;
@@ -450,7 +454,7 @@ static void init_submodule(const char *path, const char *prefix,
const char *upd;
char *url = NULL, *displaypath;
- displaypath = get_submodule_displaypath(path, prefix);
+ displaypath = get_submodule_displaypath(path, prefix, super_prefix);
sub = submodule_from_path(the_repository, null_oid(), path);
@@ -526,7 +530,8 @@ static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data
{
struct init_cb *info = cb_data;
- init_submodule(list_item->name, info->prefix, info->flags);
+ init_submodule(list_item->name, info->prefix, info->super_prefix,
+ info->flags);
}
static int module_init(int argc, const char **argv, const char *prefix)
@@ -573,6 +578,7 @@ static int module_init(int argc, const char **argv, const char *prefix)
struct status_cb {
const char *prefix;
+ const char *super_prefix;
unsigned int flags;
};
#define STATUS_CB_INIT { 0 }
@@ -611,7 +617,7 @@ static int handle_submodule_head_ref(const char *refname UNUSED,
static void status_submodule(const char *path, const struct object_id *ce_oid,
unsigned int ce_flags, const char *prefix,
- unsigned int flags)
+ const char *super_prefix, unsigned int flags)
{
char *displaypath;
struct strvec diff_files_args = STRVEC_INIT;
@@ -630,7 +636,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
die(_("no submodule mapping found in .gitmodules for path '%s'"),
path);
- displaypath = get_submodule_displaypath(path, prefix);
+ displaypath = get_submodule_displaypath(path, prefix, super_prefix);
if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {
print_status(flags, 'U', path, null_oid(), displaypath);
@@ -688,10 +694,10 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
cpr.dir = path;
prepare_submodule_repo_env(&cpr.env);
- strvec_push(&cpr.args, "--super-prefix");
- strvec_pushf(&cpr.args, "%s/", displaypath);
strvec_pushl(&cpr.args, "submodule--helper", "status",
"--recursive", NULL);
+ strvec_push(&cpr.args, "--super-prefix");
+ strvec_pushf(&cpr.args, "%s/", displaypath);
if (flags & OPT_CACHED)
strvec_push(&cpr.args, "--cached");
@@ -715,7 +721,7 @@ static void status_submodule_cb(const struct cache_entry *list_item,
struct status_cb *info = cb_data;
status_submodule(list_item->name, &list_item->oid, list_item->ce_flags,
- info->prefix, info->flags);
+ info->prefix, info->super_prefix, info->flags);
}
static int module_status(int argc, const char **argv, const char *prefix)
@@ -725,6 +731,7 @@ static int module_status(int argc, const char **argv, const char *prefix)
struct module_list list = MODULE_LIST_INIT;
int quiet = 0;
struct option module_status_options[] = {
+ OPT__SUPER_PREFIX(&info.super_prefix),
OPT__QUIET(&quiet, N_("suppress submodule status output")),
OPT_BIT(0, "cached", &info.flags, N_("use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE),
@@ -793,6 +800,7 @@ struct summary_cb {
int argc;
const char **argv;
const char *prefix;
+ const char *super_prefix;
unsigned int cached: 1;
unsigned int for_status: 1;
unsigned int files: 1;
@@ -954,7 +962,8 @@ static void generate_submodule_summary(struct summary_cb *info,
dst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);
}
- displaypath = get_submodule_displaypath(p->sm_path, info->prefix);
+ displaypath = get_submodule_displaypath(p->sm_path, info->prefix,
+ info->super_prefix);
if (!missing_src && !missing_dst) {
struct child_process cp_rev_list = CHILD_PROCESS_INIT;
@@ -1209,12 +1218,13 @@ static int module_summary(int argc, const char **argv, const char *prefix)
struct sync_cb {
const char *prefix;
+ const char *super_prefix;
unsigned int flags;
};
#define SYNC_CB_INIT { 0 }
static void sync_submodule(const char *path, const char *prefix,
- unsigned int flags)
+ const char *super_prefix, unsigned int flags)
{
const struct submodule *sub;
char *remote_key = NULL;
@@ -1248,7 +1258,7 @@ static void sync_submodule(const char *path, const char *prefix,
super_config_url = xstrdup("");
}
- displaypath = get_submodule_displaypath(path, prefix);
+ displaypath = get_submodule_displaypath(path, prefix, super_prefix);
if (!(flags & OPT_QUIET))
printf(_("Synchronizing submodule url for '%s'\n"),
@@ -1285,10 +1295,11 @@ static void sync_submodule(const char *path, const char *prefix,
cpr.dir = path;
prepare_submodule_repo_env(&cpr.env);
- strvec_push(&cpr.args, "--super-prefix");
- strvec_pushf(&cpr.args, "%s/", displaypath);
strvec_pushl(&cpr.args, "submodule--helper", "sync",
"--recursive", NULL);
+ strvec_push(&cpr.args, "--super-prefix");
+ strvec_pushf(&cpr.args, "%s/", displaypath);
+
if (flags & OPT_QUIET)
strvec_push(&cpr.args, "--quiet");
@@ -1311,7 +1322,8 @@ static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data
{
struct sync_cb *info = cb_data;
- sync_submodule(list_item->name, info->prefix, info->flags);
+ sync_submodule(list_item->name, info->prefix, info->super_prefix,
+ info->flags);
}
static int module_sync(int argc, const char **argv, const char *prefix)
@@ -1322,6 +1334,7 @@ static int module_sync(int argc, const char **argv, const char *prefix)
int quiet = 0;
int recursive = 0;
struct option module_sync_options[] = {
+ OPT__SUPER_PREFIX(&info.super_prefix),
OPT__QUIET(&quiet, N_("suppress output of synchronizing submodule url")),
OPT_BOOL(0, "recursive", &recursive,
N_("recurse into nested submodules")),
@@ -1377,7 +1390,7 @@ static void deinit_submodule(const char *path, const char *prefix,
if (!sub || !sub->name)
goto cleanup;
- displaypath = get_submodule_displaypath(path, prefix);
+ displaypath = get_submodule_displaypath(path, prefix, NULL);
/* remove the submodule work tree (unless the user already did it) */
if (is_directory(path)) {
@@ -1391,7 +1404,7 @@ static void deinit_submodule(const char *path, const char *prefix,
".git file by using absorbgitdirs."),
displaypath);
- absorb_git_dir_into_superproject(path);
+ absorb_git_dir_into_superproject(path, NULL);
}
@@ -1950,6 +1963,7 @@ static void submodule_update_clone_release(struct submodule_update_clone *suc)
struct update_data {
const char *prefix;
+ const char *super_prefix;
char *displaypath;
enum submodule_update_type update_default;
struct object_id suboid;
@@ -2025,7 +2039,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
enum submodule_update_type update_type;
char *key;
const struct update_data *ud = suc->update_data;
- char *displaypath = get_submodule_displaypath(ce->name, ud->prefix);
+ char *displaypath = get_submodule_displaypath(ce->name, ud->prefix,
+ ud->super_prefix);
struct strbuf sb = STRBUF_INIT;
int needs_cloning = 0;
int need_free_url = 0;
@@ -2505,11 +2520,11 @@ static void update_data_to_args(const struct update_data *update_data,
{
enum submodule_update_type update_type = update_data->update_default;
+ strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
if (update_data->displaypath) {
strvec_push(args, "--super-prefix");
strvec_pushf(args, "%s/", update_data->displaypath);
}
- strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
strvec_pushf(args, "--jobs=%d", update_data->max_jobs);
if (update_data->quiet)
strvec_push(args, "--quiet");
@@ -2687,7 +2702,8 @@ static int update_submodules(struct update_data *update_data)
goto fail;
update_data->displaypath = get_submodule_displaypath(
- update_data->sm_path, update_data->prefix);
+ update_data->sm_path, update_data->prefix,
+ update_data->super_prefix);
code = update_submodule(update_data);
FREE_AND_NULL(update_data->displaypath);
fail:
@@ -2713,6 +2729,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
LIST_OBJECTS_FILTER_INIT;
int ret;
struct option module_update_options[] = {
+ OPT__SUPER_PREFIX(&opt.super_prefix),
OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
OPT_BOOL(0, "init", &opt.init,
N_("initialize uninitialized submodules before update")),
@@ -2809,6 +2826,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
module_list_active(&list);
info.prefix = opt.prefix;
+ info.super_prefix = opt.super_prefix;
if (opt.quiet)
info.flags |= OPT_QUIET;
@@ -2907,7 +2925,9 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
int i;
struct pathspec pathspec = { 0 };
struct module_list list = MODULE_LIST_INIT;
+ const char *super_prefix = NULL;
struct option embed_gitdir_options[] = {
+ OPT__SUPER_PREFIX(&super_prefix),
OPT_END()
};
const char *const git_submodule_helper_usage[] = {
@@ -2923,7 +2943,8 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
goto cleanup;
for (i = 0; i < list.nr; i++)
- absorb_git_dir_into_superproject(list.entries[i]->name);
+ absorb_git_dir_into_superproject(list.entries[i]->name,
+ super_prefix);
ret = 0;
cleanup:
@@ -2955,7 +2976,7 @@ static int module_set_url(int argc, const char **argv, const char *prefix)
config_name = xstrfmt("submodule.%s.url", path);
config_set_in_gitmodules_file_gently(config_name, newurl);
- sync_submodule(path, prefix, quiet ? OPT_QUIET : 0);
+ sync_submodule(path, prefix, NULL, quiet ? OPT_QUIET : 0);
free(config_name);
@@ -3277,9 +3298,8 @@ static void die_on_index_match(const char *path, int force)
ensure_full_index(&the_index);
/*
- * Since there is only one pathspec, we just need
- * need to check ps_matched[0] to know if a cache
- * entry matched.
+ * Since there is only one pathspec, we just need to
+ * check ps_matched[0] to know if a cache entry matched.
*/
for (i = 0; i < the_index.cache_nr; i++) {
ce_path_match(&the_index, the_index.cache[i], &ps,
@@ -3435,8 +3455,6 @@ static int module_add(int argc, const char **argv, const char *prefix)
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
{
- const char *cmd = argv[0];
- const char *subcmd;
parse_opt_subcommand_fn *fn = NULL;
const char *const usage[] = {
N_("git submodule--helper <command>"),
@@ -3460,18 +3478,6 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
OPT_END()
};
argc = parse_options(argc, argv, prefix, options, usage, 0);
- subcmd = argv[0];
-
- if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
- strcmp(subcmd, "foreach") && strcmp(subcmd, "status") &&
- strcmp(subcmd, "sync") && strcmp(subcmd, "absorbgitdirs") &&
- get_super_prefix())
- /*
- * xstrfmt() rather than "%s %s" to keep the translated
- * string identical to git.c's.
- */
- die(_("%s doesn't support --super-prefix"),
- xstrfmt("'%s %s'", cmd, subcmd));
return fn(argc, argv, prefix);
}
diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c
index 9e8119d..88de32b 100644
--- a/builtin/unpack-file.c
+++ b/builtin/unpack-file.c
@@ -19,6 +19,7 @@ static char *create_temp_file(struct object_id *oid)
if (write_in_full(fd, buf, size) < 0)
die_errno("unable to write temp-file");
close(fd);
+ free(buf);
return path;
}
diff --git a/builtin/update-index.c b/builtin/update-index.c
index 82d5902..bf38885 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -3,7 +3,7 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "cache.h"
#include "bulk-checkin.h"
#include "config.h"
@@ -381,7 +381,7 @@ static int process_path(const char *path, struct stat *st, int stat_errno)
if (has_symlink_leading_path(path, len))
return error("'%s' is beyond a symbolic link", path);
- pos = cache_name_pos(path, len);
+ pos = index_name_pos(&the_index, path, len);
ce = pos < 0 ? NULL : the_index.cache[pos];
if (ce && ce_skip_worktree(ce)) {
/*
diff --git a/builtin/var.c b/builtin/var.c
index 491db27..a80c1df 100644
--- a/builtin/var.c
+++ b/builtin/var.c
@@ -11,12 +11,12 @@ static const char var_usage[] = "git var (-l | <variable>)";
static const char *editor(int flag)
{
- const char *pgm = git_editor();
+ return git_editor();
+}
- if (!pgm && flag & IDENT_STRICT)
- die("Terminal is dumb, but EDITOR unset");
-
- return pgm;
+static const char *sequence_editor(int flag)
+{
+ return git_sequence_editor();
}
static const char *pager(int flag)
@@ -41,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 },
@@ -56,18 +57,15 @@ static void list_vars(void)
printf("%s=%s\n", ptr->name, val);
}
-static const char *read_var(const char *var)
+static const struct git_var *get_git_var(const char *var)
{
struct git_var *ptr;
- const char *val;
- val = NULL;
for (ptr = git_vars; ptr->read; ptr++) {
if (strcmp(var, ptr->name) == 0) {
- val = ptr->read(IDENT_STRICT);
- break;
+ return ptr;
}
}
- return val;
+ return NULL;
}
static int show_config(const char *var, const char *value, void *cb)
@@ -81,7 +79,9 @@ static int show_config(const char *var, const char *value, void *cb)
int cmd_var(int argc, const char **argv, const char *prefix)
{
- const char *val = NULL;
+ const struct git_var *git_var;
+ const char *val;
+
if (argc != 2)
usage(var_usage);
@@ -91,10 +91,15 @@ int cmd_var(int argc, const char **argv, const char *prefix)
return 0;
}
git_config(git_default_config, NULL);
- val = read_var(argv[1]);
- if (!val)
+
+ git_var = get_git_var(argv[1]);
+ if (!git_var)
usage(var_usage);
+ val = git_var->read(IDENT_STRICT);
+ if (!val)
+ return 1;
+
printf("%s\n", val);
return 0;
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 4a24d53..254283a 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -173,7 +173,7 @@ static void prune_worktrees(void)
{
struct strbuf reason = STRBUF_INIT;
struct strbuf main_path = STRBUF_INIT;
- struct string_list kept = STRING_LIST_INIT_NODUP;
+ struct string_list kept = STRING_LIST_INIT_DUP;
DIR *dir = opendir(git_path("worktrees"));
struct dirent *d;
if (!dir)
@@ -184,14 +184,14 @@ static void prune_worktrees(void)
if (should_prune_worktree(d->d_name, &reason, &path, expire))
prune_worktree(d->d_name, reason.buf);
else if (path)
- string_list_append(&kept, path)->util = xstrdup(d->d_name);
+ string_list_append_nodup(&kept, path)->util = xstrdup(d->d_name);
}
closedir(dir);
strbuf_add_absolute_path(&main_path, get_git_common_dir());
/* massage main worktree absolute path to match 'gitdir' content */
strbuf_strip_suffix(&main_path, "/.");
- string_list_append(&kept, strbuf_detach(&main_path, NULL));
+ string_list_append_nodup(&kept, strbuf_detach(&main_path, NULL));
prune_dups(&kept);
string_list_clear(&kept, 1);
@@ -629,6 +629,7 @@ static int add(int ac, const char **av, const char *prefix)
N_("try to match the new branch name with a remote-tracking branch")),
OPT_END()
};
+ int ret;
memset(&opts, 0, sizeof(opts));
opts.checkout = 1;
@@ -705,9 +706,9 @@ static int add(int ac, const char **av, const char *prefix)
die(_("--[no-]track can only be used if a new branch is created"));
}
- UNLEAK(path);
- UNLEAK(opts);
- return add_worktree(path, branch, &opts);
+ ret = add_worktree(path, branch, &opts);
+ free(path);
+ return ret;
}
static void show_worktree_porcelain(struct worktree *wt, int line_terminator)
@@ -922,7 +923,7 @@ static int unlock_worktree(int ac, const char **av, const char *prefix)
static void validate_no_submodules(const struct worktree *wt)
{
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT(the_repository);
struct strbuf path = STRBUF_INIT;
int i, found_submodules = 0;
diff --git a/builtin/write-tree.c b/builtin/write-tree.c
index 45d6170..0780103 100644
--- a/builtin/write-tree.c
+++ b/builtin/write-tree.c
@@ -3,7 +3,7 @@
*
* Copyright (C) Linus Torvalds, 2005
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "builtin.h"
#include "cache.h"
#include "config.h"
@@ -38,7 +38,8 @@ int cmd_write_tree(int argc, const char **argv, const char *cmd_prefix)
argc = parse_options(argc, argv, cmd_prefix, write_tree_options,
write_tree_usage, 0);
- ret = write_cache_as_tree(&oid, flags, tree_prefix);
+ ret = write_index_as_tree(&oid, &the_index, get_index_file(), flags,
+ tree_prefix);
switch (ret) {
case 0:
printf("%s\n", oid_to_hex(&oid));
diff --git a/bundle-uri.c b/bundle-uri.c
index 79a914f..8a3c39c 100644
--- a/bundle-uri.c
+++ b/bundle-uri.c
@@ -7,6 +7,15 @@
#include "hashmap.h"
#include "pkt-line.h"
#include "config.h"
+#include "remote.h"
+
+static struct {
+ enum bundle_list_heuristic heuristic;
+ const char *name;
+} heuristics[BUNDLE_HEURISTIC__COUNT] = {
+ { BUNDLE_HEURISTIC_NONE, ""},
+ { BUNDLE_HEURISTIC_CREATIONTOKEN, "creationToken" },
+};
static int compare_bundles(const void *hashmap_cmp_fn_data,
const struct hashmap_entry *he1,
@@ -49,6 +58,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,
@@ -73,6 +83,9 @@ static int summarize_bundle(struct remote_bundle_info *info, void *data)
FILE *fp = data;
fprintf(fp, "[bundle \"%s\"]\n", info->id);
fprintf(fp, "\turi = %s\n", info->uri);
+
+ if (info->creationToken)
+ fprintf(fp, "\tcreationToken = %"PRIu64"\n", info->creationToken);
return 0;
}
@@ -98,6 +111,17 @@ void print_bundle_list(FILE *fp, struct bundle_list *list)
fprintf(fp, "\tversion = %d\n", list->version);
fprintf(fp, "\tmode = %s\n", mode);
+ if (list->heuristic) {
+ int i;
+ for (i = 0; i < BUNDLE_HEURISTIC__COUNT; i++) {
+ if (heuristics[i].heuristic == list->heuristic) {
+ printf("\theuristic = %s\n",
+ heuristics[list->heuristic].name);
+ break;
+ }
+ }
+ }
+
for_all_bundles_in_list(list, summarize_bundle, fp);
}
@@ -140,6 +164,21 @@ static int bundle_list_update(const char *key, const char *value,
return 0;
}
+ if (!strcmp(subkey, "heuristic")) {
+ int i;
+ for (i = 0; i < BUNDLE_HEURISTIC__COUNT; i++) {
+ if (heuristics[i].heuristic &&
+ heuristics[i].name &&
+ !strcmp(value, heuristics[i].name)) {
+ list->heuristic = heuristics[i].heuristic;
+ return 0;
+ }
+ }
+
+ /* Ignore unknown heuristics. */
+ return 0;
+ }
+
/* Ignore other unknown global keys. */
return 0;
}
@@ -163,7 +202,14 @@ 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;
+ }
+
+ if (!strcmp(subkey, "creationtoken")) {
+ if (sscanf(value, "%"PRIu64, &bundle->creationToken) != 1)
+ warning(_("could not parse bundle list key %s with value '%s'"),
+ "creationToken", value);
return 0;
}
@@ -190,6 +236,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);
@@ -389,6 +447,183 @@ static int download_bundle_to_file(struct remote_bundle_info *bundle, void *data
return 0;
}
+struct bundles_for_sorting {
+ struct remote_bundle_info **items;
+ size_t alloc;
+ size_t nr;
+};
+
+static int append_bundle(struct remote_bundle_info *bundle, void *data)
+{
+ struct bundles_for_sorting *list = data;
+ list->items[list->nr++] = bundle;
+ return 0;
+}
+
+/**
+ * For use in QSORT() to get a list sorted by creationToken
+ * in decreasing order.
+ */
+static int compare_creation_token_decreasing(const void *va, const void *vb)
+{
+ const struct remote_bundle_info * const *a = va;
+ const struct remote_bundle_info * const *b = vb;
+
+ if ((*a)->creationToken > (*b)->creationToken)
+ return -1;
+ if ((*a)->creationToken < (*b)->creationToken)
+ return 1;
+ return 0;
+}
+
+static int fetch_bundles_by_token(struct repository *r,
+ struct bundle_list *list)
+{
+ int cur;
+ int move_direction = 0;
+ const char *creationTokenStr;
+ uint64_t maxCreationToken = 0, newMaxCreationToken = 0;
+ struct bundle_list_context ctx = {
+ .r = r,
+ .list = list,
+ .mode = list->mode,
+ };
+ struct bundles_for_sorting bundles = {
+ .alloc = hashmap_get_size(&list->bundles),
+ };
+
+ ALLOC_ARRAY(bundles.items, bundles.alloc);
+
+ for_all_bundles_in_list(list, append_bundle, &bundles);
+
+ if (!bundles.nr) {
+ free(bundles.items);
+ return 0;
+ }
+
+ QSORT(bundles.items, bundles.nr, compare_creation_token_decreasing);
+
+ /*
+ * If fetch.bundleCreationToken exists, parses to a uint64t, and
+ * is not strictly smaller than the maximum creation token in the
+ * bundle list, then do not download any bundles.
+ */
+ if (!repo_config_get_value(r,
+ "fetch.bundlecreationtoken",
+ &creationTokenStr) &&
+ sscanf(creationTokenStr, "%"PRIu64, &maxCreationToken) == 1 &&
+ bundles.items[0]->creationToken <= maxCreationToken) {
+ free(bundles.items);
+ return 0;
+ }
+
+ /*
+ * Attempt to download and unbundle the minimum number of bundles by
+ * creationToken in decreasing order. If we fail to unbundle (after
+ * a successful download) then move to the next non-downloaded bundle
+ * and attempt downloading. Once we succeed in applying a bundle,
+ * move to the previous unapplied bundle and attempt to unbundle it
+ * again.
+ *
+ * In the case of a fresh clone, we will likely download all of the
+ * bundles before successfully unbundling the oldest one, then the
+ * rest of the bundles unbundle successfully in increasing order
+ * of creationToken.
+ *
+ * If there are existing objects, then this process may terminate
+ * early when all required commits from "new" bundles exist in the
+ * repo's object store.
+ */
+ cur = 0;
+ while (cur >= 0 && cur < bundles.nr) {
+ struct remote_bundle_info *bundle = bundles.items[cur];
+
+ /*
+ * If we need to dig into bundles below the previous
+ * creation token value, then likely we are in an erroneous
+ * state due to missing or invalid bundles. Halt the process
+ * instead of continuing to download extra data.
+ */
+ if (bundle->creationToken <= maxCreationToken)
+ break;
+
+ if (!bundle->file) {
+ /*
+ * Not downloaded yet. Try downloading.
+ *
+ * Note that bundle->file is non-NULL if a download
+ * was attempted, even if it failed to download.
+ */
+ if (fetch_bundle_uri_internal(ctx.r, bundle, ctx.depth + 1, ctx.list)) {
+ /* Mark as unbundled so we do not retry. */
+ bundle->unbundled = 1;
+
+ /* Try looking deeper in the list. */
+ move_direction = 1;
+ goto move;
+ }
+
+ /* We expect bundles when using creationTokens. */
+ if (!is_bundle(bundle->file, 1)) {
+ warning(_("file downloaded from '%s' is not a bundle"),
+ bundle->uri);
+ break;
+ }
+ }
+
+ if (bundle->file && !bundle->unbundled) {
+ /*
+ * This was downloaded, but not successfully
+ * unbundled. Try unbundling again.
+ */
+ if (unbundle_from_file(ctx.r, bundle->file)) {
+ /* Try looking deeper in the list. */
+ move_direction = 1;
+ } else {
+ /*
+ * Succeeded in unbundle. Retry bundles
+ * that previously failed to unbundle.
+ */
+ move_direction = -1;
+ bundle->unbundled = 1;
+
+ if (bundle->creationToken > newMaxCreationToken)
+ newMaxCreationToken = bundle->creationToken;
+ }
+ }
+
+ /*
+ * Else case: downloaded and unbundled successfully.
+ * Skip this by moving in the same direction as the
+ * previous step.
+ */
+
+move:
+ /* Move in the specified direction and repeat. */
+ cur += move_direction;
+ }
+
+ /*
+ * We succeed if the loop terminates because 'cur' drops below
+ * zero. The other case is that we terminate because 'cur'
+ * reaches the end of the list, so we have a failure no matter
+ * which bundles we apply from the list.
+ */
+ if (cur < 0) {
+ struct strbuf value = STRBUF_INIT;
+ strbuf_addf(&value, "%"PRIu64"", newMaxCreationToken);
+ if (repo_config_set_multivar_gently(ctx.r,
+ "fetch.bundleCreationToken",
+ value.buf, NULL, 0))
+ warning(_("failed to store maximum creation token"));
+
+ strbuf_release(&value);
+ }
+
+ free(bundles.items);
+ return cur >= 0;
+}
+
static int download_bundle_list(struct repository *r,
struct bundle_list *local_list,
struct bundle_list *global_list,
@@ -426,7 +661,15 @@ static int fetch_bundle_list_in_config_format(struct repository *r,
goto cleanup;
}
- if ((result = download_bundle_list(r, &list_from_bundle,
+ /*
+ * If this list uses the creationToken heuristic, then the URIs
+ * it advertises are expected to be bundles, not nested lists.
+ * We can drop 'global_list' and 'depth'.
+ */
+ if (list_from_bundle.heuristic == BUNDLE_HEURISTIC_CREATIONTOKEN) {
+ result = fetch_bundles_by_token(r, &list_from_bundle);
+ global_list->heuristic = BUNDLE_HEURISTIC_CREATIONTOKEN;
+ } else if ((result = download_bundle_list(r, &list_from_bundle,
global_list, depth)))
goto cleanup;
@@ -537,7 +780,8 @@ static int unlink_bundle(struct remote_bundle_info *info, void *data)
return 0;
}
-int fetch_bundle_uri(struct repository *r, const char *uri)
+int fetch_bundle_uri(struct repository *r, const char *uri,
+ int *has_heuristic)
{
int result;
struct bundle_list list;
@@ -557,12 +801,96 @@ int fetch_bundle_uri(struct repository *r, const char *uri)
result = unbundle_all_bundles(r, &list);
cleanup:
+ if (has_heuristic)
+ *has_heuristic = (list.heuristic != BUNDLE_HEURISTIC_NONE);
for_all_bundles_in_list(&list, unlink_bundle, NULL);
clear_bundle_list(&list);
clear_remote_bundle_info(&bundle, NULL);
return result;
}
+int fetch_bundle_list(struct repository *r, struct bundle_list *list)
+{
+ int result;
+ struct bundle_list global_list;
+
+ /*
+ * If the creationToken heuristic is used, then the URIs
+ * advertised by 'list' are not nested lists and instead
+ * direct bundles. We do not need to use global_list.
+ */
+ if (list->heuristic == BUNDLE_HEURISTIC_CREATIONTOKEN)
+ return fetch_bundles_by_token(r, 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;
+
+ if (list->heuristic == BUNDLE_HEURISTIC_CREATIONTOKEN)
+ result = fetch_bundles_by_token(r, list);
+ else
+ 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 (starts_with(key, "bundle."))
+ 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.
*/
diff --git a/bundle-uri.h b/bundle-uri.h
index 4dbc269..6dbc780 100644
--- a/bundle-uri.h
+++ b/bundle-uri.h
@@ -4,6 +4,7 @@
#include "hashmap.h"
#include "strbuf.h"
+struct packet_reader;
struct repository;
struct string_list;
@@ -41,6 +42,12 @@ struct remote_bundle_info {
* this boolean is true.
*/
unsigned unbundled:1;
+
+ /**
+ * If the bundle is part of a list with the creationToken
+ * heuristic, then we use this member for sorting the bundles.
+ */
+ uint64_t creationToken;
};
#define REMOTE_BUNDLE_INFO_INIT { 0 }
@@ -51,6 +58,14 @@ enum bundle_list_mode {
BUNDLE_MODE_ANY
};
+enum bundle_list_heuristic {
+ BUNDLE_HEURISTIC_NONE = 0,
+ BUNDLE_HEURISTIC_CREATIONTOKEN,
+
+ /* Must be last. */
+ BUNDLE_HEURISTIC__COUNT
+};
+
/**
* A bundle_list contains an unordered set of remote_bundle_info structs,
* as well as information about the bundle listing, such as version and
@@ -60,6 +75,26 @@ 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;
+
+ /**
+ * A list can have a heuristic, which helps reduce the number of
+ * downloaded bundles.
+ */
+ enum bundle_list_heuristic heuristic;
};
void init_bundle_list(struct bundle_list *list);
@@ -89,8 +124,34 @@ int bundle_uri_parse_config_format(const char *uri,
* based on that information.
*
* Returns non-zero if no bundle information is found at the given 'uri'.
+ *
+ * If the pointer 'has_heuristic' is non-NULL, then the value it points to
+ * will be set to be non-zero if and only if the fetched list has a
+ * heuristic value. Such a value indicates that the list was designed for
+ * incremental fetches.
*/
-int fetch_bundle_uri(struct repository *r, const char *uri);
+int fetch_bundle_uri(struct repository *r, const char *uri,
+ int *has_heuristic);
+
+/**
+ * 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/bundle.c b/bundle.c
index 4ef7256..6ab6cd7 100644
--- a/bundle.c
+++ b/bundle.c
@@ -12,6 +12,7 @@
#include "refs.h"
#include "strvec.h"
#include "list-objects-filter-options.h"
+#include "connected.h"
static const char v2_bundle_signature[] = "# v2 git bundle\n";
static const char v3_bundle_signature[] = "# v3 git bundle\n";
@@ -187,6 +188,21 @@ static int list_refs(struct string_list *r, int argc, const char **argv)
/* Remember to update object flag allocation in object.h */
#define PREREQ_MARK (1u<<16)
+struct string_list_iterator {
+ struct string_list *list;
+ size_t cur;
+};
+
+static const struct object_id *iterate_ref_map(void *cb_data)
+{
+ struct string_list_iterator *iter = cb_data;
+
+ if (iter->cur >= iter->list->nr)
+ return NULL;
+
+ return iter->list->items[iter->cur++].util;
+}
+
int verify_bundle(struct repository *r,
struct bundle_header *header,
enum verify_bundle_flags flags)
@@ -196,26 +212,25 @@ int verify_bundle(struct repository *r,
* to be verbose about the errors
*/
struct string_list *p = &header->prerequisites;
- struct rev_info revs = REV_INFO_INIT;
- const char *argv[] = {NULL, "--all", NULL};
- struct commit *commit;
- int i, ret = 0, req_nr;
+ int i, ret = 0;
const char *message = _("Repository lacks these prerequisite commits:");
+ struct string_list_iterator iter = {
+ .list = p,
+ };
+ struct check_connected_options opts = {
+ .quiet = 1,
+ };
if (!r || !r->objects || !r->objects->odb)
return error(_("need a repository to verify a bundle"));
- repo_init_revisions(r, &revs, NULL);
for (i = 0; i < p->nr; i++) {
struct string_list_item *e = p->items + i;
const char *name = e->string;
struct object_id *oid = e->util;
struct object *o = parse_object(r, oid);
- if (o) {
- o->flags |= PREREQ_MARK;
- add_pending_object(&revs, o, name);
+ if (o)
continue;
- }
ret++;
if (flags & VERIFY_BUNDLE_QUIET)
continue;
@@ -223,37 +238,14 @@ int verify_bundle(struct repository *r,
error("%s", message);
error("%s %s", oid_to_hex(oid), name);
}
- if (revs.pending.nr != p->nr)
+ if (ret)
goto cleanup;
- req_nr = revs.pending.nr;
- setup_revisions(2, argv, &revs, NULL);
- list_objects_filter_copy(&revs.filter, &header->filter);
+ if ((ret = check_connected(iterate_ref_map, &iter, &opts)))
+ error(_("some prerequisite commits exist in the object store, "
+ "but are not connected to the repository's history"));
- if (prepare_revision_walk(&revs))
- die(_("revision walk setup failed"));
-
- i = req_nr;
- while (i && (commit = get_revision(&revs)))
- if (commit->object.flags & PREREQ_MARK)
- i--;
-
- for (i = 0; i < p->nr; i++) {
- struct string_list_item *e = p->items + i;
- const char *name = e->string;
- const struct object_id *oid = e->util;
- struct object *o = parse_object(r, oid);
- assert(o); /* otherwise we'd have returned early */
- if (o->flags & SHOWN)
- continue;
- ret++;
- if (flags & VERIFY_BUNDLE_QUIET)
- continue;
- if (ret == 1)
- error("%s", message);
- error("%s %s", oid_to_hex(oid), name);
- }
-
+ /* TODO: preserve this verbose language. */
if (flags & VERIFY_BUNDLE_VERBOSE) {
struct string_list *r;
@@ -282,15 +274,6 @@ int verify_bundle(struct repository *r,
list_objects_filter_spec(&header->filter));
}
cleanup:
- /* Clean up objects used, as they will be reused. */
- for (i = 0; i < p->nr; i++) {
- struct string_list_item *e = p->items + i;
- struct object_id *oid = e->util;
- commit = lookup_commit_reference_gently(r, oid, 1);
- if (commit)
- clear_commit_marks(commit, ALL_REV_FLAGS | PREREQ_MARK);
- }
- release_revisions(&revs);
return ret;
}
@@ -627,6 +610,10 @@ int unbundle(struct repository *r, struct bundle_header *header,
enum verify_bundle_flags flags)
{
struct child_process ip = CHILD_PROCESS_INIT;
+
+ if (verify_bundle(r, header, flags))
+ return -1;
+
strvec_pushl(&ip.args, "index-pack", "--fix-thin", "--stdin", NULL);
/* If there is a filter, then we need to create the promisor pack. */
@@ -638,8 +625,6 @@ int unbundle(struct repository *r, struct bundle_header *header,
strvec_clear(extra_index_pack_args);
}
- if (verify_bundle(r, header, flags))
- return -1;
ip.in = bundle_fd;
ip.no_stdout = 1;
ip.git_cmd = 1;
diff --git a/cache-tree.c b/cache-tree.c
index c97111c..88c2c04 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -405,7 +405,7 @@ static int update_one(struct cache_tree *it,
}
/*
- * CE_INTENT_TO_ADD entries exist on on-disk index but
+ * CE_INTENT_TO_ADD entries exist in on-disk index but
* they are not part of generated trees. Invalidate up
* to root to force cache-tree users to read elsewhere.
*/
@@ -760,7 +760,7 @@ static void prime_cache_tree_rec(struct repository *r,
struct tree_desc desc;
struct name_entry entry;
int cnt;
- int base_path_len = tree_path->len;
+ size_t base_path_len = tree_path->len;
oidcpy(&it->oid, &tree->object.oid);
@@ -785,7 +785,6 @@ static void prime_cache_tree_rec(struct repository *r,
*/
if (r->index->sparse_index) {
strbuf_setlen(tree_path, base_path_len);
- strbuf_grow(tree_path, base_path_len + entry.pathlen + 1);
strbuf_add(tree_path, entry.path, entry.pathlen);
strbuf_addch(tree_path, '/');
}
diff --git a/cache-tree.h b/cache-tree.h
index 8efecce..bd97caa 100644
--- a/cache-tree.h
+++ b/cache-tree.h
@@ -53,19 +53,4 @@ int write_index_as_tree(struct object_id *oid, struct index_state *index_state,
void prime_cache_tree(struct repository *, struct index_state *, struct tree *);
int cache_tree_matches_traversal(struct cache_tree *, struct name_entry *ent, struct traverse_info *info);
-
-#ifdef USE_THE_INDEX_COMPATIBILITY_MACROS
-static inline int write_cache_as_tree(struct object_id *oid, int flags, const char *prefix)
-{
- return write_index_as_tree(oid, &the_index, get_index_file(), flags, prefix);
-}
-
-static inline int update_main_cache_tree(int flags)
-{
- if (!the_index.cache_tree)
- the_index.cache_tree = cache_tree();
- return cache_tree_update(&the_index, flags);
-}
-#endif
-
#endif
diff --git a/cache.h b/cache.h
index 8c5fb1e..587a969 100644
--- a/cache.h
+++ b/cache.h
@@ -360,6 +360,22 @@ struct index_state {
struct pattern_list *sparse_checkout_patterns;
};
+/**
+ * A "struct index_state istate" must be initialized with
+ * INDEX_STATE_INIT or the corresponding index_state_init().
+ *
+ * If the variable won't be used again, use release_index() to free()
+ * its resources. If it needs to be used again use discard_index(),
+ * which does the same thing, but will use use index_state_init() at
+ * the end. The discard_index() will use its own "istate->repo" as the
+ * "r" argument to index_state_init() in that case.
+ */
+#define INDEX_STATE_INIT(r) { \
+ .repo = (r), \
+}
+void index_state_init(struct index_state *istate, struct repository *r);
+void release_index(struct index_state *istate);
+
/* Name hashing */
int test_lazy_init_name_hash(struct index_state *istate, int try_threaded);
void add_name_hash(struct index_state *istate, struct cache_entry *ce);
@@ -433,18 +449,8 @@ typedef int (*must_prefetch_predicate)(const struct cache_entry *);
void prefetch_cache_entries(const struct index_state *istate,
must_prefetch_predicate must_prefetch);
-#if defined(USE_THE_INDEX_COMPATIBILITY_MACROS) || defined(USE_THE_INDEX_VARIABLE)
+#ifdef USE_THE_INDEX_VARIABLE
extern struct index_state the_index;
-
-#ifndef USE_THE_INDEX_VARIABLE
-#ifdef USE_THE_INDEX_COMPATIBILITY_MACROS
-#define active_nr (the_index.cache_nr)
-
-#define read_cache() repo_read_index(the_repository)
-#define discard_cache() discard_index(&the_index)
-#define cache_name_pos(name, namelen) index_name_pos(&the_index,(name),(namelen))
-#endif
-#endif
#endif
#define TYPE_BITS 3
@@ -480,7 +486,6 @@ static inline enum object_type object_type(unsigned int mode)
#define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
#define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
#define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
-#define GIT_SUPER_PREFIX_ENVIRONMENT "GIT_INTERNAL_SUPER_PREFIX"
#define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
#define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
#define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
@@ -566,7 +571,6 @@ int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);
int get_common_dir(struct strbuf *sb, const char *gitdir);
const char *get_git_namespace(void);
const char *strip_namespace(const char *namespaced_ref);
-const char *get_super_prefix(void);
const char *get_git_work_tree(void);
/*
@@ -1622,8 +1626,10 @@ int repo_interpret_branch_name(struct repository *r,
int validate_headref(const char *ref);
-int base_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
-int df_name_compare(const char *name1, int len1, int mode1, const char *name2, int len2, int mode2);
+int base_name_compare(const char *name1, size_t len1, int mode1,
+ const char *name2, size_t len2, int mode2);
+int df_name_compare(const char *name1, size_t len1, int mode1,
+ const char *name2, size_t len2, int mode2);
int name_compare(const char *name1, size_t len1, const char *name2, size_t len2);
int cache_name_stage_compare(const char *name1, int len1, int stage1, const char *name2, int len2, int stage2);
diff --git a/ci/lib.sh b/ci/lib.sh
index b6bbb02..e467784 100755
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -256,8 +256,7 @@
MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=$(which python3)"
if [ "$jobname" != osx-gcc ]
then
- MAKEFLAGS="$MAKEFLAGS NO_APPLE_COMMON_CRYPTO=NoThanks"
- MAKEFLAGS="$MAKEFLAGS NO_OPENSSL=NoThanks"
+ MAKEFLAGS="$MAKEFLAGS APPLE_COMMON_CRYPTO_SHA1=Yes"
fi
;;
esac
diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh
index 8ebff42..b098e10 100755
--- a/ci/run-build-and-tests.sh
+++ b/ci/run-build-and-tests.sh
@@ -26,7 +26,6 @@
export GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=1
export GIT_TEST_MULTI_PACK_INDEX=1
export GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=1
- export GIT_TEST_ADD_I_USE_BUILTIN=0
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
export GIT_TEST_WRITE_REV_INDEX=1
export GIT_TEST_CHECKOUT_WORKERS=2
diff --git a/commit-graph.c b/commit-graph.c
index a7d8755..c11b59f 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1594,8 +1594,7 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)
_("Computing commit changed paths Bloom filters"),
ctx->commits.nr);
- ALLOC_ARRAY(sorted_commits, ctx->commits.nr);
- COPY_ARRAY(sorted_commits, ctx->commits.list, ctx->commits.nr);
+ DUP_ARRAY(sorted_commits, ctx->commits.list, ctx->commits.nr);
if (ctx->order_by_pack)
QSORT(sorted_commits, ctx->commits.nr, commit_pos_cmp);
diff --git a/commit-reach.c b/commit-reach.c
index c226ee3..2e33c59 100644
--- a/commit-reach.c
+++ b/commit-reach.c
@@ -245,8 +245,7 @@ static int remove_redundant_with_gen(struct repository *r,
* min_gen_pos points to the current position within 'array'
* that is not yet known to be STALE.
*/
- ALLOC_ARRAY(sorted, cnt);
- COPY_ARRAY(sorted, array, cnt);
+ DUP_ARRAY(sorted, array, cnt);
QSORT(sorted, cnt, compare_commits_by_gen);
min_generation = commit_graph_generation(sorted[0]);
diff --git a/commit.c b/commit.c
index d00780b..e433c33 100644
--- 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));
@@ -1022,6 +1033,7 @@ struct commit *get_fork_point(const char *refname, struct commit *commit)
ret = bases->item;
cleanup_return:
+ free(revs.commit);
free_commit_list(bases);
free(full_refname);
return ret;
diff --git a/commit.h b/commit.h
index fa39202..cc2c5da 100644
--- a/commit.h
+++ b/commit.h
@@ -274,8 +274,6 @@ struct ref;
int for_each_commit_graft(each_commit_graft_fn, void *);
int interactive_add(const char **argv, const char *prefix, int patch);
-int run_add_interactive(const char *revision, const char *patch_mode,
- const struct pathspec *pathspec);
struct commit_extra_header {
struct commit_extra_header *next;
diff --git a/compat/mingw.c b/compat/mingw.c
index d614f15..e433740 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1396,8 +1396,7 @@ static wchar_t *make_environment_block(char **deltaenv)
p += s;
}
- ALLOC_ARRAY(result, size);
- COPY_ARRAY(result, wenv, size);
+ DUP_ARRAY(result, wenv, size);
FreeEnvironmentStringsW(wenv);
return result;
}
@@ -1839,16 +1838,13 @@ static int try_shell_exec(const char *cmd, char *const *argv)
if (prog) {
int exec_id;
int argc = 0;
-#ifndef _MSC_VER
- const
-#endif
char **argv2;
while (argv[argc]) argc++;
ALLOC_ARRAY(argv2, argc + 1);
argv2[0] = (char *)cmd; /* full path to the script file */
COPY_ARRAY(&argv2[1], &argv[1], argc);
- exec_id = trace2_exec(prog, argv2);
- pid = mingw_spawnv(prog, argv2, 1);
+ exec_id = trace2_exec(prog, (const char **)argv2);
+ pid = mingw_spawnv(prog, (const char **)argv2, 1);
if (pid >= 0) {
int status;
if (waitpid(pid, &status, 0) < 0)
@@ -2752,7 +2748,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;
diff --git a/compat/win32/pthread.c b/compat/win32/pthread.c
index 2e7eead..85f8f79 100644
--- a/compat/win32/pthread.c
+++ b/compat/win32/pthread.c
@@ -22,12 +22,12 @@ static unsigned __stdcall win32_start_routine(void *arg)
}
int pthread_create(pthread_t *thread, const void *unused,
- void *(*start_routine)(void*), void *arg)
+ void *(*start_routine)(void *), void *arg)
{
thread->arg = arg;
thread->start_routine = start_routine;
- thread->handle = (HANDLE)
- _beginthreadex(NULL, 0, win32_start_routine, thread, 0, NULL);
+ thread->handle = (HANDLE)_beginthreadex(NULL, 0, win32_start_routine,
+ thread, 0, NULL);
if (!thread->handle)
return errno;
@@ -39,14 +39,17 @@ int win32_pthread_join(pthread_t *thread, void **value_ptr)
{
DWORD result = WaitForSingleObject(thread->handle, INFINITE);
switch (result) {
- case WAIT_OBJECT_0:
- if (value_ptr)
- *value_ptr = thread->arg;
- return 0;
- case WAIT_ABANDONED:
- return EINVAL;
- default:
- return err_win_to_posix(GetLastError());
+ case WAIT_OBJECT_0:
+ if (value_ptr)
+ *value_ptr = thread->arg;
+ CloseHandle(thread->handle);
+ return 0;
+ case WAIT_ABANDONED:
+ CloseHandle(thread->handle);
+ return EINVAL;
+ default:
+ /* the wait failed, so do not detach */
+ return err_win_to_posix(GetLastError());
}
}
diff --git a/compat/win32/pthread.h b/compat/win32/pthread.h
index 737983d..cc3221c 100644
--- a/compat/win32/pthread.h
+++ b/compat/win32/pthread.h
@@ -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;
diff --git a/compat/winansi.c b/compat/winansi.c
index 3abe8dd..f83610f 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -644,7 +644,7 @@ void winansi_init(void)
/* start console spool thread on the pipe's read end */
hthread = CreateThread(NULL, 0, console_thread, NULL, 0, NULL);
- if (hthread == INVALID_HANDLE_VALUE)
+ if (!hthread)
die_lasterr("CreateThread(console_thread) failed");
/* schedule cleanup routine */
diff --git a/config.c b/config.c
index 8c1c407..aa2888d 100644
--- a/config.c
+++ b/config.c
@@ -3154,7 +3154,7 @@ int git_config_set_gently(const char *key, const char *value)
int repo_config_set_worktree_gently(struct repository *r,
const char *key, const char *value)
{
- /* Only use worktree-specific config if it is is already enabled. */
+ /* Only use worktree-specific config if it is already enabled. */
if (repository_format_worktree_config) {
char *file = repo_git_path(r, "config.worktree");
int ret = git_config_set_multivar_in_file_gently(
diff --git a/config.h b/config.h
index ef9eade..7606246 100644
--- a/config.h
+++ b/config.h
@@ -448,15 +448,6 @@ void git_configset_init(struct config_set *cs);
int git_configset_add_file(struct config_set *cs, const char *filename);
/**
- * Parses command line options and environment variables, and adds the
- * variable-value pairs to the `config_set`. Returns 0 on success, or -1
- * if there is an error in parsing. The caller decides whether to free
- * the incomplete configset or continue using it when the function
- * returns -1.
- */
-int git_configset_add_parameters(struct config_set *cs);
-
-/**
* Finds and returns the value list, sorted in order of increasing priority
* for the configuration variable `key` and config set `cs`. When the
* configuration variable `key` is not found, returns NULL. The caller
diff --git a/config.mak.uname b/config.mak.uname
index 7d25995..64c44db 100644
--- a/config.mak.uname
+++ b/config.mak.uname
@@ -624,6 +624,9 @@
SHELL_PATH = /usr/coreutils/bin/bash
endif
ifeq ($(uname_S),MINGW)
+ ifeq ($(shell expr "$(uname_R)" : '1\.'),2)
+ $(error "Building with MSys is no longer supported")
+ endif
pathsep = ;
HAVE_ALLOCA_H = YesPlease
NO_PREAD = YesPlease
@@ -653,7 +656,6 @@
USE_WIN32_IPC = YesPlease
USE_WIN32_MMAP = YesPlease
MMAP_PREVENTS_DELETE = UnfortunatelyYes
- USE_NED_ALLOCATOR = YesPlease
UNRELIABLE_FSTAT = UnfortunatelyYes
OBJECT_CREATION_USES_RENAMES = UnfortunatelyNeedsTo
NO_REGEX = YesPlease
@@ -678,61 +680,43 @@
RC = windres -O coff
NATIVE_CRLF = YesPlease
X = .exe
-ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
- htmldir = doc/git/html/
- prefix =
+ # MSys2
+ prefix = /usr/
+ # Enable DEP
+ BASIC_LDFLAGS += -Wl,--nxcompat
+ # Enable ASLR (unless debugging)
+ ifneq (,$(findstring -O,$(filter-out -O0 -Og,$(CFLAGS))))
+ BASIC_LDFLAGS += -Wl,--dynamicbase
+ endif
+ ifeq (MINGW32,$(MSYSTEM))
+ prefix = /mingw32
+ HOST_CPU = i686
+ BASIC_LDFLAGS += -Wl,--pic-executable,-e,_mainCRTStartup
+ endif
+ ifeq (MINGW64,$(MSYSTEM))
+ prefix = /mingw64
+ HOST_CPU = x86_64
+ BASIC_LDFLAGS += -Wl,--pic-executable,-e,mainCRTStartup
+ else
+ COMPAT_CFLAGS += -D_USE_32BIT_TIME_T
+ BASIC_LDFLAGS += -Wl,--large-address-aware
+ endif
+ CC = gcc
+ COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -DDETECT_MSYS_TTY \
+ -fstack-protector-strong
+ EXTLIBS += -lntdll
INSTALL = /bin/install
- EXTLIBS += /mingw/lib/libz.a
INTERNAL_QSORT = YesPlease
HAVE_LIBCHARSET_H = YesPlease
- NO_GETTEXT = YesPlease
- NO_PYTHON = YesPlease
- COMPAT_CFLAGS += -D__USE_MINGW_ACCESS
-else
- ifneq ($(shell expr "$(uname_R)" : '1\.'),2)
- # MSys2
- prefix = /usr/
- # Enable DEP
- BASIC_LDFLAGS += -Wl,--nxcompat
- # Enable ASLR (unless debugging)
- ifneq (,$(findstring -O,$(filter-out -O0 -Og,$(CFLAGS))))
- BASIC_LDFLAGS += -Wl,--dynamicbase
- endif
- ifeq (MINGW32,$(MSYSTEM))
- prefix = /mingw32
- HOST_CPU = i686
- BASIC_LDFLAGS += -Wl,--pic-executable,-e,_mainCRTStartup
- endif
- ifeq (MINGW64,$(MSYSTEM))
- prefix = /mingw64
- HOST_CPU = x86_64
- BASIC_LDFLAGS += -Wl,--pic-executable,-e,mainCRTStartup
- else
- COMPAT_CFLAGS += -D_USE_32BIT_TIME_T
- BASIC_LDFLAGS += -Wl,--large-address-aware
- endif
- CC = gcc
- COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO=0 -DDETECT_MSYS_TTY \
- -fstack-protector-strong
- EXTLIBS += -lntdll
- INSTALL = /bin/install
- INTERNAL_QSORT = YesPlease
- HAVE_LIBCHARSET_H = YesPlease
- USE_GETTEXT_SCHEME = fallthrough
- USE_LIBPCRE = YesPlease
- USE_NED_ALLOCATOR = YesPlease
- ifeq (/mingw64,$(subst 32,64,$(prefix)))
- # Move system config into top-level /etc/
- ETC_GITCONFIG = ../etc/gitconfig
- ETC_GITATTRIBUTES = ../etc/gitattributes
- endif
- else
- COMPAT_CFLAGS += -D__USE_MINGW_ANSI_STDIO
- NO_CURL = YesPlease
- NO_PYTHON = YesPlease
+ USE_GETTEXT_SCHEME = fallthrough
+ USE_LIBPCRE = YesPlease
+ USE_NED_ALLOCATOR = YesPlease
+ ifeq (/mingw64,$(subst 32,64,$(prefix)))
+ # Move system config into top-level /etc/
+ ETC_GITCONFIG = ../etc/gitconfig
+ ETC_GITATTRIBUTES = ../etc/gitattributes
endif
endif
-endif
ifeq ($(uname_S),QNX)
COMPAT_CFLAGS += -DSA_RESTART=0
EXPAT_NEEDS_XMLPARSE_H = YesPlease
diff --git a/connect.c b/connect.c
index eef752f..63e5964 100644
--- 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;
@@ -493,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,
diff --git a/connected.c b/connected.c
index 4f6388e..b90fd61 100644
--- a/connected.c
+++ b/connected.c
@@ -85,6 +85,7 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
promisor_pack_found:
;
} while ((oid = fn(cb_data)) != NULL);
+ free(new_pack);
return 0;
}
@@ -121,8 +122,10 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
else
rev_list.no_stderr = opt->quiet;
- if (start_command(&rev_list))
+ if (start_command(&rev_list)) {
+ free(new_pack);
return error(_("Could not run 'git rev-list'"));
+ }
sigchain_push(SIGPIPE, SIG_IGN);
@@ -154,5 +157,6 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
err = error_errno(_("failed to close rev-list's stdin"));
sigchain_pop(SIGPIPE);
+ free(new_pack);
return finish_command(&rev_list) || err;
}
diff --git a/contrib/coccinelle/array.cocci b/contrib/coccinelle/array.cocci
index aa75937..27a3b47 100644
--- a/contrib/coccinelle/array.cocci
+++ b/contrib/coccinelle/array.cocci
@@ -94,3 +94,10 @@
@@
- ptr = xcalloc(n, \( sizeof(*ptr) \| sizeof(T) \) )
+ CALLOC_ARRAY(ptr, n)
+
+@@
+expression dst, src, n;
+@@
+-ALLOC_ARRAY(dst, n);
+-COPY_ARRAY(dst, src, n);
++DUP_ARRAY(dst, src, n);
diff --git a/contrib/coccinelle/index-compatibility.cocci b/contrib/coccinelle/index-compatibility.cocci
index 8520f03..31e36cf 100644
--- a/contrib/coccinelle/index-compatibility.cocci
+++ b/contrib/coccinelle/index-compatibility.cocci
@@ -1,6 +1,7 @@
// the_index.* variables
@@
identifier AC = active_cache;
+identifier AN = active_nr;
identifier ACC = active_cache_changed;
identifier ACT = active_cache_tree;
@@
@@ -8,6 +9,9 @@
- AC
+ the_index.cache
|
+- AN
++ the_index.cache_nr
+|
- ACC
+ the_index.cache_changed
|
@@ -15,19 +19,13 @@
+ the_index.cache_tree
)
-@@
-identifier AN = active_nr;
-identifier f != prepare_to_commit;
-@@
- f(...) {<...
-- AN
-+ the_index.cache_nr
- ...>}
-
// "the_repository" simple cases
@@
@@
(
+- read_cache
++ repo_read_index
+|
- read_cache_unmerged
+ repo_read_index_unmerged
|
@@ -96,6 +94,15 @@
|
- resolve_undo_clear
+ resolve_undo_clear_index
+|
+- cache_name_pos
++ index_name_pos
+|
+- update_main_cache_tree
++ cache_tree_update
+|
+- discard_cache
++ discard_index
)
(
+ &the_index,
@@ -137,3 +144,14 @@
...
+ , NULL, NULL, NULL
)
+
+@@
+expression O;
+@@
+- write_cache_as_tree
++ write_index_as_tree
+ (
+- O,
++ O, &the_index, get_index_file(),
+ ...
+ )
diff --git a/contrib/coccinelle/index-compatibility.pending.cocci b/contrib/coccinelle/index-compatibility.pending.cocci
deleted file mode 100644
index 01f875d0..0000000
--- a/contrib/coccinelle/index-compatibility.pending.cocci
+++ /dev/null
@@ -1,24 +0,0 @@
-// "the_repository" simple cases
-@@
-@@
-(
-- read_cache
-+ repo_read_index
-)
- (
-+ the_repository,
- ...)
-
-// "the_index" simple cases
-@@
-@@
-(
-- discard_cache
-+ discard_index
-|
-- cache_name_pos
-+ index_name_pos
-)
- (
-+ &the_index,
- ...)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index ba5c395..dc95c34 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -58,6 +58,12 @@
#
# 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 @@
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 @@
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 @@
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 @@
# 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 @@
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 @@
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 @@
*)
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 @@
;;
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 @@
*)
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*" \
diff --git a/contrib/git-jump/README b/contrib/git-jump/README
index 8bcace2..3211841 100644
--- a/contrib/git-jump/README
+++ b/contrib/git-jump/README
@@ -79,6 +79,14 @@
git config jump.grepCmd "ag --column"
--------------------------------------------------
+You can use the optional argument '--stdout' to print the listing to
+standard output instead of feeding it to the editor. You can use the
+argument with M-x grep on Emacs:
+
+--------------------------------------------------
+# In Emacs, M-x grep and invoke "git jump --stdout <mode>"
+M-x grep<RET>git jump --stdout diff<RET>
+--------------------------------------------------
Related Programs
----------------
@@ -100,7 +108,7 @@
-----------
This script was written and tested with vim. Given that the quickfix
-format is the same as what gcc produces, I expect emacs users have a
+format is the same as what gcc produces, I expect other tools have a
similar feature for iterating through the list, but I know nothing about
how to activate it.
diff --git a/contrib/git-jump/git-jump b/contrib/git-jump/git-jump
index 92dbd4c..40c4b0d 100755
--- a/contrib/git-jump/git-jump
+++ b/contrib/git-jump/git-jump
@@ -2,7 +2,7 @@
usage() {
cat <<\EOF
-usage: git jump <mode> [<args>]
+usage: git jump [--stdout] <mode> [<args>]
Jump to interesting elements in an editor.
The <mode> parameter is one of:
@@ -15,12 +15,30 @@
configured, to the command in `jump.grepCmd`.
ws: elements are whitespace errors. Arguments are given to diff --check.
+
+If the optional argument `--stdout` is given, print the quickfix
+lines to standard output instead of feeding it to the editor.
EOF
}
open_editor() {
editor=`git var GIT_EDITOR`
- eval "$editor -q \$1"
+ case "$editor" in
+ *emacs*)
+ # Supported editor values are:
+ # - emacs
+ # - emacsclient
+ # - emacsclient -t
+ #
+ # Wait for completion of the asynchronously executed process
+ # to avoid race conditions in case of "emacsclient".
+ eval "$editor --eval \"(let ((buf (grep \\\"cat \$1\\\"))) (pop-to-buffer buf) (select-frame-set-input-focus (selected-frame)) (while (get-buffer-process buf) (sleep-for 0.1)))\""
+ ;;
+ *)
+ # assume anything else is vi-compatible
+ eval "$editor -q \$1"
+ ;;
+ esac
}
mode_diff() {
@@ -64,15 +82,36 @@
git diff --check "$@"
}
+use_stdout=
+while test $# -gt 0; do
+ case "$1" in
+ --stdout)
+ use_stdout=t
+ ;;
+ --*)
+ usage >&2
+ exit 1
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+done
if test $# -lt 1; then
usage >&2
exit 1
fi
mode=$1; shift
+type "mode_$mode" >/dev/null 2>&1 || { usage >&2; exit 1; }
+
+if test "$use_stdout" = "t"; then
+ "mode_$mode" "$@"
+ exit 0
+fi
trap 'rm -f "$tmp"' 0 1 2 3 15
tmp=`mktemp -t git-jump.XXXXXX` || exit 1
-type "mode_$mode" >/dev/null 2>&1 || { usage >&2; exit 1; }
"mode_$mode" "$@" >"$tmp"
test -s "$tmp" || exit 0
open_editor "$tmp"
diff --git a/convert.c b/convert.c
index 9b67649..a54d169 100644
--- a/convert.c
+++ b/convert.c
@@ -1308,7 +1308,7 @@ void convert_attrs(struct index_state *istate,
git_config(read_convert_config, NULL);
}
- git_check_attr(istate, path, check);
+ git_check_attr(istate, NULL, path, check);
ccheck = check->items;
ca->crlf_action = git_path_check_crlf(ccheck + 4);
if (ca->crlf_action == CRLF_UNDEFINED)
diff --git a/credential.c b/credential.c
index f6389a5..f320113 100644
--- a/credential.c
+++ b/credential.c
@@ -7,6 +7,7 @@
#include "prompt.h"
#include "sigchain.h"
#include "urlmatch.h"
+#include "git-compat-util.h"
void credential_init(struct credential *c)
{
@@ -234,6 +235,11 @@ int credential_read(struct credential *c, FILE *fp)
} else if (!strcmp(key, "path")) {
free(c->path);
c->path = xstrdup(value);
+ } else if (!strcmp(key, "password_expiry_utc")) {
+ errno = 0;
+ c->password_expiry_utc = parse_timestamp(value, NULL, 10);
+ if (c->password_expiry_utc == 0 || errno == ERANGE)
+ c->password_expiry_utc = TIME_MAX;
} else if (!strcmp(key, "url")) {
credential_from_url(c, value);
} else if (!strcmp(key, "quit")) {
@@ -269,6 +275,11 @@ void credential_write(const struct credential *c, FILE *fp)
credential_write_item(fp, "path", c->path, 0);
credential_write_item(fp, "username", c->username, 0);
credential_write_item(fp, "password", c->password, 0);
+ if (c->password_expiry_utc != TIME_MAX) {
+ char *s = xstrfmt("%"PRItime, c->password_expiry_utc);
+ credential_write_item(fp, "password_expiry_utc", s, 0);
+ free(s);
+ }
}
static int run_credential_helper(struct credential *c,
@@ -342,6 +353,12 @@ void credential_fill(struct credential *c)
for (i = 0; i < c->helpers.nr; i++) {
credential_do(c, c->helpers.items[i].string, "get");
+ if (c->password_expiry_utc < time(NULL)) {
+ /* Discard expired password */
+ FREE_AND_NULL(c->password);
+ /* Reset expiry to maintain consistency */
+ c->password_expiry_utc = TIME_MAX;
+ }
if (c->username && c->password)
return;
if (c->quit)
@@ -360,7 +377,7 @@ void credential_approve(struct credential *c)
if (c->approved)
return;
- if (!c->username || !c->password)
+ if (!c->username || !c->password || c->password_expiry_utc < time(NULL))
return;
credential_apply_config(c);
@@ -381,6 +398,7 @@ void credential_reject(struct credential *c)
FREE_AND_NULL(c->username);
FREE_AND_NULL(c->password);
+ c->password_expiry_utc = TIME_MAX;
c->approved = 0;
}
diff --git a/credential.h b/credential.h
index f430e77..935b28a 100644
--- a/credential.h
+++ b/credential.h
@@ -126,10 +126,12 @@ struct credential {
char *protocol;
char *host;
char *path;
+ timestamp_t password_expiry_utc;
};
#define CREDENTIAL_INIT { \
.helpers = STRING_LIST_INIT_DUP, \
+ .password_expiry_utc = TIME_MAX, \
}
/* Initialize a credential structure, setting all fields to empty. */
diff --git a/csum-file.c b/csum-file.c
index 59ef339..cce13c0 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -45,7 +45,8 @@ void hashflush(struct hashfile *f)
unsigned offset = f->offset;
if (offset) {
- the_hash_algo->update_fn(&f->ctx, f->buffer, offset);
+ if (!f->skip_hash)
+ the_hash_algo->update_fn(&f->ctx, f->buffer, offset);
flush(f, f->buffer, offset);
f->offset = 0;
}
@@ -64,7 +65,12 @@ int finalize_hashfile(struct hashfile *f, unsigned char *result,
int fd;
hashflush(f);
- the_hash_algo->final_fn(f->buffer, &f->ctx);
+
+ if (f->skip_hash)
+ hashclr(f->buffer);
+ else
+ the_hash_algo->final_fn(f->buffer, &f->ctx);
+
if (result)
hashcpy(result, f->buffer);
if (flags & CSUM_HASH_IN_STREAM)
@@ -108,7 +114,8 @@ void hashwrite(struct hashfile *f, const void *buf, unsigned int count)
* the hashfile's buffer. In this block,
* f->offset is necessarily zero.
*/
- the_hash_algo->update_fn(&f->ctx, buf, nr);
+ if (!f->skip_hash)
+ the_hash_algo->update_fn(&f->ctx, buf, nr);
flush(f, buf, nr);
} else {
/*
@@ -153,6 +160,7 @@ static struct hashfile *hashfd_internal(int fd, const char *name,
f->tp = tp;
f->name = name;
f->do_crc = 0;
+ f->skip_hash = 0;
the_hash_algo->init_fn(&f->ctx);
f->buffer_len = buffer_len;
diff --git a/csum-file.h b/csum-file.h
index 0d29f52..793a59d 100644
--- a/csum-file.h
+++ b/csum-file.h
@@ -20,6 +20,13 @@ struct hashfile {
size_t buffer_len;
unsigned char *buffer;
unsigned char *check_buffer;
+
+ /**
+ * If non-zero, skip_hash indicates that we should
+ * not actually compute the hash for this hashfile and
+ * instead only use it as a buffered write.
+ */
+ int skip_hash;
};
/* Checkpoint */
diff --git a/date.c b/date.c
index 53bd6a7..6f45eeb 100644
--- a/date.c
+++ b/date.c
@@ -493,6 +493,12 @@ static int match_alpha(const char *date, struct tm *tm, int *offset)
return 2;
}
+ /* ISO-8601 allows yyyymmDD'T'HHMMSS, with less precision */
+ if (*date == 'T' && isdigit(date[1]) && tm->tm_hour == -1) {
+ tm->tm_min = tm->tm_sec = 0;
+ return 1;
+ }
+
/* BAD CRAP */
return skip_alpha(date);
}
@@ -639,6 +645,18 @@ static inline int nodate(struct tm *tm)
}
/*
+ * Have we seen an ISO-8601-alike date, i.e. 20220101T0,
+ * In which, hour is still unset,
+ * and minutes and second has been set to 0.
+ */
+static inline int maybeiso8601(struct tm *tm)
+{
+ return tm->tm_hour == -1 &&
+ tm->tm_min == 0 &&
+ tm->tm_sec == 0;
+}
+
+/*
* We've seen a digit. Time? Year? Date?
*/
static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt)
@@ -701,6 +719,25 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
return end - date;
}
+ /* reduced precision of ISO-8601's time: HHMM or HH */
+ if (maybeiso8601(tm)) {
+ unsigned int num1 = num;
+ unsigned int num2 = 0;
+ if (n == 4) {
+ num1 = num / 100;
+ num2 = num % 100;
+ }
+ if ((n == 4 || n == 2) && !nodate(tm) &&
+ set_time(num1, num2, 0, tm) == 0)
+ return n;
+ /*
+ * We thought this is an ISO-8601 time string,
+ * we set minutes and seconds to 0,
+ * turn out it isn't, rollback the change.
+ */
+ tm->tm_min = tm->tm_sec = -1;
+ }
+
/* Four-digit year or a timezone? */
if (n == 4) {
if (num <= 1400 && *offset == -1) {
diff --git a/delta-islands.c b/delta-islands.c
index 90c0d69..afdec0a 100644
--- a/delta-islands.c
+++ b/delta-islands.c
@@ -513,6 +513,22 @@ void propagate_island_marks(struct commit *commit)
}
}
+void free_island_marks(void)
+{
+ struct island_bitmap *bitmap;
+
+ if (island_marks) {
+ kh_foreach_value(island_marks, bitmap, {
+ if (!--bitmap->refcount)
+ free(bitmap);
+ });
+ kh_destroy_oid_map(island_marks);
+ }
+
+ /* detect use-after-free with a an address which is never valid: */
+ island_marks = (void *)-1;
+}
+
int compute_pack_layers(struct packing_data *to_pack)
{
uint32_t i;
diff --git a/delta-islands.h b/delta-islands.h
index eb0f952..8d1591a 100644
--- a/delta-islands.h
+++ b/delta-islands.h
@@ -14,5 +14,6 @@ void resolve_tree_islands(struct repository *r,
void load_delta_islands(struct repository *r, int progress);
void propagate_island_marks(struct commit *commit);
int compute_pack_layers(struct packing_data *to_pack);
+void free_island_marks(void);
#endif /* DELTA_ISLANDS_H */
diff --git a/diff-no-index.c b/diff-no-index.c
index 18edbdf..05fafd0 100644
--- a/diff-no-index.c
+++ b/diff-no-index.c
@@ -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 6a5ed21..469e18a 100644
--- a/diff.c
+++ b/diff.c
@@ -2800,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);
@@ -3437,6 +3437,22 @@ static int diff_filepair_is_phoney(struct diff_filespec *one,
return !DIFF_FILE_VALID(one) && !DIFF_FILE_VALID(two);
}
+static int set_diff_algorithm(struct diff_options *opts,
+ const char *alg)
+{
+ long value = parse_algorithm_value(alg);
+
+ if (value < 0)
+ return -1;
+
+ /* clear out previous settings */
+ DIFF_XDL_CLR(opts, NEED_MINIMAL);
+ opts->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK;
+ opts->xdl_opts |= value;
+
+ return 0;
+}
+
static void builtin_diff(const char *name_a,
const char *name_b,
struct diff_filespec *one,
@@ -4440,15 +4456,13 @@ static void run_diff_cmd(const char *pgm,
const char *xfrm_msg = NULL;
int complete_rewrite = (p->status == DIFF_STATUS_MODIFIED) && p->score;
int must_show_header = 0;
+ struct userdiff_driver *drv = NULL;
-
- if (o->flags.allow_external) {
- struct userdiff_driver *drv;
-
+ if (o->flags.allow_external || !o->ignore_driver_algorithm)
drv = userdiff_find_by_path(o->repo->index, attr_path);
- if (drv && drv->external)
- pgm = drv->external;
- }
+
+ if (o->flags.allow_external && drv && drv->external)
+ pgm = drv->external;
if (msg) {
/*
@@ -4465,12 +4479,16 @@ static void run_diff_cmd(const char *pgm,
run_external_diff(pgm, name, other, one, two, xfrm_msg, o);
return;
}
- if (one && two)
+ if (one && two) {
+ if (!o->ignore_driver_algorithm && drv && drv->algorithm)
+ set_diff_algorithm(o, drv->algorithm);
+
builtin_diff(name, other ? other : name,
one, two, xfrm_msg, must_show_header,
o, complete_rewrite);
- else
+ } else {
fprintf(o->file, "* Unmerged path %s\n", name);
+ }
}
static void diff_fill_oid_info(struct diff_filespec *one, struct index_state *istate)
@@ -4567,6 +4585,14 @@ static void run_diffstat(struct diff_filepair *p, struct diff_options *o,
const char *name;
const char *other;
+ if (!o->ignore_driver_algorithm) {
+ struct userdiff_driver *drv = userdiff_find_by_path(o->repo->index,
+ p->one->path);
+
+ if (drv && drv->algorithm)
+ set_diff_algorithm(o, drv->algorithm);
+ }
+
if (DIFF_PAIR_UNMERGED(p)) {
/* unmerged */
builtin_diffstat(p->one->path, NULL, NULL, NULL,
@@ -4611,8 +4637,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));
@@ -4658,8 +4682,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[] = {
@@ -4817,8 +4839,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,
@@ -5113,17 +5133,32 @@ static int diff_opt_diff_algorithm(const struct option *opt,
const char *arg, int unset)
{
struct diff_options *options = opt->value;
- long value = parse_algorithm_value(arg);
BUG_ON_OPT_NEG(unset);
- if (value < 0)
+
+ if (set_diff_algorithm(options, arg))
return error(_("option diff-algorithm accepts \"myers\", "
"\"minimal\", \"patience\" and \"histogram\""));
- /* clear out previous settings */
- DIFF_XDL_CLR(options, NEED_MINIMAL);
- options->xdl_opts &= ~XDF_DIFF_ALGORITHM_MASK;
- options->xdl_opts |= value;
+ options->ignore_driver_algorithm = 1;
+
+ return 0;
+}
+
+static int diff_opt_diff_algorithm_no_arg(const struct option *opt,
+ const char *arg, int unset)
+{
+ struct diff_options *options = opt->value;
+
+ BUG_ON_OPT_NEG(unset);
+ BUG_ON_OPT_ARG(arg);
+
+ if (set_diff_algorithm(options, opt->long_name))
+ BUG("available diff algorithms include \"myers\", "
+ "\"minimal\", \"patience\" and \"histogram\"");
+
+ options->ignore_driver_algorithm = 1;
+
return 0;
}
@@ -5256,7 +5291,6 @@ static int diff_opt_patience(const struct option *opt,
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
- options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF);
/*
* Both --patience and --anchored use PATIENCE_DIFF
* internally, so remove any anchors previously
@@ -5265,7 +5299,9 @@ static int diff_opt_patience(const struct option *opt,
for (i = 0; i < options->anchors_nr; i++)
free(options->anchors[i]);
options->anchors_nr = 0;
- return 0;
+ options->ignore_driver_algorithm = 1;
+
+ return set_diff_algorithm(options, "patience");
}
static int diff_opt_ignore_regex(const struct option *opt,
@@ -5415,7 +5451,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")),
@@ -5567,9 +5604,10 @@ static void prep_parse_options(struct diff_options *options)
N_("prevent rename/copy detection if the number of rename/copy targets exceeds given limit")),
OPT_GROUP(N_("Diff algorithm options")),
- OPT_BIT(0, "minimal", &options->xdl_opts,
- N_("produce the smallest possible diff"),
- XDF_NEED_MINIMAL),
+ OPT_CALLBACK_F(0, "minimal", options, NULL,
+ N_("produce the smallest possible diff"),
+ PARSE_OPT_NONEG | PARSE_OPT_NOARG,
+ diff_opt_diff_algorithm_no_arg),
OPT_BIT_F('w', "ignore-all-space", &options->xdl_opts,
N_("ignore whitespace when comparing lines"),
XDF_IGNORE_WHITESPACE, PARSE_OPT_NONEG),
@@ -5595,9 +5633,10 @@ static void prep_parse_options(struct diff_options *options)
N_("generate diff using the \"patience diff\" algorithm"),
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
diff_opt_patience),
- OPT_BITOP(0, "histogram", &options->xdl_opts,
- N_("generate diff using the \"histogram diff\" algorithm"),
- XDF_HISTOGRAM_DIFF, XDF_DIFF_ALGORITHM_MASK),
+ OPT_CALLBACK_F(0, "histogram", options, NULL,
+ N_("generate diff using the \"histogram diff\" algorithm"),
+ PARSE_OPT_NONEG | PARSE_OPT_NOARG,
+ diff_opt_diff_algorithm_no_arg),
OPT_CALLBACK_F(0, "diff-algorithm", options, N_("<algorithm>"),
N_("choose a diff algorithm"),
PARSE_OPT_NONEG, diff_opt_diff_algorithm),
@@ -5685,22 +5724,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;
}
@@ -6509,7 +6551,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 fd33cae..8d770b1 100644
--- a/diff.h
+++ b/diff.h
@@ -333,6 +333,7 @@ struct diff_options {
int prefix_length;
const char *stat_sep;
int xdl_opts;
+ int ignore_driver_algorithm;
/* see Documentation/diff-options.txt */
char **anchors;
@@ -394,7 +395,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 +539,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);
diff --git a/dir-iterator.c b/dir-iterator.c
index 3764dd8..cedd304 100644
--- a/dir-iterator.c
+++ b/dir-iterator.c
@@ -112,10 +112,7 @@ static int prepare_next_entry_data(struct dir_iterator_int *iter,
iter->base.basename = iter->base.path.buf +
iter->levels[iter->levels_nr - 1].prefix_len;
- if (iter->flags & DIR_ITERATOR_FOLLOW_SYMLINKS)
- err = stat(iter->base.path.buf, &iter->base.st);
- else
- err = lstat(iter->base.path.buf, &iter->base.st);
+ err = lstat(iter->base.path.buf, &iter->base.st);
saved_errno = errno;
if (err && errno != ENOENT)
@@ -213,13 +210,10 @@ struct dir_iterator *dir_iterator_begin(const char *path, unsigned int flags)
iter->flags = flags;
/*
- * Note: stat/lstat already checks for NULL or empty strings and
+ * Note: lstat already checks for NULL or empty strings and
* nonexistent paths.
*/
- if (iter->flags & DIR_ITERATOR_FOLLOW_SYMLINKS)
- err = stat(iter->base.path.buf, &iter->base.st);
- else
- err = lstat(iter->base.path.buf, &iter->base.st);
+ err = lstat(iter->base.path.buf, &iter->base.st);
if (err < 0) {
saved_errno = errno;
diff --git a/dir-iterator.h b/dir-iterator.h
index e3b6ff2..479e1ec 100644
--- a/dir-iterator.h
+++ b/dir-iterator.h
@@ -54,24 +54,8 @@
* and ITER_ERROR is returned immediately. In both cases, a meaningful
* warning is emitted. Note: ENOENT errors are always ignored so that
* the API users may remove files during iteration.
- *
- * - DIR_ITERATOR_FOLLOW_SYMLINKS: make dir-iterator follow symlinks.
- * i.e., linked directories' contents will be iterated over and
- * iter->base.st will contain information on the referred files,
- * not the symlinks themselves, which is the default behavior. Broken
- * symlinks are ignored.
- *
- * Note: setting DIR_ITERATOR_FOLLOW_SYMLINKS affects resolving the
- * starting path as well (e.g., attempting to iterate starting at a
- * symbolic link pointing to a directory without FOLLOW_SYMLINKS will
- * result in an error).
- *
- * Warning: circular symlinks are also followed when
- * DIR_ITERATOR_FOLLOW_SYMLINKS is set. The iteration may end up with
- * an ELOOP if they happen and DIR_ITERATOR_PEDANTIC is set.
*/
#define DIR_ITERATOR_PEDANTIC (1 << 0)
-#define DIR_ITERATOR_FOLLOW_SYMLINKS (1 << 1)
struct dir_iterator {
/* The current path: */
@@ -88,9 +72,7 @@ struct dir_iterator {
const char *basename;
/*
- * The result of calling lstat() on path; or stat(), if the
- * DIR_ITERATOR_FOLLOW_SYMLINKS flag was set at
- * dir_iterator's initialization.
+ * The result of calling lstat() on path.
*/
struct stat st;
};
diff --git a/dir.c b/dir.c
index fd689bb..9036337 100644
--- a/dir.c
+++ b/dir.c
@@ -3600,8 +3600,12 @@ static void free_untracked(struct untracked_cache_dir *ucd)
void free_untracked_cache(struct untracked_cache *uc)
{
- if (uc)
- free_untracked(uc->root);
+ if (!uc)
+ return;
+
+ free(uc->exclude_per_dir_to_free);
+ strbuf_release(&uc->ident);
+ free_untracked(uc->root);
free(uc);
}
@@ -3758,7 +3762,7 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long
next + offset + hashsz);
uc->dir_flags = get_be32(next + ouc_offset(dir_flags));
exclude_per_dir = (const char *)next + exclude_per_dir_offset;
- uc->exclude_per_dir = xstrdup(exclude_per_dir);
+ uc->exclude_per_dir = uc->exclude_per_dir_to_free = xstrdup(exclude_per_dir);
/* NUL after exclude_per_dir is covered by sizeof(*ouc) */
next += exclude_per_dir_offset + strlen(exclude_per_dir) + 1;
if (next >= end)
diff --git a/dir.h b/dir.h
index 62e89a0..264a6e0 100644
--- a/dir.h
+++ b/dir.h
@@ -188,6 +188,7 @@ struct untracked_cache {
struct oid_stat ss_info_exclude;
struct oid_stat ss_excludes_file;
const char *exclude_per_dir;
+ char *exclude_per_dir_to_free;
struct strbuf ident;
/*
* dir_struct#flags must match dir_flags or the untracked
diff --git a/entry.c b/entry.c
index 1d78e54..9e7dbe3 100644
--- a/entry.c
+++ b/entry.c
@@ -383,7 +383,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca
return error("cannot create submodule directory %s", path);
sub = submodule_from_ce(ce);
if (sub)
- return submodule_move_head(ce->name,
+ return submodule_move_head(ce->name, state->super_prefix,
NULL, oid_to_hex(&ce->oid),
state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);
break;
@@ -476,7 +476,7 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
* no pathname to return.
*/
BUG("Can't remove entry to a path");
- unlink_entry(ce);
+ unlink_entry(ce, state->super_prefix);
return 0;
}
@@ -510,10 +510,10 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
if (!(st.st_mode & S_IFDIR))
unlink_or_warn(ce->name);
- return submodule_move_head(ce->name,
+ return submodule_move_head(ce->name, state->super_prefix,
NULL, oid_to_hex(&ce->oid), 0);
} else
- return submodule_move_head(ce->name,
+ return submodule_move_head(ce->name, state->super_prefix,
"HEAD", oid_to_hex(&ce->oid),
state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);
}
@@ -574,12 +574,12 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
return write_entry(ce, path.buf, ca, state, 0, nr_checkouts);
}
-void unlink_entry(const struct cache_entry *ce)
+void unlink_entry(const struct cache_entry *ce, const char *super_prefix)
{
const struct submodule *sub = submodule_from_ce(ce);
if (sub) {
/* state.force is set at the caller. */
- submodule_move_head(ce->name, "HEAD", NULL,
+ submodule_move_head(ce->name, super_prefix, "HEAD", NULL,
SUBMODULE_MOVE_HEAD_FORCE);
}
if (check_leading_path(ce->name, ce_namelen(ce), 1) >= 0)
diff --git a/entry.h b/entry.h
index 9be4659..2d4fbb8 100644
--- a/entry.h
+++ b/entry.h
@@ -8,6 +8,7 @@ struct checkout {
struct index_state *istate;
const char *base_dir;
int base_dir_len;
+ const char *super_prefix;
struct delayed_checkout *delayed_checkout;
struct checkout_metadata meta;
unsigned force:1,
@@ -48,8 +49,11 @@ int finish_delayed_checkout(struct checkout *state, int show_progress);
/*
* Unlink the last component and schedule the leading directories for
* removal, such that empty directories get removed.
+ *
+ * The "super_prefix" is either NULL, or the "--super-prefix" passed
+ * down from "read-tree" et al.
*/
-void unlink_entry(const struct cache_entry *ce);
+void unlink_entry(const struct cache_entry *ce, const char *super_prefix);
void *read_blob_entry(const struct cache_entry *ce, size_t *size);
int fstat_checkout_output(int fd, const struct checkout *state, struct stat *st);
diff --git a/environment.c b/environment.c
index 18d042b..1ee3686 100644
--- a/environment.c
+++ b/environment.c
@@ -102,8 +102,6 @@ char *git_work_tree_cfg;
static char *git_namespace;
-static char *super_prefix;
-
/*
* Repository-local GIT_* environment variables; see cache.h for details.
*/
@@ -121,7 +119,6 @@ const char * const local_repo_env[] = {
NO_REPLACE_OBJECTS_ENVIRONMENT,
GIT_REPLACE_REF_BASE_ENVIRONMENT,
GIT_PREFIX_ENVIRONMENT,
- GIT_SUPER_PREFIX_ENVIRONMENT,
GIT_SHALLOW_FILE_ENVIRONMENT,
GIT_COMMON_DIR_ENVIRONMENT,
NULL
@@ -234,16 +231,6 @@ const char *strip_namespace(const char *namespaced_ref)
return NULL;
}
-const char *get_super_prefix(void)
-{
- static int initialized;
- if (!initialized) {
- super_prefix = xstrdup_or_null(getenv(GIT_SUPER_PREFIX_ENVIRONMENT));
- initialized = 1;
- }
- return super_prefix;
-}
-
static int git_work_tree_initialized;
/*
diff --git a/fsck.c b/fsck.c
index 47eaeed..2b18717 100644
--- a/fsck.c
+++ b/fsck.c
@@ -748,6 +748,23 @@ static int fsck_tree(const struct object_id *tree_oid,
return retval;
}
+/*
+ * Confirm that the headers of a commit or tag object end in a reasonable way,
+ * either with the usual "\n\n" separator, or at least with a trailing newline
+ * on the final header line.
+ *
+ * This property is important for the memory safety of our callers. It allows
+ * them to scan the buffer linewise without constantly checking the remaining
+ * size as long as:
+ *
+ * - they check that there are bytes left in the buffer at the start of any
+ * line (i.e., that the last newline they saw was not the final one we
+ * found here)
+ *
+ * - any intra-line scanning they do will stop at a newline, which will worst
+ * case hit the newline we found here as the end-of-header. This makes it
+ * OK for them to use helpers like parse_oid_hex(), or even skip_prefix().
+ */
static int verify_headers(const void *data, unsigned long size,
const struct object_id *oid, enum object_type type,
struct fsck_options *options)
@@ -808,6 +825,20 @@ static int fsck_ident(const char **ident,
if (*p != ' ')
return report(options, oid, type, FSCK_MSG_MISSING_SPACE_BEFORE_DATE, "invalid author/committer line - missing space before date");
p++;
+ /*
+ * Our timestamp parser is based on the C strto*() functions, which
+ * will happily eat whitespace, including the newline that is supposed
+ * to prevent us walking past the end of the buffer. So do our own
+ * scan, skipping linear whitespace but not newlines, and then
+ * confirming we found a digit. We _could_ be even more strict here,
+ * as we really expect only a single space, but since we have
+ * traditionally allowed extra whitespace, we'll continue to do so.
+ */
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (!isdigit(*p))
+ return report(options, oid, type, FSCK_MSG_BAD_DATE,
+ "invalid author/committer line - bad date");
if (*p == '0' && p[1] != ' ')
return report(options, oid, type, FSCK_MSG_ZERO_PADDED_DATE, "invalid author/committer line - zero-padded date");
if (date_overflows(parse_timestamp(p, &end, 10)))
@@ -834,12 +865,18 @@ static int fsck_commit(const struct object_id *oid,
unsigned author_count;
int err;
const char *buffer_begin = buffer;
+ const char *buffer_end = buffer + size;
const char *p;
+ /*
+ * We _must_ stop parsing immediately if this reports failure, as the
+ * memory safety of the rest of the function depends on it. See the
+ * comment above the definition of verify_headers() for more details.
+ */
if (verify_headers(buffer, size, oid, OBJ_COMMIT, options))
return -1;
- if (!skip_prefix(buffer, "tree ", &buffer))
+ if (buffer >= buffer_end || !skip_prefix(buffer, "tree ", &buffer))
return report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_TREE, "invalid format - expected 'tree' line");
if (parse_oid_hex(buffer, &tree_oid, &p) || *p != '\n') {
err = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_TREE_SHA1, "invalid 'tree' line format - bad sha1");
@@ -847,7 +884,7 @@ static int fsck_commit(const struct object_id *oid,
return err;
}
buffer = p + 1;
- while (skip_prefix(buffer, "parent ", &buffer)) {
+ while (buffer < buffer_end && skip_prefix(buffer, "parent ", &buffer)) {
if (parse_oid_hex(buffer, &parent_oid, &p) || *p != '\n') {
err = report(options, oid, OBJ_COMMIT, FSCK_MSG_BAD_PARENT_SHA1, "invalid 'parent' line format - bad sha1");
if (err)
@@ -856,7 +893,7 @@ static int fsck_commit(const struct object_id *oid,
buffer = p + 1;
}
author_count = 0;
- while (skip_prefix(buffer, "author ", &buffer)) {
+ while (buffer < buffer_end && skip_prefix(buffer, "author ", &buffer)) {
author_count++;
err = fsck_ident(&buffer, oid, OBJ_COMMIT, options);
if (err)
@@ -868,7 +905,7 @@ static int fsck_commit(const struct object_id *oid,
err = report(options, oid, OBJ_COMMIT, FSCK_MSG_MULTIPLE_AUTHORS, "invalid format - multiple 'author' lines");
if (err)
return err;
- if (!skip_prefix(buffer, "committer ", &buffer))
+ if (buffer >= buffer_end || !skip_prefix(buffer, "committer ", &buffer))
return report(options, oid, OBJ_COMMIT, FSCK_MSG_MISSING_COMMITTER, "invalid format - expected 'committer' line");
err = fsck_ident(&buffer, oid, OBJ_COMMIT, options);
if (err)
@@ -899,13 +936,19 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
int ret = 0;
char *eol;
struct strbuf sb = STRBUF_INIT;
+ const char *buffer_end = buffer + size;
const char *p;
+ /*
+ * We _must_ stop parsing immediately if this reports failure, as the
+ * memory safety of the rest of the function depends on it. See the
+ * comment above the definition of verify_headers() for more details.
+ */
ret = verify_headers(buffer, size, oid, OBJ_TAG, options);
if (ret)
goto done;
- if (!skip_prefix(buffer, "object ", &buffer)) {
+ if (buffer >= buffer_end || !skip_prefix(buffer, "object ", &buffer)) {
ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_OBJECT, "invalid format - expected 'object' line");
goto done;
}
@@ -916,11 +959,11 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
}
buffer = p + 1;
- if (!skip_prefix(buffer, "type ", &buffer)) {
+ if (buffer >= buffer_end || !skip_prefix(buffer, "type ", &buffer)) {
ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TYPE_ENTRY, "invalid format - expected 'type' line");
goto done;
}
- eol = strchr(buffer, '\n');
+ eol = memchr(buffer, '\n', buffer_end - buffer);
if (!eol) {
ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TYPE, "invalid format - unexpected end after 'type' line");
goto done;
@@ -932,11 +975,11 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
goto done;
buffer = eol + 1;
- if (!skip_prefix(buffer, "tag ", &buffer)) {
+ if (buffer >= buffer_end || !skip_prefix(buffer, "tag ", &buffer)) {
ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TAG_ENTRY, "invalid format - expected 'tag' line");
goto done;
}
- eol = strchr(buffer, '\n');
+ eol = memchr(buffer, '\n', buffer_end - buffer);
if (!eol) {
ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TAG, "invalid format - unexpected end after 'type' line");
goto done;
@@ -952,7 +995,7 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
}
buffer = eol + 1;
- if (!skip_prefix(buffer, "tagger ", &buffer)) {
+ if (buffer >= buffer_end || !skip_prefix(buffer, "tagger ", &buffer)) {
/* early tags do not contain 'tagger' lines; warn only */
ret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TAGGER_ENTRY, "invalid format - expected 'tagger' line");
if (ret)
@@ -960,10 +1003,8 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
}
else
ret = fsck_ident(&buffer, oid, OBJ_TAG, options);
- if (!*buffer)
- goto done;
- if (!starts_with(buffer, "\n")) {
+ if (buffer < buffer_end && !starts_with(buffer, "\n")) {
/*
* The verify_headers() check will allow
* e.g. "[...]tagger <tagger>\nsome
@@ -1237,19 +1278,26 @@ int fsck_object(struct object *obj, void *data, unsigned long size,
if (!obj)
return report(options, NULL, OBJ_NONE, FSCK_MSG_BAD_OBJECT_SHA1, "no valid object to fsck");
- if (obj->type == OBJ_BLOB)
- return fsck_blob(&obj->oid, data, size, options);
- if (obj->type == OBJ_TREE)
- return fsck_tree(&obj->oid, data, size, options);
- if (obj->type == OBJ_COMMIT)
- return fsck_commit(&obj->oid, data, size, options);
- if (obj->type == OBJ_TAG)
- return fsck_tag(&obj->oid, data, size, options);
+ return fsck_buffer(&obj->oid, obj->type, data, size, options);
+}
- return report(options, &obj->oid, obj->type,
+int fsck_buffer(const struct object_id *oid, enum object_type type,
+ void *data, unsigned long size,
+ struct fsck_options *options)
+{
+ if (type == OBJ_BLOB)
+ return fsck_blob(oid, data, size, options);
+ if (type == OBJ_TREE)
+ return fsck_tree(oid, data, size, options);
+ if (type == OBJ_COMMIT)
+ return fsck_commit(oid, data, size, options);
+ if (type == OBJ_TAG)
+ return fsck_tag(oid, data, size, options);
+
+ return report(options, oid, type,
FSCK_MSG_UNKNOWN_TYPE,
"unknown type '%d' (internal fsck error)",
- obj->type);
+ type);
}
int fsck_error_function(struct fsck_options *o,
diff --git a/fsck.h b/fsck.h
index fcecf41..6683308 100644
--- a/fsck.h
+++ b/fsck.h
@@ -184,6 +184,14 @@ int fsck_object(struct object *obj, void *data, unsigned long size,
struct fsck_options *options);
/*
+ * Same as fsck_object(), but for when the caller doesn't have an object
+ * struct.
+ */
+int fsck_buffer(const struct object_id *oid, enum object_type,
+ void *data, unsigned long size,
+ struct fsck_options *options);
+
+/*
* fsck a tag, and pass info about it back to the caller. This is
* exposed fsck_object() internals for git-mktag(1).
*/
diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c
index ee63a97..899bfe9 100644
--- a/fsmonitor-settings.c
+++ b/fsmonitor-settings.c
@@ -143,8 +143,6 @@ static void lookup_fsmonitor_settings(struct repository *r)
enum fsmonitor_mode fsm_settings__get_mode(struct repository *r)
{
- if (!r)
- r = the_repository;
if (!r->settings.fsmonitor)
lookup_fsmonitor_settings(r);
@@ -153,8 +151,6 @@ enum fsmonitor_mode fsm_settings__get_mode(struct repository *r)
const char *fsm_settings__get_hook_path(struct repository *r)
{
- if (!r)
- r = the_repository;
if (!r->settings.fsmonitor)
lookup_fsmonitor_settings(r);
@@ -174,8 +170,6 @@ void fsm_settings__set_ipc(struct repository *r)
* Caller requested IPC explicitly, so avoid (possibly
* recursive) config lookup.
*/
- if (!r)
- r = the_repository;
if (!r->settings.fsmonitor)
r->settings.fsmonitor = alloc_settings();
@@ -197,8 +191,6 @@ void fsm_settings__set_hook(struct repository *r, const char *path)
* Caller requested hook explicitly, so avoid (possibly
* recursive) config lookup.
*/
- if (!r)
- r = the_repository;
if (!r->settings.fsmonitor)
r->settings.fsmonitor = alloc_settings();
@@ -210,8 +202,6 @@ void fsm_settings__set_hook(struct repository *r, const char *path)
void fsm_settings__set_disabled(struct repository *r)
{
- if (!r)
- r = the_repository;
if (!r->settings.fsmonitor)
r->settings.fsmonitor = alloc_settings();
@@ -223,8 +213,6 @@ void fsm_settings__set_disabled(struct repository *r)
void fsm_settings__set_incompatible(struct repository *r,
enum fsmonitor_reason reason)
{
- if (!r)
- r = the_repository;
if (!r->settings.fsmonitor)
r->settings.fsmonitor = alloc_settings();
@@ -235,8 +223,6 @@ void fsm_settings__set_incompatible(struct repository *r,
enum fsmonitor_reason fsm_settings__get_reason(struct repository *r)
{
- if (!r)
- r = the_repository;
if (!r->settings.fsmonitor)
lookup_fsmonitor_settings(r);
diff --git a/fsmonitor.c b/fsmonitor.c
index 08af00c..a5b9e75 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -304,7 +304,7 @@ void refresh_fsmonitor(struct index_state *istate)
char *buf;
unsigned int i;
int is_trivial = 0;
- struct repository *r = istate->repo ? istate->repo : the_repository;
+ struct repository *r = istate->repo;
enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
enum fsmonitor_reason reason = fsm_settings__get_reason(r);
diff --git a/git-add--interactive.perl b/git-add--interactive.perl
deleted file mode 100755
index 95887fd..0000000
--- a/git-add--interactive.perl
+++ /dev/null
@@ -1,1920 +0,0 @@
-#!/usr/bin/perl
-
-use 5.008;
-use strict;
-use warnings;
-use Git qw(unquote_path);
-use Git::I18N;
-
-binmode(STDOUT, ":raw");
-
-my $repo = Git->repository();
-
-my $menu_use_color = $repo->get_colorbool('color.interactive');
-my ($prompt_color, $header_color, $help_color) =
- $menu_use_color ? (
- $repo->get_color('color.interactive.prompt', 'bold blue'),
- $repo->get_color('color.interactive.header', 'bold'),
- $repo->get_color('color.interactive.help', 'red bold'),
- ) : ();
-my $error_color = ();
-if ($menu_use_color) {
- my $help_color_spec = ($repo->config('color.interactive.help') or
- 'red bold');
- $error_color = $repo->get_color('color.interactive.error',
- $help_color_spec);
-}
-
-my $diff_use_color = $repo->get_colorbool('color.diff');
-my ($fraginfo_color) =
- $diff_use_color ? (
- $repo->get_color('color.diff.frag', 'cyan'),
- ) : ();
-my ($diff_context_color) =
- $diff_use_color ? (
- $repo->get_color($repo->config('color.diff.context') ? 'color.diff.context' : 'color.diff.plain', ''),
- ) : ();
-my ($diff_old_color) =
- $diff_use_color ? (
- $repo->get_color('color.diff.old', 'red'),
- ) : ();
-my ($diff_new_color) =
- $diff_use_color ? (
- $repo->get_color('color.diff.new', 'green'),
- ) : ();
-
-my $normal_color = $repo->get_color("", "reset");
-
-my $diff_algorithm = $repo->config('diff.algorithm');
-my $diff_filter = $repo->config('interactive.difffilter');
-
-my $use_readkey = 0;
-my $use_termcap = 0;
-my %term_escapes;
-
-sub ReadMode;
-sub ReadKey;
-if ($repo->config_bool("interactive.singlekey")) {
- eval {
- require Term::ReadKey;
- Term::ReadKey->import;
- $use_readkey = 1;
- };
- if (!$use_readkey) {
- print STDERR "missing Term::ReadKey, disabling interactive.singlekey\n";
- }
- eval {
- require Term::Cap;
- my $termcap = Term::Cap->Tgetent;
- foreach (values %$termcap) {
- $term_escapes{$_} = 1 if /^\e/;
- }
- $use_termcap = 1;
- };
-}
-
-sub colored {
- my $color = shift;
- my $string = join("", @_);
-
- if (defined $color) {
- # Put a color code at the beginning of each line, a reset at the end
- # color after newlines that are not at the end of the string
- $string =~ s/(\n+)(.)/$1$color$2/g;
- # reset before newlines
- $string =~ s/(\n+)/$normal_color$1/g;
- # codes at beginning and end (if necessary):
- $string =~ s/^/$color/;
- $string =~ s/$/$normal_color/ unless $string =~ /\n$/;
- }
- return $string;
-}
-
-# command line options
-my $patch_mode_only;
-my $patch_mode;
-my $patch_mode_revision;
-
-sub apply_patch;
-sub apply_patch_for_checkout_commit;
-sub apply_patch_for_stash;
-
-my %patch_modes = (
- 'stage' => {
- DIFF => 'diff-files -p',
- APPLY => sub { apply_patch 'apply --cached', @_; },
- APPLY_CHECK => 'apply --cached',
- FILTER => 'file-only',
- IS_REVERSE => 0,
- },
- 'stash' => {
- DIFF => 'diff-index -p HEAD',
- APPLY => sub { apply_patch 'apply --cached', @_; },
- APPLY_CHECK => 'apply --cached',
- FILTER => undef,
- IS_REVERSE => 0,
- },
- 'reset_head' => {
- DIFF => 'diff-index -p --cached',
- APPLY => sub { apply_patch 'apply -R --cached', @_; },
- APPLY_CHECK => 'apply -R --cached',
- FILTER => 'index-only',
- IS_REVERSE => 1,
- },
- 'reset_nothead' => {
- DIFF => 'diff-index -R -p --cached',
- APPLY => sub { apply_patch 'apply --cached', @_; },
- APPLY_CHECK => 'apply --cached',
- FILTER => 'index-only',
- IS_REVERSE => 0,
- },
- 'checkout_index' => {
- DIFF => 'diff-files -p',
- APPLY => sub { apply_patch 'apply -R', @_; },
- APPLY_CHECK => 'apply -R',
- FILTER => 'file-only',
- IS_REVERSE => 1,
- },
- 'checkout_head' => {
- DIFF => 'diff-index -p',
- APPLY => sub { apply_patch_for_checkout_commit '-R', @_ },
- APPLY_CHECK => 'apply -R',
- FILTER => undef,
- IS_REVERSE => 1,
- },
- 'checkout_nothead' => {
- DIFF => 'diff-index -R -p',
- APPLY => sub { apply_patch_for_checkout_commit '', @_ },
- APPLY_CHECK => 'apply',
- FILTER => undef,
- IS_REVERSE => 0,
- },
- 'worktree_head' => {
- DIFF => 'diff-index -p',
- APPLY => sub { apply_patch 'apply -R', @_ },
- APPLY_CHECK => 'apply -R',
- FILTER => undef,
- IS_REVERSE => 1,
- },
- 'worktree_nothead' => {
- DIFF => 'diff-index -R -p',
- APPLY => sub { apply_patch 'apply', @_ },
- APPLY_CHECK => 'apply',
- FILTER => undef,
- IS_REVERSE => 0,
- },
-);
-
-$patch_mode = 'stage';
-my %patch_mode_flavour = %{$patch_modes{$patch_mode}};
-
-sub run_cmd_pipe {
- if ($^O eq 'MSWin32') {
- my @invalid = grep {m/[":*]/} @_;
- die "$^O does not support: @invalid\n" if @invalid;
- my @args = map { m/ /o ? "\"$_\"": $_ } @_;
- return qx{@args};
- } else {
- my $fh = undef;
- open($fh, '-|', @_) or die;
- my @out = <$fh>;
- close $fh || die "Cannot close @_ ($!)";
- return @out;
- }
-}
-
-my ($GIT_DIR) = run_cmd_pipe(qw(git rev-parse --git-dir));
-
-if (!defined $GIT_DIR) {
- exit(1); # rev-parse would have already said "not a git repo"
-}
-chomp($GIT_DIR);
-
-sub refresh {
- my $fh;
- open $fh, 'git update-index --refresh |'
- or die;
- while (<$fh>) {
- ;# ignore 'needs update'
- }
- close $fh;
-}
-
-sub list_untracked {
- map {
- chomp $_;
- unquote_path($_);
- }
- run_cmd_pipe(qw(git ls-files --others --exclude-standard --), @ARGV);
-}
-
-# TRANSLATORS: you can adjust this to align "git add -i" status menu
-my $status_fmt = __('%12s %12s %s');
-my $status_head = sprintf($status_fmt, __('staged'), __('unstaged'), __('path'));
-
-{
- my $initial;
- sub is_initial_commit {
- $initial = system('git rev-parse HEAD -- >/dev/null 2>&1') != 0
- unless defined $initial;
- return $initial;
- }
-}
-
-{
- my $empty_tree;
- sub get_empty_tree {
- return $empty_tree if defined $empty_tree;
-
- ($empty_tree) = run_cmd_pipe(qw(git hash-object -t tree /dev/null));
- chomp $empty_tree;
- return $empty_tree;
- }
-}
-
-sub get_diff_reference {
- my $ref = shift;
- if (defined $ref and $ref ne 'HEAD') {
- return $ref;
- } elsif (is_initial_commit()) {
- return get_empty_tree();
- } else {
- return 'HEAD';
- }
-}
-
-# Returns list of hashes, contents of each of which are:
-# VALUE: pathname
-# BINARY: is a binary path
-# INDEX: is index different from HEAD?
-# FILE: is file different from index?
-# INDEX_ADDDEL: is it add/delete between HEAD and index?
-# FILE_ADDDEL: is it add/delete between index and file?
-# UNMERGED: is the path unmerged
-
-sub list_modified {
- my ($only) = @_;
- my (%data, @return);
- my ($add, $del, $adddel, $file);
-
- my $reference = get_diff_reference($patch_mode_revision);
- for (run_cmd_pipe(qw(git diff-index --cached
- --numstat --summary), $reference,
- '--', @ARGV)) {
- if (($add, $del, $file) =
- /^([-\d]+) ([-\d]+) (.*)/) {
- my ($change, $bin);
- $file = unquote_path($file);
- if ($add eq '-' && $del eq '-') {
- $change = __('binary');
- $bin = 1;
- }
- else {
- $change = "+$add/-$del";
- }
- $data{$file} = {
- INDEX => $change,
- BINARY => $bin,
- FILE => __('nothing'),
- }
- }
- elsif (($adddel, $file) =
- /^ (create|delete) mode [0-7]+ (.*)$/) {
- $file = unquote_path($file);
- $data{$file}{INDEX_ADDDEL} = $adddel;
- }
- }
-
- for (run_cmd_pipe(qw(git diff-files --ignore-submodules=dirty --numstat --summary --raw --), @ARGV)) {
- if (($add, $del, $file) =
- /^([-\d]+) ([-\d]+) (.*)/) {
- $file = unquote_path($file);
- my ($change, $bin);
- if ($add eq '-' && $del eq '-') {
- $change = __('binary');
- $bin = 1;
- }
- else {
- $change = "+$add/-$del";
- }
- $data{$file}{FILE} = $change;
- if ($bin) {
- $data{$file}{BINARY} = 1;
- }
- }
- elsif (($adddel, $file) =
- /^ (create|delete) mode [0-7]+ (.*)$/) {
- $file = unquote_path($file);
- $data{$file}{FILE_ADDDEL} = $adddel;
- }
- elsif (/^:[0-7]+ [0-7]+ [0-9a-f]+ [0-9a-f]+ (.) (.*)$/) {
- $file = unquote_path($2);
- if (!exists $data{$file}) {
- $data{$file} = +{
- INDEX => __('unchanged'),
- BINARY => 0,
- };
- }
- if ($1 eq 'U') {
- $data{$file}{UNMERGED} = 1;
- }
- }
- }
-
- for (sort keys %data) {
- my $it = $data{$_};
-
- if ($only) {
- if ($only eq 'index-only') {
- next if ($it->{INDEX} eq __('unchanged'));
- }
- if ($only eq 'file-only') {
- next if ($it->{FILE} eq __('nothing'));
- }
- }
- push @return, +{
- VALUE => $_,
- %$it,
- };
- }
- return @return;
-}
-
-sub find_unique {
- my ($string, @stuff) = @_;
- my $found = undef;
- for (my $i = 0; $i < @stuff; $i++) {
- my $it = $stuff[$i];
- my $hit = undef;
- if (ref $it) {
- if ((ref $it) eq 'ARRAY') {
- $it = $it->[0];
- }
- else {
- $it = $it->{VALUE};
- }
- }
- eval {
- if ($it =~ /^$string/) {
- $hit = 1;
- };
- };
- if (defined $hit && defined $found) {
- return undef;
- }
- if ($hit) {
- $found = $i + 1;
- }
- }
- return $found;
-}
-
-# inserts string into trie and updates count for each character
-sub update_trie {
- my ($trie, $string) = @_;
- foreach (split //, $string) {
- $trie = $trie->{$_} ||= {COUNT => 0};
- $trie->{COUNT}++;
- }
-}
-
-# returns an array of tuples (prefix, remainder)
-sub find_unique_prefixes {
- my @stuff = @_;
- my @return = ();
-
- # any single prefix exceeding the soft limit is omitted
- # if any prefix exceeds the hard limit all are omitted
- # 0 indicates no limit
- my $soft_limit = 0;
- my $hard_limit = 3;
-
- # build a trie modelling all possible options
- my %trie;
- foreach my $print (@stuff) {
- if ((ref $print) eq 'ARRAY') {
- $print = $print->[0];
- }
- elsif ((ref $print) eq 'HASH') {
- $print = $print->{VALUE};
- }
- update_trie(\%trie, $print);
- push @return, $print;
- }
-
- # use the trie to find the unique prefixes
- for (my $i = 0; $i < @return; $i++) {
- my $ret = $return[$i];
- my @letters = split //, $ret;
- my %search = %trie;
- my ($prefix, $remainder);
- my $j;
- for ($j = 0; $j < @letters; $j++) {
- my $letter = $letters[$j];
- if ($search{$letter}{COUNT} == 1) {
- $prefix = substr $ret, 0, $j + 1;
- $remainder = substr $ret, $j + 1;
- last;
- }
- else {
- my $prefix = substr $ret, 0, $j;
- return ()
- if ($hard_limit && $j + 1 > $hard_limit);
- }
- %search = %{$search{$letter}};
- }
- if (ord($letters[0]) > 127 ||
- ($soft_limit && $j + 1 > $soft_limit)) {
- $prefix = undef;
- $remainder = $ret;
- }
- $return[$i] = [$prefix, $remainder];
- }
- return @return;
-}
-
-# filters out prefixes which have special meaning to list_and_choose()
-sub is_valid_prefix {
- my $prefix = shift;
- return (defined $prefix) &&
- !($prefix =~ /[\s,]/) && # separators
- !($prefix =~ /^-/) && # deselection
- !($prefix =~ /^\d+/) && # selection
- ($prefix ne '*') && # "all" wildcard
- ($prefix ne '?'); # prompt help
-}
-
-# given a prefix/remainder tuple return a string with the prefix highlighted
-# for now use square brackets; later might use ANSI colors (underline, bold)
-sub highlight_prefix {
- my $prefix = shift;
- my $remainder = shift;
-
- if (!defined $prefix) {
- return $remainder;
- }
-
- if (!is_valid_prefix($prefix)) {
- return "$prefix$remainder";
- }
-
- if (!$menu_use_color) {
- return "[$prefix]$remainder";
- }
-
- return "$prompt_color$prefix$normal_color$remainder";
-}
-
-sub error_msg {
- print STDERR colored $error_color, @_;
-}
-
-sub list_and_choose {
- my ($opts, @stuff) = @_;
- my (@chosen, @return);
- if (!@stuff) {
- return @return;
- }
- my $i;
- my @prefixes = find_unique_prefixes(@stuff) unless $opts->{LIST_ONLY};
-
- TOPLOOP:
- while (1) {
- my $last_lf = 0;
-
- if ($opts->{HEADER}) {
- my $indent = $opts->{LIST_FLAT} ? "" : " ";
- print colored $header_color, "$indent$opts->{HEADER}\n";
- }
- for ($i = 0; $i < @stuff; $i++) {
- my $chosen = $chosen[$i] ? '*' : ' ';
- my $print = $stuff[$i];
- my $ref = ref $print;
- my $highlighted = highlight_prefix(@{$prefixes[$i]})
- if @prefixes;
- if ($ref eq 'ARRAY') {
- $print = $highlighted || $print->[0];
- }
- elsif ($ref eq 'HASH') {
- my $value = $highlighted || $print->{VALUE};
- $print = sprintf($status_fmt,
- $print->{INDEX},
- $print->{FILE},
- $value);
- }
- else {
- $print = $highlighted || $print;
- }
- printf("%s%2d: %s", $chosen, $i+1, $print);
- if (($opts->{LIST_FLAT}) &&
- (($i + 1) % ($opts->{LIST_FLAT}))) {
- print "\t";
- $last_lf = 0;
- }
- else {
- print "\n";
- $last_lf = 1;
- }
- }
- if (!$last_lf) {
- print "\n";
- }
-
- return if ($opts->{LIST_ONLY});
-
- print colored $prompt_color, $opts->{PROMPT};
- if ($opts->{SINGLETON}) {
- print "> ";
- }
- else {
- print ">> ";
- }
- my $line = <STDIN>;
- if (!$line) {
- print "\n";
- $opts->{ON_EOF}->() if $opts->{ON_EOF};
- last;
- }
- chomp $line;
- last if $line eq '';
- if ($line eq '?') {
- $opts->{SINGLETON} ?
- singleton_prompt_help_cmd() :
- prompt_help_cmd();
- next TOPLOOP;
- }
- for my $choice (split(/[\s,]+/, $line)) {
- my $choose = 1;
- my ($bottom, $top);
-
- # Input that begins with '-'; unchoose
- if ($choice =~ s/^-//) {
- $choose = 0;
- }
- # A range can be specified like 5-7 or 5-.
- if ($choice =~ /^(\d+)-(\d*)$/) {
- ($bottom, $top) = ($1, length($2) ? $2 : 1 + @stuff);
- }
- elsif ($choice =~ /^\d+$/) {
- $bottom = $top = $choice;
- }
- elsif ($choice eq '*') {
- $bottom = 1;
- $top = 1 + @stuff;
- }
- else {
- $bottom = $top = find_unique($choice, @stuff);
- if (!defined $bottom) {
- error_msg sprintf(__("Huh (%s)?\n"), $choice);
- next TOPLOOP;
- }
- }
- if ($opts->{SINGLETON} && $bottom != $top) {
- error_msg sprintf(__("Huh (%s)?\n"), $choice);
- next TOPLOOP;
- }
- for ($i = $bottom-1; $i <= $top-1; $i++) {
- next if (@stuff <= $i || $i < 0);
- $chosen[$i] = $choose;
- }
- }
- last if ($opts->{IMMEDIATE} || $line eq '*');
- }
- for ($i = 0; $i < @stuff; $i++) {
- if ($chosen[$i]) {
- push @return, $stuff[$i];
- }
- }
- return @return;
-}
-
-sub singleton_prompt_help_cmd {
- print colored $help_color, __ <<'EOF' ;
-Prompt help:
-1 - select a numbered item
-foo - select item based on unique prefix
- - (empty) select nothing
-EOF
-}
-
-sub prompt_help_cmd {
- print colored $help_color, __ <<'EOF' ;
-Prompt help:
-1 - select a single item
-3-5 - select a range of items
-2-3,6-9 - select multiple ranges
-foo - select item based on unique prefix
--... - unselect specified items
-* - choose all items
- - (empty) finish selecting
-EOF
-}
-
-sub status_cmd {
- list_and_choose({ LIST_ONLY => 1, HEADER => $status_head },
- list_modified());
- print "\n";
-}
-
-sub say_n_paths {
- my $did = shift @_;
- my $cnt = scalar @_;
- if ($did eq 'added') {
- printf(__n("added %d path\n", "added %d paths\n",
- $cnt), $cnt);
- } elsif ($did eq 'updated') {
- printf(__n("updated %d path\n", "updated %d paths\n",
- $cnt), $cnt);
- } elsif ($did eq 'reverted') {
- printf(__n("reverted %d path\n", "reverted %d paths\n",
- $cnt), $cnt);
- } else {
- printf(__n("touched %d path\n", "touched %d paths\n",
- $cnt), $cnt);
- }
-}
-
-sub update_cmd {
- my @mods = list_modified('file-only');
- return if (!@mods);
-
- my @update = list_and_choose({ PROMPT => __('Update'),
- HEADER => $status_head, },
- @mods);
- if (@update) {
- system(qw(git update-index --add --remove --),
- map { $_->{VALUE} } @update);
- say_n_paths('updated', @update);
- }
- print "\n";
-}
-
-sub revert_cmd {
- my @update = list_and_choose({ PROMPT => __('Revert'),
- HEADER => $status_head, },
- list_modified());
- if (@update) {
- if (is_initial_commit()) {
- system(qw(git rm --cached),
- map { $_->{VALUE} } @update);
- }
- else {
- my @lines = run_cmd_pipe(qw(git ls-tree HEAD --),
- map { $_->{VALUE} } @update);
- my $fh;
- open $fh, '| git update-index --index-info'
- or die;
- for (@lines) {
- print $fh $_;
- }
- close($fh);
- for (@update) {
- if ($_->{INDEX_ADDDEL} &&
- $_->{INDEX_ADDDEL} eq 'create') {
- system(qw(git update-index --force-remove --),
- $_->{VALUE});
- printf(__("note: %s is untracked now.\n"), $_->{VALUE});
- }
- }
- }
- refresh();
- say_n_paths('reverted', @update);
- }
- print "\n";
-}
-
-sub add_untracked_cmd {
- my @add = list_and_choose({ PROMPT => __('Add untracked') },
- list_untracked());
- if (@add) {
- system(qw(git update-index --add --), @add);
- say_n_paths('added', @add);
- } else {
- print __("No untracked files.\n");
- }
- print "\n";
-}
-
-sub run_git_apply {
- my $cmd = shift;
- my $fh;
- open $fh, '| git ' . $cmd . " --allow-overlap";
- print $fh @_;
- return close $fh;
-}
-
-sub parse_diff {
- my ($path) = @_;
- my @diff_cmd = split(" ", $patch_mode_flavour{DIFF});
- if (defined $diff_algorithm) {
- splice @diff_cmd, 1, 0, "--diff-algorithm=${diff_algorithm}";
- }
- if (defined $patch_mode_revision) {
- push @diff_cmd, get_diff_reference($patch_mode_revision);
- }
- my @diff = run_cmd_pipe("git", @diff_cmd, qw(--no-color --), $path);
- my @colored = ();
- if ($diff_use_color) {
- my @display_cmd = ("git", @diff_cmd, qw(--color --), $path);
- if (defined $diff_filter) {
- # quotemeta is overkill, but sufficient for shell-quoting
- my $diff = join(' ', map { quotemeta } @display_cmd);
- @display_cmd = ("$diff | $diff_filter");
- }
-
- @colored = run_cmd_pipe(@display_cmd);
- }
- my (@hunk) = { TEXT => [], DISPLAY => [], TYPE => 'header' };
-
- if (@colored && @colored != @diff) {
- print STDERR
- "fatal: mismatched output from interactive.diffFilter\n",
- "hint: Your filter must maintain a one-to-one correspondence\n",
- "hint: between its input and output lines.\n";
- exit 1;
- }
-
- for (my $i = 0; $i < @diff; $i++) {
- if ($diff[$i] =~ /^@@ /) {
- push @hunk, { TEXT => [], DISPLAY => [],
- TYPE => 'hunk' };
- }
- push @{$hunk[-1]{TEXT}}, $diff[$i];
- push @{$hunk[-1]{DISPLAY}},
- (@colored ? $colored[$i] : $diff[$i]);
- }
- return @hunk;
-}
-
-sub parse_diff_header {
- my $src = shift;
-
- my $head = { TEXT => [], DISPLAY => [], TYPE => 'header' };
- my $mode = { TEXT => [], DISPLAY => [], TYPE => 'mode' };
- my $deletion = { TEXT => [], DISPLAY => [], TYPE => 'deletion' };
- my $addition;
-
- for (my $i = 0; $i < @{$src->{TEXT}}; $i++) {
- if ($src->{TEXT}->[$i] =~ /^new file/) {
- $addition = 1;
- $head->{TYPE} = 'addition';
- }
- my $dest =
- $src->{TEXT}->[$i] =~ /^(old|new) mode (\d+)$/ ? $mode :
- $src->{TEXT}->[$i] =~ /^deleted file/ ? $deletion :
- $head;
- push @{$dest->{TEXT}}, $src->{TEXT}->[$i];
- push @{$dest->{DISPLAY}}, $src->{DISPLAY}->[$i];
- }
- return ($head, $mode, $deletion, $addition);
-}
-
-sub hunk_splittable {
- my ($text) = @_;
-
- my @s = split_hunk($text);
- return (1 < @s);
-}
-
-sub parse_hunk_header {
- my ($line) = @_;
- my ($o_ofs, $o_cnt, $n_ofs, $n_cnt) =
- $line =~ /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
- $o_cnt = 1 unless defined $o_cnt;
- $n_cnt = 1 unless defined $n_cnt;
- return ($o_ofs, $o_cnt, $n_ofs, $n_cnt);
-}
-
-sub format_hunk_header {
- my ($o_ofs, $o_cnt, $n_ofs, $n_cnt) = @_;
- return ("@@ -$o_ofs" .
- (($o_cnt != 1) ? ",$o_cnt" : '') .
- " +$n_ofs" .
- (($n_cnt != 1) ? ",$n_cnt" : '') .
- " @@\n");
-}
-
-sub split_hunk {
- my ($text, $display) = @_;
- my @split = ();
- if (!defined $display) {
- $display = $text;
- }
- # If there are context lines in the middle of a hunk,
- # it can be split, but we would need to take care of
- # overlaps later.
-
- my ($o_ofs, undef, $n_ofs) = parse_hunk_header($text->[0]);
- my $hunk_start = 1;
-
- OUTER:
- while (1) {
- my $next_hunk_start = undef;
- my $i = $hunk_start - 1;
- my $this = +{
- TEXT => [],
- DISPLAY => [],
- TYPE => 'hunk',
- OLD => $o_ofs,
- NEW => $n_ofs,
- OCNT => 0,
- NCNT => 0,
- ADDDEL => 0,
- POSTCTX => 0,
- USE => undef,
- };
-
- while (++$i < @$text) {
- my $line = $text->[$i];
- my $display = $display->[$i];
- if ($line =~ /^\\/) {
- push @{$this->{TEXT}}, $line;
- push @{$this->{DISPLAY}}, $display;
- next;
- }
- if ($line =~ /^ /) {
- if ($this->{ADDDEL} &&
- !defined $next_hunk_start) {
- # We have seen leading context and
- # adds/dels and then here is another
- # context, which is trailing for this
- # split hunk and leading for the next
- # one.
- $next_hunk_start = $i;
- }
- push @{$this->{TEXT}}, $line;
- push @{$this->{DISPLAY}}, $display;
- $this->{OCNT}++;
- $this->{NCNT}++;
- if (defined $next_hunk_start) {
- $this->{POSTCTX}++;
- }
- next;
- }
-
- # add/del
- if (defined $next_hunk_start) {
- # We are done with the current hunk and
- # this is the first real change for the
- # next split one.
- $hunk_start = $next_hunk_start;
- $o_ofs = $this->{OLD} + $this->{OCNT};
- $n_ofs = $this->{NEW} + $this->{NCNT};
- $o_ofs -= $this->{POSTCTX};
- $n_ofs -= $this->{POSTCTX};
- push @split, $this;
- redo OUTER;
- }
- push @{$this->{TEXT}}, $line;
- push @{$this->{DISPLAY}}, $display;
- $this->{ADDDEL}++;
- if ($line =~ /^-/) {
- $this->{OCNT}++;
- }
- else {
- $this->{NCNT}++;
- }
- }
-
- push @split, $this;
- last;
- }
-
- for my $hunk (@split) {
- $o_ofs = $hunk->{OLD};
- $n_ofs = $hunk->{NEW};
- my $o_cnt = $hunk->{OCNT};
- my $n_cnt = $hunk->{NCNT};
-
- my $head = format_hunk_header($o_ofs, $o_cnt, $n_ofs, $n_cnt);
- my $display_head = $head;
- unshift @{$hunk->{TEXT}}, $head;
- if ($diff_use_color) {
- $display_head = colored($fraginfo_color, $head);
- }
- unshift @{$hunk->{DISPLAY}}, $display_head;
- }
- return @split;
-}
-
-sub find_last_o_ctx {
- my ($it) = @_;
- my $text = $it->{TEXT};
- my ($o_ofs, $o_cnt) = parse_hunk_header($text->[0]);
- my $i = @{$text};
- my $last_o_ctx = $o_ofs + $o_cnt;
- while (0 < --$i) {
- my $line = $text->[$i];
- if ($line =~ /^ /) {
- $last_o_ctx--;
- next;
- }
- last;
- }
- return $last_o_ctx;
-}
-
-sub merge_hunk {
- my ($prev, $this) = @_;
- my ($o0_ofs, $o0_cnt, $n0_ofs, $n0_cnt) =
- parse_hunk_header($prev->{TEXT}[0]);
- my ($o1_ofs, $o1_cnt, $n1_ofs, $n1_cnt) =
- parse_hunk_header($this->{TEXT}[0]);
-
- my (@line, $i, $ofs, $o_cnt, $n_cnt);
- $ofs = $o0_ofs;
- $o_cnt = $n_cnt = 0;
- for ($i = 1; $i < @{$prev->{TEXT}}; $i++) {
- my $line = $prev->{TEXT}[$i];
- if ($line =~ /^\+/) {
- $n_cnt++;
- push @line, $line;
- next;
- } elsif ($line =~ /^\\/) {
- push @line, $line;
- next;
- }
-
- last if ($o1_ofs <= $ofs);
-
- $o_cnt++;
- $ofs++;
- if ($line =~ /^ /) {
- $n_cnt++;
- }
- push @line, $line;
- }
-
- for ($i = 1; $i < @{$this->{TEXT}}; $i++) {
- my $line = $this->{TEXT}[$i];
- if ($line =~ /^\+/) {
- $n_cnt++;
- push @line, $line;
- next;
- } elsif ($line =~ /^\\/) {
- push @line, $line;
- next;
- }
- $ofs++;
- $o_cnt++;
- if ($line =~ /^ /) {
- $n_cnt++;
- }
- push @line, $line;
- }
- my $head = format_hunk_header($o0_ofs, $o_cnt, $n0_ofs, $n_cnt);
- @{$prev->{TEXT}} = ($head, @line);
-}
-
-sub coalesce_overlapping_hunks {
- my (@in) = @_;
- my @out = ();
-
- my ($last_o_ctx, $last_was_dirty);
- my $ofs_delta = 0;
-
- for (@in) {
- if ($_->{TYPE} ne 'hunk') {
- push @out, $_;
- next;
- }
- my $text = $_->{TEXT};
- my ($o_ofs, $o_cnt, $n_ofs, $n_cnt) =
- parse_hunk_header($text->[0]);
- unless ($_->{USE}) {
- $ofs_delta += $o_cnt - $n_cnt;
- # If this hunk has been edited then subtract
- # the delta that is due to the edit.
- if ($_->{OFS_DELTA}) {
- $ofs_delta -= $_->{OFS_DELTA};
- }
- next;
- }
- if ($ofs_delta) {
- if ($patch_mode_flavour{IS_REVERSE}) {
- $o_ofs -= $ofs_delta;
- } else {
- $n_ofs += $ofs_delta;
- }
- $_->{TEXT}->[0] = format_hunk_header($o_ofs, $o_cnt,
- $n_ofs, $n_cnt);
- }
- # If this hunk was edited then adjust the offset delta
- # to reflect the edit.
- if ($_->{OFS_DELTA}) {
- $ofs_delta += $_->{OFS_DELTA};
- }
- if (defined $last_o_ctx &&
- $o_ofs <= $last_o_ctx &&
- !$_->{DIRTY} &&
- !$last_was_dirty) {
- merge_hunk($out[-1], $_);
- }
- else {
- push @out, $_;
- }
- $last_o_ctx = find_last_o_ctx($out[-1]);
- $last_was_dirty = $_->{DIRTY};
- }
- return @out;
-}
-
-sub reassemble_patch {
- my $head = shift;
- my @patch;
-
- # Include everything in the header except the beginning of the diff.
- push @patch, (grep { !/^[-+]{3}/ } @$head);
-
- # Then include any headers from the hunk lines, which must
- # come before any actual hunk.
- while (@_ && $_[0] !~ /^@/) {
- push @patch, shift;
- }
-
- # Then begin the diff.
- push @patch, grep { /^[-+]{3}/ } @$head;
-
- # And then the actual hunks.
- push @patch, @_;
-
- return @patch;
-}
-
-sub color_diff {
- return map {
- colored((/^@/ ? $fraginfo_color :
- /^\+/ ? $diff_new_color :
- /^-/ ? $diff_old_color :
- $diff_context_color),
- $_);
- } @_;
-}
-
-my %edit_hunk_manually_modes = (
- stage => N__(
-"If the patch applies cleanly, the edited hunk will immediately be
-marked for staging."),
- stash => N__(
-"If the patch applies cleanly, the edited hunk will immediately be
-marked for stashing."),
- reset_head => N__(
-"If the patch applies cleanly, the edited hunk will immediately be
-marked for unstaging."),
- reset_nothead => N__(
-"If the patch applies cleanly, the edited hunk will immediately be
-marked for applying."),
- checkout_index => N__(
-"If the patch applies cleanly, the edited hunk will immediately be
-marked for discarding."),
- checkout_head => N__(
-"If the patch applies cleanly, the edited hunk will immediately be
-marked for discarding."),
- checkout_nothead => N__(
-"If the patch applies cleanly, the edited hunk will immediately be
-marked for applying."),
- worktree_head => N__(
-"If the patch applies cleanly, the edited hunk will immediately be
-marked for discarding."),
- worktree_nothead => N__(
-"If the patch applies cleanly, the edited hunk will immediately be
-marked for applying."),
-);
-
-sub recount_edited_hunk {
- local $_;
- my ($oldtext, $newtext) = @_;
- my ($o_cnt, $n_cnt) = (0, 0);
- for (@{$newtext}[1..$#{$newtext}]) {
- my $mode = substr($_, 0, 1);
- if ($mode eq '-') {
- $o_cnt++;
- } elsif ($mode eq '+') {
- $n_cnt++;
- } elsif ($mode eq ' ' or $mode eq "\n") {
- $o_cnt++;
- $n_cnt++;
- }
- }
- my ($o_ofs, undef, $n_ofs, undef) =
- parse_hunk_header($newtext->[0]);
- $newtext->[0] = format_hunk_header($o_ofs, $o_cnt, $n_ofs, $n_cnt);
- my (undef, $orig_o_cnt, undef, $orig_n_cnt) =
- parse_hunk_header($oldtext->[0]);
- # Return the change in the number of lines inserted by this hunk
- return $orig_o_cnt - $orig_n_cnt - $o_cnt + $n_cnt;
-}
-
-sub edit_hunk_manually {
- my ($oldtext) = @_;
-
- my $hunkfile = $repo->repo_path . "/addp-hunk-edit.diff";
- my $fh;
- open $fh, '>', $hunkfile
- or die sprintf(__("failed to open hunk edit file for writing: %s"), $!);
- print $fh Git::comment_lines __("Manual hunk edit mode -- see bottom for a quick guide.\n");
- print $fh @$oldtext;
- my $is_reverse = $patch_mode_flavour{IS_REVERSE};
- my ($remove_plus, $remove_minus) = $is_reverse ? ('-', '+') : ('+', '-');
- my $comment_line_char = Git::get_comment_line_char;
- print $fh Git::comment_lines sprintf(__ <<EOF, $remove_minus, $remove_plus, $comment_line_char),
----
-To remove '%s' lines, make them ' ' lines (context).
-To remove '%s' lines, delete them.
-Lines starting with %s will be removed.
-EOF
-__($edit_hunk_manually_modes{$patch_mode}),
-# TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
-__ <<EOF2 ;
-If it does not apply cleanly, you will be given an opportunity to
-edit again. If all lines of the hunk are removed, then the edit is
-aborted and the hunk is left unchanged.
-EOF2
- close $fh;
-
- chomp(my ($editor) = run_cmd_pipe(qw(git var GIT_EDITOR)));
- system('sh', '-c', $editor.' "$@"', $editor, $hunkfile);
-
- if ($? != 0) {
- return undef;
- }
-
- open $fh, '<', $hunkfile
- or die sprintf(__("failed to open hunk edit file for reading: %s"), $!);
- my @newtext = grep { !/^\Q$comment_line_char\E/ } <$fh>;
- close $fh;
- unlink $hunkfile;
-
- # Abort if nothing remains
- if (!grep { /\S/ } @newtext) {
- return undef;
- }
-
- # Reinsert the first hunk header if the user accidentally deleted it
- if ($newtext[0] !~ /^@/) {
- unshift @newtext, $oldtext->[0];
- }
- return \@newtext;
-}
-
-sub diff_applies {
- return run_git_apply($patch_mode_flavour{APPLY_CHECK} . ' --check',
- map { @{$_->{TEXT}} } @_);
-}
-
-sub _restore_terminal_and_die {
- ReadMode 'restore';
- print "\n";
- exit 1;
-}
-
-sub prompt_single_character {
- if ($use_readkey) {
- local $SIG{TERM} = \&_restore_terminal_and_die;
- local $SIG{INT} = \&_restore_terminal_and_die;
- ReadMode 'cbreak';
- my $key = ReadKey 0;
- ReadMode 'restore';
- if (defined $key) {
- if ($use_termcap and $key eq "\e") {
- while (!defined $term_escapes{$key}) {
- my $next = ReadKey 0.5;
- last if (!defined $next);
- $key .= $next;
- }
- $key =~ s/\e/^[/;
- }
- print "$key";
- }
- print "\n";
- return $key;
- } else {
- return <STDIN>;
- }
-}
-
-sub prompt_yesno {
- my ($prompt) = @_;
- while (1) {
- print colored $prompt_color, $prompt;
- my $line = prompt_single_character;
- return undef unless defined $line;
- return 0 if $line =~ /^n/i;
- return 1 if $line =~ /^y/i;
- }
-}
-
-sub edit_hunk_loop {
- my ($head, $hunks, $ix) = @_;
- my $hunk = $hunks->[$ix];
- my $text = $hunk->{TEXT};
-
- while (1) {
- my $newtext = edit_hunk_manually($text);
- if (!defined $newtext) {
- return undef;
- }
- my $newhunk = {
- TEXT => $newtext,
- TYPE => $hunk->{TYPE},
- USE => 1,
- DIRTY => 1,
- };
- $newhunk->{OFS_DELTA} = recount_edited_hunk($text, $newtext);
- # If this hunk has already been edited then add the
- # offset delta of the previous edit to get the real
- # delta from the original unedited hunk.
- $hunk->{OFS_DELTA} and
- $newhunk->{OFS_DELTA} += $hunk->{OFS_DELTA};
- if (diff_applies($head,
- @{$hunks}[0..$ix-1],
- $newhunk,
- @{$hunks}[$ix+1..$#{$hunks}])) {
- $newhunk->{DISPLAY} = [color_diff(@{$newtext})];
- return $newhunk;
- }
- else {
- prompt_yesno(
- # TRANSLATORS: do not translate [y/n]
- # The program will only accept that input
- # at this point.
- # Consider translating (saying "no" discards!) as
- # (saying "n" for "no" discards!) if the translation
- # of the word "no" does not start with n.
- __('Your edited hunk does not apply. Edit again '
- . '(saying "no" discards!) [y/n]? ')
- ) or return undef;
- }
- }
-}
-
-my %help_patch_modes = (
- stage => N__(
-"y - stage this hunk
-n - do not stage this hunk
-q - quit; do not stage this hunk or any of the remaining ones
-a - stage this hunk and all later hunks in the file
-d - do not stage this hunk or any of the later hunks in the file"),
- stash => N__(
-"y - stash this hunk
-n - do not stash this hunk
-q - quit; do not stash this hunk or any of the remaining ones
-a - stash this hunk and all later hunks in the file
-d - do not stash this hunk or any of the later hunks in the file"),
- reset_head => N__(
-"y - unstage this hunk
-n - do not unstage this hunk
-q - quit; do not unstage this hunk or any of the remaining ones
-a - unstage this hunk and all later hunks in the file
-d - do not unstage this hunk or any of the later hunks in the file"),
- reset_nothead => N__(
-"y - apply this hunk to index
-n - do not apply this hunk to index
-q - quit; do not apply this hunk or any of the remaining ones
-a - apply this hunk and all later hunks in the file
-d - do not apply this hunk or any of the later hunks in the file"),
- checkout_index => N__(
-"y - discard this hunk from worktree
-n - do not discard this hunk from worktree
-q - quit; do not discard this hunk or any of the remaining ones
-a - discard this hunk and all later hunks in the file
-d - do not discard this hunk or any of the later hunks in the file"),
- checkout_head => N__(
-"y - discard this hunk from index and worktree
-n - do not discard this hunk from index and worktree
-q - quit; do not discard this hunk or any of the remaining ones
-a - discard this hunk and all later hunks in the file
-d - do not discard this hunk or any of the later hunks in the file"),
- checkout_nothead => N__(
-"y - apply this hunk to index and worktree
-n - do not apply this hunk to index and worktree
-q - quit; do not apply this hunk or any of the remaining ones
-a - apply this hunk and all later hunks in the file
-d - do not apply this hunk or any of the later hunks in the file"),
- worktree_head => N__(
-"y - discard this hunk from worktree
-n - do not discard this hunk from worktree
-q - quit; do not discard this hunk or any of the remaining ones
-a - discard this hunk and all later hunks in the file
-d - do not discard this hunk or any of the later hunks in the file"),
- worktree_nothead => N__(
-"y - apply this hunk to worktree
-n - do not apply this hunk to worktree
-q - quit; do not apply this hunk or any of the remaining ones
-a - apply this hunk and all later hunks in the file
-d - do not apply this hunk or any of the later hunks in the file"),
-);
-
-sub help_patch_cmd {
- local $_;
- my $other = $_[0] . ",?";
- print colored $help_color, __($help_patch_modes{$patch_mode}), "\n",
- map { "$_\n" } grep {
- my $c = quotemeta(substr($_, 0, 1));
- $other =~ /,$c/
- } split "\n", __ <<EOF ;
-g - select a hunk to go to
-/ - search for a hunk matching the given regex
-j - leave this hunk undecided, see next undecided hunk
-J - leave this hunk undecided, see next hunk
-k - leave this hunk undecided, see previous undecided hunk
-K - leave this hunk undecided, see previous hunk
-s - split the current hunk into smaller hunks
-e - manually edit the current hunk
-? - print help
-EOF
-}
-
-sub apply_patch {
- my $cmd = shift;
- my $ret = run_git_apply $cmd, @_;
- if (!$ret) {
- print STDERR @_;
- }
- return $ret;
-}
-
-sub apply_patch_for_checkout_commit {
- my $reverse = shift;
- my $applies_index = run_git_apply 'apply '.$reverse.' --cached --check', @_;
- my $applies_worktree = run_git_apply 'apply '.$reverse.' --check', @_;
-
- if ($applies_worktree && $applies_index) {
- run_git_apply 'apply '.$reverse.' --cached', @_;
- run_git_apply 'apply '.$reverse, @_;
- return 1;
- } elsif (!$applies_index) {
- print colored $error_color, __("The selected hunks do not apply to the index!\n");
- if (prompt_yesno __("Apply them to the worktree anyway? ")) {
- return run_git_apply 'apply '.$reverse, @_;
- } else {
- print colored $error_color, __("Nothing was applied.\n");
- return 0;
- }
- } else {
- print STDERR @_;
- return 0;
- }
-}
-
-sub patch_update_cmd {
- my @all_mods = list_modified($patch_mode_flavour{FILTER});
- error_msg sprintf(__("ignoring unmerged: %s\n"), $_->{VALUE})
- for grep { $_->{UNMERGED} } @all_mods;
- @all_mods = grep { !$_->{UNMERGED} } @all_mods;
-
- my @mods = grep { !($_->{BINARY}) } @all_mods;
- my @them;
-
- if (!@mods) {
- if (@all_mods) {
- print STDERR __("Only binary files changed.\n");
- } else {
- print STDERR __("No changes.\n");
- }
- return 0;
- }
- if ($patch_mode_only) {
- @them = @mods;
- }
- else {
- @them = list_and_choose({ PROMPT => __('Patch update'),
- HEADER => $status_head, },
- @mods);
- }
- for (@them) {
- return 0 if patch_update_file($_->{VALUE});
- }
-}
-
-# Generate a one line summary of a hunk.
-sub summarize_hunk {
- my $rhunk = shift;
- my $summary = $rhunk->{TEXT}[0];
-
- # Keep the line numbers, discard extra context.
- $summary =~ s/@@(.*?)@@.*/$1 /s;
- $summary .= " " x (20 - length $summary);
-
- # Add some user context.
- for my $line (@{$rhunk->{TEXT}}) {
- if ($line =~ m/^[+-].*\w/) {
- $summary .= $line;
- last;
- }
- }
-
- chomp $summary;
- return substr($summary, 0, 80) . "\n";
-}
-
-
-# Print a one-line summary of each hunk in the array ref in
-# the first argument, starting with the index in the 2nd.
-sub display_hunks {
- my ($hunks, $i) = @_;
- my $ctr = 0;
- $i ||= 0;
- for (; $i < @$hunks && $ctr < 20; $i++, $ctr++) {
- my $status = " ";
- if (defined $hunks->[$i]{USE}) {
- $status = $hunks->[$i]{USE} ? "+" : "-";
- }
- printf "%s%2d: %s",
- $status,
- $i + 1,
- summarize_hunk($hunks->[$i]);
- }
- return $i;
-}
-
-my %patch_update_prompt_modes = (
- stage => {
- mode => N__("Stage mode change [y,n,q,a,d%s,?]? "),
- deletion => N__("Stage deletion [y,n,q,a,d%s,?]? "),
- addition => N__("Stage addition [y,n,q,a,d%s,?]? "),
- hunk => N__("Stage this hunk [y,n,q,a,d%s,?]? "),
- },
- stash => {
- mode => N__("Stash mode change [y,n,q,a,d%s,?]? "),
- deletion => N__("Stash deletion [y,n,q,a,d%s,?]? "),
- addition => N__("Stash addition [y,n,q,a,d%s,?]? "),
- hunk => N__("Stash this hunk [y,n,q,a,d%s,?]? "),
- },
- reset_head => {
- mode => N__("Unstage mode change [y,n,q,a,d%s,?]? "),
- deletion => N__("Unstage deletion [y,n,q,a,d%s,?]? "),
- addition => N__("Unstage addition [y,n,q,a,d%s,?]? "),
- hunk => N__("Unstage this hunk [y,n,q,a,d%s,?]? "),
- },
- reset_nothead => {
- mode => N__("Apply mode change to index [y,n,q,a,d%s,?]? "),
- deletion => N__("Apply deletion to index [y,n,q,a,d%s,?]? "),
- addition => N__("Apply addition to index [y,n,q,a,d%s,?]? "),
- hunk => N__("Apply this hunk to index [y,n,q,a,d%s,?]? "),
- },
- checkout_index => {
- mode => N__("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
- deletion => N__("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
- addition => N__("Discard addition from worktree [y,n,q,a,d%s,?]? "),
- hunk => N__("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
- },
- checkout_head => {
- mode => N__("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "),
- deletion => N__("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "),
- addition => N__("Discard addition from index and worktree [y,n,q,a,d%s,?]? "),
- hunk => N__("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "),
- },
- checkout_nothead => {
- mode => N__("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "),
- deletion => N__("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "),
- addition => N__("Apply addition to index and worktree [y,n,q,a,d%s,?]? "),
- hunk => N__("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "),
- },
- worktree_head => {
- mode => N__("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
- deletion => N__("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
- addition => N__("Discard addition from worktree [y,n,q,a,d%s,?]? "),
- hunk => N__("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
- },
- worktree_nothead => {
- mode => N__("Apply mode change to worktree [y,n,q,a,d%s,?]? "),
- deletion => N__("Apply deletion to worktree [y,n,q,a,d%s,?]? "),
- addition => N__("Apply addition to worktree [y,n,q,a,d%s,?]? "),
- hunk => N__("Apply this hunk to worktree [y,n,q,a,d%s,?]? "),
- },
-);
-
-sub patch_update_file {
- my $quit = 0;
- my ($ix, $num);
- my $path = shift;
- my ($head, @hunk) = parse_diff($path);
- ($head, my $mode, my $deletion, my $addition) = parse_diff_header($head);
- for (@{$head->{DISPLAY}}) {
- print;
- }
-
- if (@{$mode->{TEXT}}) {
- unshift @hunk, $mode;
- }
- if (@{$deletion->{TEXT}}) {
- foreach my $hunk (@hunk) {
- push @{$deletion->{TEXT}}, @{$hunk->{TEXT}};
- push @{$deletion->{DISPLAY}}, @{$hunk->{DISPLAY}};
- }
- @hunk = ($deletion);
- }
-
- $num = scalar @hunk;
- $ix = 0;
-
- while (1) {
- my ($prev, $next, $other, $undecided, $i);
- $other = '';
-
- last if ($ix and !$num);
- if ($num <= $ix) {
- $ix = 0;
- }
- for ($i = 0; $i < $ix; $i++) {
- if (!defined $hunk[$i]{USE}) {
- $prev = 1;
- $other .= ',k';
- last;
- }
- }
- if ($ix) {
- $other .= ',K';
- }
- for ($i = $ix + 1; $i < $num; $i++) {
- if (!defined $hunk[$i]{USE}) {
- $next = 1;
- $other .= ',j';
- last;
- }
- }
- if ($ix < $num - 1) {
- $other .= ',J';
- }
- if ($num > 1) {
- $other .= ',g,/';
- }
- for ($i = 0; $i < $num; $i++) {
- if (!defined $hunk[$i]{USE}) {
- $undecided = 1;
- last;
- }
- }
- last if (!$undecided && ($num || !$addition));
-
- if ($num) {
- if ($hunk[$ix]{TYPE} eq 'hunk' &&
- hunk_splittable($hunk[$ix]{TEXT})) {
- $other .= ',s';
- }
- if ($hunk[$ix]{TYPE} eq 'hunk') {
- $other .= ',e';
- }
- for (@{$hunk[$ix]{DISPLAY}}) {
- print;
- }
- }
- my $type = $num ? $hunk[$ix]{TYPE} : $head->{TYPE};
- print colored $prompt_color, "(", ($ix+1), "/", ($num ? $num : 1), ") ",
- sprintf(__($patch_update_prompt_modes{$patch_mode}{$type}), $other);
-
- my $line = prompt_single_character;
- last unless defined $line;
- if ($line) {
- if ($line =~ /^y/i) {
- if ($num) {
- $hunk[$ix]{USE} = 1;
- } else {
- $head->{USE} = 1;
- }
- }
- elsif ($line =~ /^n/i) {
- if ($num) {
- $hunk[$ix]{USE} = 0;
- } else {
- $head->{USE} = 0;
- }
- }
- elsif ($line =~ /^a/i) {
- if ($num) {
- while ($ix < $num) {
- if (!defined $hunk[$ix]{USE}) {
- $hunk[$ix]{USE} = 1;
- }
- $ix++;
- }
- } else {
- $head->{USE} = 1;
- $ix++;
- }
- next;
- }
- elsif ($line =~ /^g(.*)/) {
- my $response = $1;
- unless ($other =~ /g/) {
- error_msg __("No other hunks to goto\n");
- next;
- }
- my $no = $ix > 10 ? $ix - 10 : 0;
- while ($response eq '') {
- $no = display_hunks(\@hunk, $no);
- if ($no < $num) {
- print __("go to which hunk (<ret> to see more)? ");
- } else {
- print __("go to which hunk? ");
- }
- $response = <STDIN>;
- if (!defined $response) {
- $response = '';
- }
- chomp $response;
- }
- if ($response !~ /^\s*\d+\s*$/) {
- error_msg sprintf(__("Invalid number: '%s'\n"),
- $response);
- } elsif (0 < $response && $response <= $num) {
- $ix = $response - 1;
- } else {
- error_msg sprintf(__n("Sorry, only %d hunk available.\n",
- "Sorry, only %d hunks available.\n", $num), $num);
- }
- next;
- }
- elsif ($line =~ /^d/i) {
- if ($num) {
- while ($ix < $num) {
- if (!defined $hunk[$ix]{USE}) {
- $hunk[$ix]{USE} = 0;
- }
- $ix++;
- }
- } else {
- $head->{USE} = 0;
- $ix++;
- }
- next;
- }
- elsif ($line =~ /^q/i) {
- if ($num) {
- for ($i = 0; $i < $num; $i++) {
- if (!defined $hunk[$i]{USE}) {
- $hunk[$i]{USE} = 0;
- }
- }
- } elsif (!defined $head->{USE}) {
- $head->{USE} = 0;
- }
- $quit = 1;
- last;
- }
- elsif ($line =~ m|^/(.*)|) {
- my $regex = $1;
- unless ($other =~ m|/|) {
- error_msg __("No other hunks to search\n");
- next;
- }
- if ($regex eq "") {
- print colored $prompt_color, __("search for regex? ");
- $regex = <STDIN>;
- if (defined $regex) {
- chomp $regex;
- }
- }
- my $search_string;
- eval {
- $search_string = qr{$regex}m;
- };
- if ($@) {
- my ($err,$exp) = ($@, $1);
- $err =~ s/ at .*git-add--interactive line \d+, <STDIN> line \d+.*$//;
- error_msg sprintf(__("Malformed search regexp %s: %s\n"), $exp, $err);
- next;
- }
- my $iy = $ix;
- while (1) {
- my $text = join ("", @{$hunk[$iy]{TEXT}});
- last if ($text =~ $search_string);
- $iy++;
- $iy = 0 if ($iy >= $num);
- if ($ix == $iy) {
- error_msg __("No hunk matches the given pattern\n");
- last;
- }
- }
- $ix = $iy;
- next;
- }
- elsif ($line =~ /^K/) {
- if ($other =~ /K/) {
- $ix--;
- }
- else {
- error_msg __("No previous hunk\n");
- }
- next;
- }
- elsif ($line =~ /^J/) {
- if ($other =~ /J/) {
- $ix++;
- }
- else {
- error_msg __("No next hunk\n");
- }
- next;
- }
- elsif ($line =~ /^k/) {
- if ($other =~ /k/) {
- while (1) {
- $ix--;
- last if (!$ix ||
- !defined $hunk[$ix]{USE});
- }
- }
- else {
- error_msg __("No previous hunk\n");
- }
- next;
- }
- elsif ($line =~ /^j/) {
- if ($other !~ /j/) {
- error_msg __("No next hunk\n");
- next;
- }
- }
- elsif ($line =~ /^s/) {
- unless ($other =~ /s/) {
- error_msg __("Sorry, cannot split this hunk\n");
- next;
- }
- my @split = split_hunk($hunk[$ix]{TEXT}, $hunk[$ix]{DISPLAY});
- if (1 < @split) {
- print colored $header_color, sprintf(
- __n("Split into %d hunk.\n",
- "Split into %d hunks.\n",
- scalar(@split)), scalar(@split));
- }
- splice (@hunk, $ix, 1, @split);
- $num = scalar @hunk;
- next;
- }
- elsif ($line =~ /^e/) {
- unless ($other =~ /e/) {
- error_msg __("Sorry, cannot edit this hunk\n");
- next;
- }
- my $newhunk = edit_hunk_loop($head, \@hunk, $ix);
- if (defined $newhunk) {
- splice @hunk, $ix, 1, $newhunk;
- }
- }
- else {
- help_patch_cmd($other);
- next;
- }
- # soft increment
- while (1) {
- $ix++;
- last if ($ix >= $num ||
- !defined $hunk[$ix]{USE});
- }
- }
- }
-
- @hunk = coalesce_overlapping_hunks(@hunk) if ($num);
-
- my $n_lofs = 0;
- my @result = ();
- for (@hunk) {
- if ($_->{USE}) {
- push @result, @{$_->{TEXT}};
- }
- }
-
- if (@result or $head->{USE}) {
- my @patch = reassemble_patch($head->{TEXT}, @result);
- my $apply_routine = $patch_mode_flavour{APPLY};
- &$apply_routine(@patch);
- refresh();
- }
-
- print "\n";
- return $quit;
-}
-
-sub diff_cmd {
- my @mods = list_modified('index-only');
- @mods = grep { !($_->{BINARY}) } @mods;
- return if (!@mods);
- my (@them) = list_and_choose({ PROMPT => __('Review diff'),
- IMMEDIATE => 1,
- HEADER => $status_head, },
- @mods);
- return if (!@them);
- my $reference = (is_initial_commit()) ? get_empty_tree() : 'HEAD';
- system(qw(git diff -p --cached), $reference, '--',
- map { $_->{VALUE} } @them);
-}
-
-sub quit_cmd {
- print __("Bye.\n");
- exit(0);
-}
-
-sub help_cmd {
-# TRANSLATORS: please do not translate the command names
-# 'status', 'update', 'revert', etc.
- print colored $help_color, __ <<'EOF' ;
-status - show paths with changes
-update - add working tree state to the staged set of changes
-revert - revert staged set of changes back to the HEAD version
-patch - pick hunks and update selectively
-diff - view diff between HEAD and index
-add untracked - add contents of untracked files to the staged set of changes
-EOF
-}
-
-sub process_args {
- return unless @ARGV;
- my $arg = shift @ARGV;
- if ($arg =~ /--patch(?:=(.*))?/) {
- if (defined $1) {
- if ($1 eq 'reset') {
- $patch_mode = 'reset_head';
- $patch_mode_revision = 'HEAD';
- $arg = shift @ARGV or die __("missing --");
- if ($arg ne '--') {
- $patch_mode_revision = $arg;
-
- # NEEDSWORK: Instead of comparing to the literal "HEAD",
- # compare the commit objects instead so that other ways of
- # saying the same thing (such as "@") are also handled
- # appropriately.
- #
- # This applies to the cases below too.
- $patch_mode = ($arg eq 'HEAD' ?
- 'reset_head' : 'reset_nothead');
- $arg = shift @ARGV or die __("missing --");
- }
- } elsif ($1 eq 'checkout') {
- $arg = shift @ARGV or die __("missing --");
- if ($arg eq '--') {
- $patch_mode = 'checkout_index';
- } else {
- $patch_mode_revision = $arg;
- $patch_mode = ($arg eq 'HEAD' ?
- 'checkout_head' : 'checkout_nothead');
- $arg = shift @ARGV or die __("missing --");
- }
- } elsif ($1 eq 'worktree') {
- $arg = shift @ARGV or die __("missing --");
- if ($arg eq '--') {
- $patch_mode = 'checkout_index';
- } else {
- $patch_mode_revision = $arg;
- $patch_mode = ($arg eq 'HEAD' ?
- 'worktree_head' : 'worktree_nothead');
- $arg = shift @ARGV or die __("missing --");
- }
- } elsif ($1 eq 'stage' or $1 eq 'stash') {
- $patch_mode = $1;
- $arg = shift @ARGV or die __("missing --");
- } else {
- die sprintf(__("unknown --patch mode: %s"), $1);
- }
- } else {
- $patch_mode = 'stage';
- $arg = shift @ARGV or die __("missing --");
- }
- die sprintf(__("invalid argument %s, expecting --"),
- $arg) unless $arg eq "--";
- %patch_mode_flavour = %{$patch_modes{$patch_mode}};
- $patch_mode_only = 1;
- }
- elsif ($arg ne "--") {
- die sprintf(__("invalid argument %s, expecting --"), $arg);
- }
-}
-
-sub main_loop {
- my @cmd = ([ 'status', \&status_cmd, ],
- [ 'update', \&update_cmd, ],
- [ 'revert', \&revert_cmd, ],
- [ 'add untracked', \&add_untracked_cmd, ],
- [ 'patch', \&patch_update_cmd, ],
- [ 'diff', \&diff_cmd, ],
- [ 'quit', \&quit_cmd, ],
- [ 'help', \&help_cmd, ],
- );
- while (1) {
- my ($it) = list_and_choose({ PROMPT => __('What now'),
- SINGLETON => 1,
- LIST_FLAT => 4,
- HEADER => __('*** Commands ***'),
- ON_EOF => \&quit_cmd,
- IMMEDIATE => 1 }, @cmd);
- if ($it) {
- eval {
- $it->[1]->();
- };
- if ($@) {
- print "$@";
- }
- }
- }
-}
-
-process_args();
-refresh();
-if ($patch_mode_only) {
- patch_update_cmd();
-}
-else {
- status_cmd();
- main_loop();
-}
diff --git a/git-bisect.sh b/git-bisect.sh
deleted file mode 100755
index dfce4b4..0000000
--- a/git-bisect.sh
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/bin/sh
-
-USAGE='[help|start|bad|good|new|old|terms|skip|next|reset|visualize|view|replay|log|run]'
-LONG_USAGE='git bisect help
- print this long help message.
-git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]
- [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]
- reset bisect state and start bisection.
-git bisect (bad|new) [<rev>]
- mark <rev> a known-bad revision/
- a revision after change in a given property.
-git bisect (good|old) [<rev>...]
- mark <rev>... known-good revisions/
- revisions before change in a given property.
-git bisect terms [--term-good | --term-bad]
- show the terms used for old and new commits (default: bad, good)
-git bisect skip [(<rev>|<range>)...]
- mark <rev>... untestable revisions.
-git bisect next
- find next bisection to test and check it out.
-git bisect reset [<commit>]
- finish bisection search and go back to commit.
-git bisect (visualize|view)
- show bisect status in gitk.
-git bisect replay <logfile>
- replay bisection log.
-git bisect log
- show bisect log.
-git bisect run <cmd>...
- use <cmd>... to automatically bisect.
-
-Please use "git help bisect" to get the full man page.'
-
-OPTIONS_SPEC=
-. git-sh-setup
-
-TERM_BAD=bad
-TERM_GOOD=good
-
-get_terms () {
- if test -s "$GIT_DIR/BISECT_TERMS"
- then
- {
- read TERM_BAD
- read TERM_GOOD
- } <"$GIT_DIR/BISECT_TERMS"
- fi
-}
-
-case "$#" in
-0)
- usage ;;
-*)
- cmd="$1"
- get_terms
- shift
- case "$cmd" in
- help)
- git bisect -h ;;
- bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
- git bisect--helper state "$cmd" "$@" ;;
- log)
- git bisect--helper log || exit ;;
- *)
- git bisect--helper "$cmd" "$@" ;;
- esac
-esac
diff --git a/git-compat-util.h b/git-compat-util.h
index de57f43..4f0028c 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -97,8 +97,14 @@ struct strbuf;
# define BARF_UNLESS_AN_ARRAY(arr) \
BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(__typeof__(arr), \
__typeof__(&(arr)[0])))
+# define BARF_UNLESS_COPYABLE(dst, src) \
+ BUILD_ASSERT_OR_ZERO(__builtin_types_compatible_p(__typeof__(*(dst)), \
+ __typeof__(*(src))))
#else
# define BARF_UNLESS_AN_ARRAY(arr) 0
+# define BARF_UNLESS_COPYABLE(dst, src) \
+ BUILD_ASSERT_OR_ZERO(0 ? ((*(dst) = *(src)), 0) : \
+ sizeof(*(dst)) == sizeof(*(src)))
#endif
/*
* ARRAY_SIZE - get the number of elements in a visible array
@@ -1102,7 +1108,7 @@ int xstrncmpz(const char *s, const char *t, size_t len);
#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult(sizeof(*(x)), (alloc)))
#define COPY_ARRAY(dst, src, n) copy_array((dst), (src), (n), sizeof(*(dst)) + \
- BUILD_ASSERT_OR_ZERO(sizeof(*(dst)) == sizeof(*(src))))
+ BARF_UNLESS_COPYABLE((dst), (src)))
static inline void copy_array(void *dst, const void *src, size_t n, size_t size)
{
if (n)
@@ -1110,13 +1116,18 @@ static inline void copy_array(void *dst, const void *src, size_t n, size_t size)
}
#define MOVE_ARRAY(dst, src, n) move_array((dst), (src), (n), sizeof(*(dst)) + \
- BUILD_ASSERT_OR_ZERO(sizeof(*(dst)) == sizeof(*(src))))
+ BARF_UNLESS_COPYABLE((dst), (src)))
static inline void move_array(void *dst, const void *src, size_t n, size_t size)
{
if (n)
memmove(dst, src, st_mult(size, n));
}
+#define DUP_ARRAY(dst, src, n) do { \
+ size_t dup_array_n_ = (n); \
+ COPY_ARRAY(ALLOC_ARRAY((dst), dup_array_n_), (src), dup_array_n_); \
+} while (0)
+
/*
* These functions help you allocate structs with flex arrays, and copy
* the data directly into the array. For example, if you had:
diff --git a/git-request-pull.sh b/git-request-pull.sh
index 2d0e446..01640a0 100755
--- a/git-request-pull.sh
+++ b/git-request-pull.sh
@@ -153,7 +153,7 @@
if test $(git cat-file -t "$head") = tag
then
git cat-file tag "$head" |
- sed -n -e '1,/^$/d' -e '/^-----BEGIN PGP /q' -e p
+ sed -n -e '1,/^$/d' -e '/^-----BEGIN \(PGP\|SSH\|SIGNED\) /q' -e p
echo
echo "----------------------------------------------------------------"
fi &&
diff --git a/git-send-email.perl b/git-send-email.perl
index ad51508..c761801 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -208,6 +208,10 @@
my $force = 0;
my $dump_aliases = 0;
+# Variables to prevent short format-patch options from being captured
+# as abbreviated send-email options
+my $reroll_count;
+
# Handle interactive edition of files.
my $multiedit;
my $editor;
@@ -530,6 +534,7 @@
"batch-size=i" => \$batch_size,
"relogin-delay=i" => \$relogin_delay,
"git-completion-helper" => \$git_completion_helper,
+ "v=s" => \$reroll_count,
);
$rc = GetOptions(%options);
@@ -770,7 +775,9 @@
die __("Cannot run git format-patch from outside a repository\n")
unless $repo;
require File::Temp;
- push @files, $repo->command('format-patch', '-o', File::Temp::tempdir(CLEANUP => 1), @rev_list_opts);
+ push @files, $repo->command('format-patch', '-o', File::Temp::tempdir(CLEANUP => 1),
+ defined $reroll_count ? ('-v', $reroll_count) : (),
+ @rev_list_opts);
}
@files = handle_backup_files(@files);
diff --git a/git-submodule.sh b/git-submodule.sh
index 9a50f2e..7f9582d 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -244,6 +244,9 @@
-q|--quiet)
quiet=1
;;
+ -v|--verbose)
+ quiet=0
+ ;;
--progress)
progress=1
;;
diff --git a/git.c b/git.c
index 10202a7..6171fd6 100644
--- a/git.c
+++ b/git.c
@@ -14,9 +14,8 @@
* RUN_SETUP for reading from the configuration file.
*/
#define NEED_WORK_TREE (1<<3)
-#define SUPPORT_SUPER_PREFIX (1<<4)
-#define DELAY_PAGER_CONFIG (1<<5)
-#define NO_PARSEOPT (1<<6) /* parse-options is not used */
+#define DELAY_PAGER_CONFIG (1<<4)
+#define NO_PARSEOPT (1<<5) /* parse-options is not used */
struct cmd_struct {
const char *cmd;
@@ -29,8 +28,7 @@ const char git_usage_string[] =
" [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\n"
" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
- " [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
- " <command> [<args>]");
+ " [--config-env=<name>=<envvar>] <command> [<args>]");
const char git_more_info_string[] =
N_("'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -226,20 +224,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
setenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);
if (envchanged)
*envchanged = 1;
- } else if (!strcmp(cmd, "--super-prefix")) {
- if (*argc < 2) {
- fprintf(stderr, _("no prefix given for --super-prefix\n" ));
- usage(git_usage_string);
- }
- setenv(GIT_SUPER_PREFIX_ENVIRONMENT, (*argv)[1], 1);
- if (envchanged)
- *envchanged = 1;
- (*argv)++;
- (*argc)--;
- } else if (skip_prefix(cmd, "--super-prefix=", &cmd)) {
- setenv(GIT_SUPER_PREFIX_ENVIRONMENT, cmd, 1);
- if (envchanged)
- *envchanged = 1;
} else if (!strcmp(cmd, "--bare")) {
char *cwd = xgetcwd();
is_bare_repository_cfg = 1;
@@ -446,14 +430,9 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
use_pager = 1;
if (run_setup && startup_info->have_repository)
/* get_git_dir() may set up repo, avoid that */
- trace_repo_setup(prefix);
+ trace_repo_setup();
commit_pager_choice();
- if (!help && get_super_prefix()) {
- if (!(p->option & SUPPORT_SUPER_PREFIX))
- die(_("%s doesn't support --super-prefix"), p->cmd);
- }
-
if (!help && p->option & NEED_WORK_TREE)
setup_work_tree();
@@ -492,7 +471,7 @@ static struct cmd_struct commands[] = {
{ "annotate", cmd_annotate, RUN_SETUP },
{ "apply", cmd_apply, RUN_SETUP_GENTLY },
{ "archive", cmd_archive, RUN_SETUP_GENTLY },
- { "bisect--helper", cmd_bisect__helper, RUN_SETUP },
+ { "bisect", cmd_bisect, RUN_SETUP },
{ "blame", cmd_blame, RUN_SETUP },
{ "branch", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },
{ "bugreport", cmd_bugreport, RUN_SETUP_GENTLY },
@@ -504,7 +483,7 @@ static struct cmd_struct commands[] = {
{ "check-ref-format", cmd_check_ref_format, NO_PARSEOPT },
{ "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
{ "checkout--worker", cmd_checkout__worker,
- RUN_SETUP | NEED_WORK_TREE | SUPPORT_SUPER_PREFIX },
+ RUN_SETUP | NEED_WORK_TREE },
{ "checkout-index", cmd_checkout_index,
RUN_SETUP | NEED_WORK_TREE},
{ "cherry", cmd_cherry, RUN_SETUP },
@@ -528,7 +507,6 @@ static struct cmd_struct commands[] = {
{ "diff-index", cmd_diff_index, RUN_SETUP | NO_PARSEOPT },
{ "diff-tree", cmd_diff_tree, RUN_SETUP | NO_PARSEOPT },
{ "difftool", cmd_difftool, RUN_SETUP_GENTLY },
- { "env--helper", cmd_env__helper },
{ "fast-export", cmd_fast_export, RUN_SETUP },
{ "fast-import", cmd_fast_import, RUN_SETUP | NO_PARSEOPT },
{ "fetch", cmd_fetch, RUN_SETUP },
@@ -539,7 +517,7 @@ static struct cmd_struct commands[] = {
{ "format-patch", cmd_format_patch, RUN_SETUP },
{ "fsck", cmd_fsck, RUN_SETUP },
{ "fsck-objects", cmd_fsck, RUN_SETUP },
- { "fsmonitor--daemon", cmd_fsmonitor__daemon, SUPPORT_SUPER_PREFIX | RUN_SETUP },
+ { "fsmonitor--daemon", cmd_fsmonitor__daemon, RUN_SETUP },
{ "gc", cmd_gc, RUN_SETUP },
{ "get-tar-commit-id", cmd_get_tar_commit_id, NO_PARSEOPT },
{ "grep", cmd_grep, RUN_SETUP_GENTLY },
@@ -583,7 +561,7 @@ static struct cmd_struct commands[] = {
{ "pull", cmd_pull, RUN_SETUP | NEED_WORK_TREE },
{ "push", cmd_push, RUN_SETUP },
{ "range-diff", cmd_range_diff, RUN_SETUP | USE_PAGER },
- { "read-tree", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},
+ { "read-tree", cmd_read_tree, RUN_SETUP },
{ "rebase", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },
{ "receive-pack", cmd_receive_pack },
{ "reflog", cmd_reflog, RUN_SETUP },
@@ -610,7 +588,7 @@ static struct cmd_struct commands[] = {
{ "stash", cmd_stash, RUN_SETUP | NEED_WORK_TREE },
{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
{ "stripspace", cmd_stripspace },
- { "submodule--helper", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX },
+ { "submodule--helper", cmd_submodule__helper, RUN_SETUP },
{ "switch", cmd_switch, RUN_SETUP | NEED_WORK_TREE },
{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
{ "tag", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },
@@ -727,9 +705,6 @@ static void execv_dashed_external(const char **argv)
struct child_process cmd = CHILD_PROCESS_INIT;
int status;
- if (get_super_prefix())
- die(_("%s doesn't support --super-prefix"), argv[0]);
-
if (use_pager == -1 && !is_builtin(argv[0]))
use_pager = check_pager_config(argv[0]);
commit_pager_choice();
@@ -799,9 +774,6 @@ static int run_argv(int *argcp, const char ***argv)
*/
trace2_cmd_name("_run_git_alias_");
- if (get_super_prefix())
- die("%s doesn't support --super-prefix", **argv);
-
commit_pager_choice();
strvec_push(&cmd.args, "git");
diff --git a/gpg-interface.c b/gpg-interface.c
index f877a1e..5cd66d3 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -977,9 +977,13 @@ static int sign_buffer_gpg(struct strbuf *buffer, struct strbuf *signature,
break; /* found */
}
ret |= !cp;
+ if (ret) {
+ error(_("gpg failed to sign the data:\n%s"),
+ gpg_status.len ? gpg_status.buf : "(no gpg output)");
+ strbuf_release(&gpg_status);
+ return -1;
+ }
strbuf_release(&gpg_status);
- if (ret)
- return error(_("gpg failed to sign the data"));
/* Strip CR from the line endings, in case we are on Windows. */
remove_cr_after(signature, bottom);
@@ -998,6 +1002,7 @@ static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
char *ssh_signing_key_file = NULL;
struct strbuf ssh_signature_filename = STRBUF_INIT;
const char *literal_key = NULL;
+ int literal_ssh_key = 0;
if (!signing_key || signing_key[0] == '\0')
return error(
@@ -1005,6 +1010,7 @@ static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
if (is_literal_ssh_key(signing_key, &literal_key)) {
/* A literal ssh key */
+ literal_ssh_key = 1;
key_file = mks_tempfile_t(".git_signing_key_tmpXXXXXX");
if (!key_file)
return error_errno(
@@ -1039,8 +1045,10 @@ static int sign_buffer_ssh(struct strbuf *buffer, struct strbuf *signature,
"-Y", "sign",
"-n", "git",
"-f", ssh_signing_key_file,
- buffer_file->filename.buf,
NULL);
+ if (literal_ssh_key)
+ strvec_push(&signer.args, "-U");
+ strvec_push(&signer.args, buffer_file->filename.buf);
sigchain_push(SIGPIPE, SIG_IGN);
ret = pipe_command(&signer, NULL, 0, NULL, 0, &signer_stderr, 0);
diff --git a/grep.c b/grep.c
index 06eed69..cee44a7 100644
--- a/grep.c
+++ b/grep.c
@@ -262,6 +262,31 @@ static void pcre2_free(void *pointer, MAYBE_UNUSED void *memory_data)
free(pointer);
}
+static int pcre2_jit_functional(void)
+{
+ static int jit_working = -1;
+ pcre2_code *code;
+ size_t off;
+ int err;
+
+ if (jit_working != -1)
+ return jit_working;
+
+ /*
+ * Try to JIT compile a simple pattern to probe if the JIT is
+ * working in general. It might fail for systems where creating
+ * memory mappings for runtime code generation is restricted.
+ */
+ code = pcre2_compile((PCRE2_SPTR)".", 1, 0, &err, &off, NULL);
+ if (!code)
+ return 0;
+
+ jit_working = pcre2_jit_compile(code, PCRE2_JIT_COMPLETE) == 0;
+ pcre2_code_free(code);
+
+ return jit_working;
+}
+
static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt)
{
int error;
@@ -293,7 +318,7 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
options |= PCRE2_CASELESS;
}
if (!opt->ignore_locale && is_utf8_locale() && !literal)
- options |= (PCRE2_UTF | PCRE2_MATCH_INVALID_UTF);
+ options |= (PCRE2_UTF | PCRE2_UCP | PCRE2_MATCH_INVALID_UTF);
#ifndef GIT_PCRE2_VERSION_10_36_OR_HIGHER
/* Work around https://bugs.exim.org/show_bug.cgi?id=2642 fixed in 10.36 */
@@ -317,8 +342,29 @@ static void compile_pcre2_pattern(struct grep_pat *p, const struct grep_opt *opt
pcre2_config(PCRE2_CONFIG_JIT, &p->pcre2_jit_on);
if (p->pcre2_jit_on) {
jitret = pcre2_jit_compile(p->pcre2_pattern, PCRE2_JIT_COMPLETE);
- if (jitret)
- die("Couldn't JIT the PCRE2 pattern '%s', got '%d'\n", p->pattern, jitret);
+ if (jitret == PCRE2_ERROR_NOMEMORY && !pcre2_jit_functional()) {
+ /*
+ * Even though pcre2_config(PCRE2_CONFIG_JIT, ...)
+ * indicated JIT support, the library might still
+ * fail to generate JIT code for various reasons,
+ * e.g. when SELinux's 'deny_execmem' or PaX's
+ * MPROTECT prevent creating W|X memory mappings.
+ *
+ * Instead of faling hard, fall back to interpreter
+ * mode, just as if the pattern was prefixed with
+ * '(*NO_JIT)'.
+ */
+ p->pcre2_jit_on = 0;
+ return;
+ } else if (jitret) {
+ int need_clip = p->patternlen > 64;
+ int clip_len = need_clip ? 64 : p->patternlen;
+ die("Couldn't JIT the PCRE2 pattern '%.*s'%s, got '%d'%s",
+ clip_len, p->pattern, need_clip ? "..." : "", jitret,
+ pcre2_jit_functional()
+ ? "\nPerhaps prefix (*NO_JIT) to your pattern?"
+ : "");
+ }
/*
* The pcre2_config(PCRE2_CONFIG_JIT, ...) call just
@@ -769,11 +815,11 @@ static void free_pattern_expr(struct grep_expr *x)
free(x);
}
-void free_grep_patterns(struct grep_opt *opt)
+static void free_grep_pat(struct grep_pat *pattern)
{
struct grep_pat *p, *n;
- for (p = opt->pattern_list; p; p = n) {
+ for (p = pattern; p; p = n) {
n = p->next;
switch (p->token) {
case GREP_PATTERN: /* atom */
@@ -790,10 +836,15 @@ void free_grep_patterns(struct grep_opt *opt)
}
free(p);
}
+}
- if (!opt->pattern_expression)
- return;
- free_pattern_expr(opt->pattern_expression);
+void free_grep_patterns(struct grep_opt *opt)
+{
+ free_grep_pat(opt->pattern_list);
+ free_grep_pat(opt->header_list);
+
+ if (opt->pattern_expression)
+ free_pattern_expr(opt->pattern_expression);
}
static const char *end_of_line(const char *cp, unsigned long *left)
diff --git a/help.c b/help.c
index f1e090a..812af4c 100644
--- 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)
diff --git a/hook.c b/hook.c
index 22b274b..7981e08 100644
--- a/hook.c
+++ b/hook.c
@@ -59,6 +59,11 @@ static int pick_next_hook(struct child_process *cp,
cp->no_stdin = 1;
strvec_pushv(&cp->env, hook_cb->options->env.v);
+ /* reopen the file for stdin; run_command closes it. */
+ if (hook_cb->options->path_to_stdin) {
+ cp->no_stdin = 0;
+ cp->in = xopen(hook_cb->options->path_to_stdin, O_RDONLY);
+ }
cp->stdout_to_stderr = 1;
cp->trace2_hook_name = hook_cb->hook_name;
cp->dir = hook_cb->options->dir;
diff --git a/hook.h b/hook.h
index 4258b13..19ab9a5 100644
--- a/hook.h
+++ b/hook.h
@@ -30,6 +30,11 @@ struct run_hooks_opt
* was invoked.
*/
int *invoked_hook;
+
+ /**
+ * Path to file which should be piped to stdin for each hook.
+ */
+ const char *path_to_stdin;
};
#define RUN_HOOKS_OPT_INIT { \
diff --git a/http-backend.c b/http-backend.c
index 6eb3b2f..8ab58e5 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -759,10 +759,14 @@ int cmd_main(int argc, const char **argv)
struct service_cmd *c = &services[i];
regex_t re;
regmatch_t out[1];
+ int ret;
if (regcomp(&re, c->pattern, REG_EXTENDED))
die("Bogus regex in service table: %s", c->pattern);
- if (!regexec(&re, dir, 1, out, 0)) {
+ ret = regexec(&re, dir, 1, out, 0);
+ regfree(&re);
+
+ if (!ret) {
size_t n;
if (strcmp(method, c->method))
@@ -774,7 +778,6 @@ int cmd_main(int argc, const char **argv)
dir[out[0].rm_so] = 0;
break;
}
- regfree(&re);
}
if (!cmd)
@@ -786,6 +789,7 @@ int cmd_main(int argc, const char **argv)
if (!getenv("GIT_HTTP_EXPORT_ALL") &&
access("git-daemon-export-ok", F_OK) )
not_found(&hdr, "Repository not exported: '%s'", dir);
+ free(dir);
http_config();
max_request_buffer = git_env_ulong("GIT_HTTP_MAX_REQUEST_BUFFER",
@@ -795,5 +799,6 @@ int cmd_main(int argc, const char **argv)
setenv(GIT_PROTOCOL_ENVIRONMENT, proto_header, 0);
cmd->imp(&hdr, cmd_arg);
+ free(cmd_arg);
return 0;
}
diff --git a/http-fetch.c b/http-fetch.c
index 31bc5c7..258fec2 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -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) {
diff --git a/list-objects-filter-options.c b/list-objects-filter-options.c
index 5339660..ee01bcd 100644
--- a/list-objects-filter-options.c
+++ b/list-objects-filter-options.c
@@ -290,10 +290,6 @@ int opt_parse_list_objects_filter(const struct option *opt,
const char *arg, int unset)
{
struct list_objects_filter_options *filter_options = opt->value;
- opt_lof_init init = (opt_lof_init)opt->defval;
-
- if (init)
- filter_options = init(opt->value);
if (unset || !arg)
list_objects_filter_set_no_filter(filter_options);
diff --git a/list-objects-filter-options.h b/list-objects-filter-options.h
index 7eeadab..1fe393f 100644
--- a/list-objects-filter-options.h
+++ b/list-objects-filter-options.h
@@ -111,27 +111,13 @@ void parse_list_objects_filter(
* The opt->value to opt_parse_list_objects_filter() is either a
* "struct list_objects_filter_option *" when using
* OPT_PARSE_LIST_OBJECTS_FILTER().
- *
- * Or, if using no "struct option" field is used by the callback,
- * except the "defval" which is expected to be an "opt_lof_init"
- * function, which is called with the "opt->value" and must return a
- * pointer to the ""struct list_objects_filter_option *" to be used.
- *
- * The OPT_PARSE_LIST_OBJECTS_FILTER_INIT() can be used e.g. the
- * "struct list_objects_filter_option" is embedded in a "struct
- * rev_info", which the "defval" could be tasked with lazily
- * initializing. See cmd_pack_objects() for an example.
*/
int opt_parse_list_objects_filter(const struct option *opt,
const char *arg, int unset);
-typedef struct list_objects_filter_options *(*opt_lof_init)(void *);
-#define OPT_PARSE_LIST_OBJECTS_FILTER_INIT(fo, init) \
- { OPTION_CALLBACK, 0, "filter", (fo), N_("args"), \
- N_("object filtering"), 0, opt_parse_list_objects_filter, \
- (intptr_t)(init) }
#define OPT_PARSE_LIST_OBJECTS_FILTER(fo) \
- OPT_PARSE_LIST_OBJECTS_FILTER_INIT((fo), NULL)
+ OPT_CALLBACK(0, "filter", (fo), N_("args"), \
+ N_("object filtering"), opt_parse_list_objects_filter)
/*
* Translates abbreviated numbers in the filter's filter_spec into their
diff --git a/ll-merge.c b/ll-merge.c
index 22a603e..130d265 100644
--- a/ll-merge.c
+++ b/ll-merge.c
@@ -391,7 +391,7 @@ enum ll_merge_result ll_merge(mmbuffer_t *result_buf,
normalize_file(theirs, path, istate);
}
- git_check_attr(istate, path, check);
+ git_check_attr(istate, NULL, path, check);
ll_driver_name = check->items[0].value;
if (check->items[1].value) {
marker_size = atoi(check->items[1].value);
@@ -419,7 +419,7 @@ int ll_merge_marker_size(struct index_state *istate, const char *path)
if (!check)
check = attr_check_initl("conflict-marker-size", NULL);
- git_check_attr(istate, path, check);
+ git_check_attr(istate, NULL, path, check);
if (check->items[0].value) {
marker_size = atoi(check->items[0].value);
if (marker_size <= 0)
diff --git a/merge-recursive.c b/merge-recursive.c
index 2fd0aa9..ae469f8 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -412,7 +412,7 @@ static int unpack_trees_start(struct merge_options *opt,
{
int rc;
struct tree_desc t[3];
- struct index_state tmp_index = { NULL };
+ struct index_state tmp_index = INDEX_STATE_INIT(opt->repo);
memset(&opt->priv->unpack_opts, 0, sizeof(opt->priv->unpack_opts));
if (opt->priv->call_depth)
diff --git a/object-file.c b/object-file.c
index c1b71c2..939865c 100644
--- a/object-file.c
+++ b/object-file.c
@@ -33,6 +33,7 @@
#include "object-store.h"
#include "promisor-remote.h"
#include "submodule.h"
+#include "fsck.h"
/* The maximum size for an object header. */
#define MAX_HEADER_LEN 32
@@ -1211,35 +1212,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;
+ void *map = NULL;
+ struct stat st;
- if (path)
- fd = git_open(path);
- else
- fd = open_loose_object(r, oid, &path);
- map = NULL;
- if (fd >= 0) {
- 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 +1238,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 +1423,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 +1446,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 +1456,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 +1500,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 +1582,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 +1613,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;
}
@@ -1659,21 +1672,6 @@ int oid_object_info(struct repository *r,
return type;
}
-static void *read_object(struct repository *r,
- const struct object_id *oid, enum object_type *type,
- unsigned long *size)
-{
- struct object_info oi = OBJECT_INFO_INIT;
- void *content;
- oi.typep = type;
- oi.sizep = size;
- oi.contentp = &content;
-
- if (oid_object_info_extended(r, oid, &oi, 0) < 0)
- return NULL;
- return content;
-}
-
int pretend_object_file(void *buf, unsigned long len, enum object_type type,
struct object_id *oid)
{
@@ -1695,46 +1693,25 @@ int pretend_object_file(void *buf, unsigned long len, enum object_type type,
/*
* This function dies on corrupt objects; the callers who want to
- * deal with them should arrange to call read_object() and give error
- * messages themselves.
+ * deal with them should arrange to call oid_object_info_extended() and give
+ * error messages themselves.
*/
-void *read_object_file_extended(struct repository *r,
- const struct object_id *oid,
- enum object_type *type,
- unsigned long *size,
- int lookup_replace)
+void *repo_read_object_file(struct repository *r,
+ const struct object_id *oid,
+ enum object_type *type,
+ unsigned long *size)
{
+ struct object_info oi = OBJECT_INFO_INIT;
+ unsigned flags = OBJECT_INFO_DIE_IF_CORRUPT | OBJECT_INFO_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);
- if (data)
- return data;
+ oi.typep = type;
+ oi.sizep = size;
+ oi.contentp = &data;
+ if (oid_object_info_extended(r, oid, &oi, flags))
+ return NULL;
- 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;
+ return data;
}
void *read_object_with_reference(struct repository *r,
@@ -2262,6 +2239,7 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
{
void *buf;
unsigned long len;
+ struct object_info oi = OBJECT_INFO_INIT;
enum object_type type;
char hdr[MAX_HEADER_LEN];
int hdrlen;
@@ -2269,8 +2247,10 @@ 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);
- if (!buf)
+ oi.typep = &type;
+ oi.sizep = &len;
+ oi.contentp = &buf;
+ if (oid_object_info_extended(the_repository, oid, &oi, 0))
return error(_("cannot read object for %s"), oid_to_hex(oid));
hdrlen = format_object_header(hdr, sizeof(hdr), type, len);
ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime, 0);
@@ -2305,32 +2285,21 @@ int repo_has_object_file(struct repository *r,
return repo_has_object_file_with_flags(r, oid, 0);
}
-static void check_tree(const void *buf, size_t size)
+/*
+ * We can't use the normal fsck_error_function() for index_mem(),
+ * because we don't yet have a valid oid for it to report. Instead,
+ * report the minimal fsck error here, and rely on the caller to
+ * give more context.
+ */
+static int hash_format_check_report(struct fsck_options *opts,
+ const struct object_id *oid,
+ enum object_type object_type,
+ enum fsck_msg_type msg_type,
+ enum fsck_msg_id msg_id,
+ const char *message)
{
- struct tree_desc desc;
- struct name_entry entry;
-
- init_tree_desc(&desc, buf, size);
- while (tree_entry(&desc, &entry))
- /* do nothing
- * tree_entry() will die() on malformed entries */
- ;
-}
-
-static void check_commit(const void *buf, size_t size)
-{
- struct commit c;
- memset(&c, 0, sizeof(c));
- if (parse_commit_buffer(the_repository, &c, buf, size, 0))
- die(_("corrupt commit"));
-}
-
-static void check_tag(const void *buf, size_t size)
-{
- struct tag t;
- memset(&t, 0, sizeof(t));
- if (parse_tag_buffer(the_repository, &t, buf, size))
- die(_("corrupt tag"));
+ error(_("object fails fsck: %s"), message);
+ return 1;
}
static int index_mem(struct index_state *istate,
@@ -2357,12 +2326,13 @@ static int index_mem(struct index_state *istate,
}
}
if (flags & HASH_FORMAT_CHECK) {
- if (type == OBJ_TREE)
- check_tree(buf, size);
- if (type == OBJ_COMMIT)
- check_commit(buf, size);
- if (type == OBJ_TAG)
- check_tag(buf, size);
+ struct fsck_options opts = FSCK_OPTIONS_DEFAULT;
+
+ opts.strict = 1;
+ opts.error_func = hash_format_check_report;
+ if (fsck_buffer(null_oid(), type, buf, size, &opts))
+ die(_("refusing to create malformed object"));
+ fsck_finish(&opts);
}
if (write_object)
@@ -2785,13 +2755,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;
diff --git a/object-store.h b/object-store.h
index 1be57ab..1a713d8 100644
--- a/object-store.h
+++ b/object-store.h
@@ -241,17 +241,10 @@ const char *loose_object_path(struct repository *r, struct strbuf *buf,
void *map_loose_object(struct repository *r, const struct object_id *oid,
unsigned long *size);
-void *read_object_file_extended(struct repository *r,
- const struct object_id *oid,
- enum object_type *type,
- unsigned long *size, int lookup_replace);
-static inline void *repo_read_object_file(struct repository *r,
- const struct object_id *oid,
- enum object_type *type,
- unsigned long *size)
-{
- return read_object_file_extended(r, oid, type, size, 1);
-}
+void *repo_read_object_file(struct repository *r,
+ const struct object_id *oid,
+ enum object_type *type,
+ unsigned long *size);
#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
#define read_object_file(oid, type, size) repo_read_object_file(the_repository, oid, type, size)
#endif
@@ -358,8 +351,7 @@ void assert_oid_type(const struct object_id *oid, enum object_type expect);
/*
* Enabling the object read lock allows multiple threads to safely call the
* following functions in parallel: repo_read_object_file(), read_object_file(),
- * read_object_file_extended(), read_object_with_reference(), read_object(),
- * oid_object_info() and oid_object_info_extended().
+ * read_object_with_reference(), oid_object_info() and oid_object_info_extended().
*
* obj_read_lock() and obj_read_unlock() may also be used to protect other
* section which cannot execute in parallel with object reading. Since the used
@@ -434,19 +426,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);
diff --git a/pack-bitmap.c b/pack-bitmap.c
index 440407f..d2a42ab 100644
--- a/pack-bitmap.c
+++ b/pack-bitmap.c
@@ -354,8 +354,8 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git,
if (bitmap_git->pack || bitmap_git->midx) {
struct strbuf buf = STRBUF_INIT;
get_midx_filename(&buf, midx->object_dir);
- /* ignore extra bitmap file; we can only handle one */
- warning(_("ignoring extra bitmap file: '%s'"), buf.buf);
+ trace2_data_string("bitmap", the_repository,
+ "ignoring extra midx bitmap file", buf.buf);
close(fd);
strbuf_release(&buf);
return -1;
@@ -411,9 +411,6 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git
struct stat st;
char *bitmap_name;
- if (open_pack_index(packfile))
- return -1;
-
bitmap_name = pack_bitmap_filename(packfile);
fd = git_open(bitmap_name);
@@ -432,8 +429,8 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git
}
if (bitmap_git->pack || bitmap_git->midx) {
- /* ignore extra bitmap file; we can only handle one */
- warning(_("ignoring extra bitmap file: '%s'"), packfile->pack_name);
+ trace2_data_string("bitmap", the_repository,
+ "ignoring extra bitmap file", packfile->pack_name);
close(fd);
return -1;
}
@@ -458,6 +455,8 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git
return -1;
}
+ trace2_data_string("bitmap", the_repository, "opened bitmap file",
+ packfile->pack_name);
return 0;
}
@@ -525,11 +524,16 @@ static int open_pack_bitmap(struct repository *r,
struct packed_git *p;
int ret = -1;
- assert(!bitmap_git->map);
-
for (p = get_all_packs(r); p; p = p->next) {
- if (open_pack_bitmap_1(bitmap_git, p) == 0)
+ if (open_pack_bitmap_1(bitmap_git, p) == 0) {
ret = 0;
+ /*
+ * The only reason to keep looking is to report
+ * duplicates.
+ */
+ if (!trace2_is_enabled())
+ break;
+ }
}
return ret;
@@ -553,11 +557,20 @@ static int open_midx_bitmap(struct repository *r,
static int open_bitmap(struct repository *r,
struct bitmap_index *bitmap_git)
{
+ int found;
+
assert(!bitmap_git->map);
- if (!open_midx_bitmap(r, bitmap_git))
- return 0;
- return open_pack_bitmap(r, bitmap_git);
+ found = !open_midx_bitmap(r, bitmap_git);
+
+ /*
+ * these will all be skipped if we opened a midx bitmap; but run it
+ * anyway if tracing is enabled to report the duplicates
+ */
+ if (!found || trace2_is_enabled())
+ found |= !open_pack_bitmap(r, bitmap_git);
+
+ return found ? 0 : -1;
}
struct bitmap_index *prepare_bitmap_git(struct repository *r)
diff --git a/packfile.c b/packfile.c
index c0d7dd9..79e21ab 100644
--- a/packfile.c
+++ b/packfile.c
@@ -1650,22 +1650,6 @@ struct unpack_entry_stack_ent {
unsigned long size;
};
-static void *read_object(struct repository *r,
- const struct object_id *oid,
- enum object_type *type,
- unsigned long *size)
-{
- struct object_info oi = OBJECT_INFO_INIT;
- void *content;
- oi.typep = type;
- oi.sizep = size;
- oi.contentp = &content;
-
- if (oid_object_info_extended(r, oid, &oi, 0) < 0)
- return NULL;
- return content;
-}
-
void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
enum object_type *final_type, unsigned long *final_size)
{
@@ -1798,6 +1782,8 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
uint32_t pos;
struct object_id base_oid;
if (!(offset_to_pack_pos(p, obj_offset, &pos))) {
+ struct object_info oi = OBJECT_INFO_INIT;
+
nth_packed_object_id(&base_oid, p,
pack_pos_to_index(p, pos));
error("failed to read delta base object %s"
@@ -1805,7 +1791,13 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
oid_to_hex(&base_oid), (uintmax_t)obj_offset,
p->pack_name);
mark_bad_packed_object(p, &base_oid);
- base = read_object(r, &base_oid, &type, &base_size);
+
+ oi.typep = &type;
+ oi.sizep = &base_size;
+ oi.contentp = &base;
+ if (oid_object_info_extended(r, &base_oid, &oi, 0) < 0)
+ base = NULL;
+
external_base = base;
}
}
diff --git a/parse-options.c b/parse-options.c
index a1ec932..fd47432 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -702,8 +702,7 @@ static struct option *preprocess_options(struct parse_opt_ctx_t *ctx,
if (!nr_aliases)
return NULL;
- ALLOC_ARRAY(newopt, nr + 1);
- COPY_ARRAY(newopt, options, nr + 1);
+ DUP_ARRAY(newopt, options, nr + 1);
/* each alias has two string pointers and NULL */
CALLOC_ARRAY(ctx->alias_groups, 3 * (nr_aliases + 1));
diff --git a/parse-options.h b/parse-options.h
index b6ef86e..50d852f 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -369,6 +369,10 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);
{ OPTION_CALLBACK, 0, "abbrev", (var), N_("n"), \
N_("use <n> digits to display object names"), \
PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
+#define OPT__SUPER_PREFIX(var) \
+ OPT_STRING_F(0, "super-prefix", (var), N_("prefix"), \
+ N_("prefixed path to initial superproject"), PARSE_OPT_HIDDEN)
+
#define OPT__COLOR(var, h) \
OPT_COLOR_FLAG(0, "color", (var), (h))
#define OPT_COLUMN(s, l, v, h) \
diff --git a/pathspec.c b/pathspec.c
index 46e77a8..ab70fcb 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -545,7 +545,7 @@ static void NORETURN unsupported_magic(const char *pattern,
}
/*
* We may want to substitute "this command" with a command
- * name. E.g. when add--interactive dies when running
+ * name. E.g. when "git add -p" or "git add -i" dies when running
* "checkout -p"
*/
die(_("%s: pathspec magic not supported by this command: %s"),
@@ -681,8 +681,7 @@ void copy_pathspec(struct pathspec *dst, const struct pathspec *src)
int i, j;
*dst = *src;
- ALLOC_ARRAY(dst->items, dst->nr);
- COPY_ARRAY(dst->items, src->items, dst->nr);
+ DUP_ARRAY(dst->items, src->items, dst->nr);
for (i = 0; i < dst->nr; i++) {
struct pathspec_item *d = &dst->items[i];
@@ -691,8 +690,7 @@ void copy_pathspec(struct pathspec *dst, const struct pathspec *src)
d->match = xstrdup(s->match);
d->original = xstrdup(s->original);
- ALLOC_ARRAY(d->attr_match, d->attr_match_nr);
- COPY_ARRAY(d->attr_match, s->attr_match, d->attr_match_nr);
+ DUP_ARRAY(d->attr_match, s->attr_match, d->attr_match_nr);
for (j = 0; j < d->attr_match_nr; j++) {
const char *value = s->attr_match[j].value;
d->attr_match[j].value = xstrdup_or_null(value);
@@ -732,7 +730,7 @@ int match_pathspec_attrs(struct index_state *istate,
if (name[namelen])
name = to_free = xmemdupz(name, namelen);
- git_check_attr(istate, name, item->attr_check);
+ git_check_attr(istate, NULL, name, item->attr_check);
free(to_free);
diff --git a/po/bg.po b/po/bg.po
index a2cd8a0..daec132 100644
--- a/po/bg.po
+++ b/po/bg.po
@@ -1,7 +1,7 @@
# Bulgarian translation of git po-file.
-# Copyright (C) 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Alexander Shopov <ash@kambanaria.org>.
+# Copyright (C) 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023 Alexander Shopov <ash@kambanaria.org>.
# This file is distributed under the same license as the git package.
-# Alexander Shopov <ash@kambanaria.org>, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022.
+# Alexander Shopov <ash@kambanaria.org>, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023.
# ========================
# DICTIONARY TO MERGE IN GIT GUI
# ------------------------
@@ -196,6 +196,10 @@
# scalar repo скаларно хранилище
# unclean завършвам работа/задача с грешка
# cache tree кеш за обекти-дървета
+# gitattributes file файл с атрибути на git
+# advertised обявен за наличен
+# superproject свръхпроект
+#
# ------------------------
# „$var“ - може да не сработва за shell има gettext и eval_gettext - проверка - намират се лесно по „$
# ------------------------
@@ -212,10 +216,10 @@
# for i in `sort -u FILES`; do cnt=`grep $i FILES | wc -l`; echo $cnt $i ;done | sort -n
msgid ""
msgstr ""
-"Project-Id-Version: git 2.39\n"
+"Project-Id-Version: git 2.40\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-12-06 15:52+0100\n"
-"PO-Revision-Date: 2022-12-06 16:55+0200\n"
+"POT-Creation-Date: 2023-03-01 01:20+0000\n"
+"PO-Revision-Date: 2023-03-02 08:54+0200\n"
"Last-Translator: Alexander Shopov <ash@kambanaria.org>\n"
"Language-Team: Bulgarian <dict@fsa-bg.org>\n"
"Language: bg\n"
@@ -250,13 +254,13 @@
msgid "could not write index"
msgstr "индексът не може да бъде записан"
-#, c-format, perl-format
+#, c-format
msgid "updated %d path\n"
msgid_plural "updated %d paths\n"
msgstr[0] "%d файл обновен\n"
msgstr[1] "%d файла обновени\n"
-#, c-format, perl-format
+#, c-format
msgid "note: %s is untracked now.\n"
msgstr "БЕЛЕЖКА: „%s“ вече не се следи.\n"
@@ -270,7 +274,7 @@
msgid "Could not parse HEAD^{tree}"
msgstr "Указателят „HEAD^{tree}“ не може да бъде анализиран"
-#, c-format, perl-format
+#, c-format
msgid "reverted %d path\n"
msgid_plural "reverted %d paths\n"
msgstr[0] "%d файл с отменени промѐни\n"
@@ -283,7 +287,7 @@
msgid "Add untracked"
msgstr "Добавяне на неследени"
-#, c-format, perl-format
+#, c-format
msgid "added %d path\n"
msgid_plural "added %d paths\n"
msgstr[0] "%d файл добавен\n"
@@ -377,19 +381,19 @@
msgid "Bye.\n"
msgstr "Изход.\n"
-#, c-format, perl-format
+#, c-format
msgid "Stage mode change [y,n,q,a,d%s,?]? "
msgstr "Добавяне на промяната на права̀та за достъп [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Stage deletion [y,n,q,a,d%s,?]? "
msgstr "Добавяне на изтриването [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Stage addition [y,n,q,a,d%s,?]? "
msgstr "Добавяне на добавянето [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Stage this hunk [y,n,q,a,d%s,?]? "
msgstr "Добавяне на това парче [y,n,q,a,d%s,?]? "
@@ -413,19 +417,19 @@
"a — добавяне на това и всички следващи парчета от файла в индекса\n"
"d — без добавяне на това и всички следващи парчета от файла в индекса\n"
-#, c-format, perl-format
+#, c-format
msgid "Stash mode change [y,n,q,a,d%s,?]? "
msgstr "Скатаване на промяната на права̀та за достъп [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Stash deletion [y,n,q,a,d%s,?]? "
msgstr "Скатаване на изтриването [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Stash addition [y,n,q,a,d%s,?]? "
msgstr "Скатаване на добавянето [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Stash this hunk [y,n,q,a,d%s,?]? "
msgstr "Скатаване на това парче [y,n,q,a,d%s,?]? "
@@ -449,19 +453,19 @@
"a — скатаване на това и всички следващи парчета от файла\n"
"d — без скатаване на това и всички следващи парчета от файла\n"
-#, c-format, perl-format
+#, c-format
msgid "Unstage mode change [y,n,q,a,d%s,?]? "
msgstr "Изваждане на промяната на права̀та за достъп [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Unstage deletion [y,n,q,a,d%s,?]? "
msgstr "Изваждане на изтриването [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Unstage addition [y,n,q,a,d%s,?]? "
msgstr "Изваждане на добавянето [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
msgstr "Изваждане на това парче [y,n,q,a,d%s,?]? "
@@ -485,20 +489,20 @@
"a — изваждане на това и всички следващи парчета от файла от индекса\n"
"d — без изваждане на това и всички следващи парчета от файла от индекса\n"
-#, c-format, perl-format
+#, c-format
msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
msgstr ""
"Прилагане на промяната на права̀та за достъп към индекса [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
msgstr "Прилагане на изтриването към индекса [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply addition to index [y,n,q,a,d%s,?]? "
msgstr "Прилагане на добавянето към индекса [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply this hunk to index [y,n,q,a,d%s,?]? "
msgstr "Прилагане на това парче към индекса [y,n,q,a,d%s,?]? "
@@ -522,21 +526,21 @@
"a — прилагане на това и всички следващи парчета от файла към индекса\n"
"d — без прилагане на това и всички следващи парчета от файла към индекса\n"
-#, c-format, perl-format
+#, c-format
msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Премахване на промяната в права̀та за достъп от работното дърво [y,n,q,a,"
"d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
msgstr "Премахване на изтриването от работното дърво [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Discard addition from worktree [y,n,q,a,d%s,?]? "
msgstr "Премахване на добавянето от работното дърво [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Discard this hunk from worktree [y,n,q,a,d%s,?]? "
msgstr "Премахване на парчето от работното дърво [y,n,q,a,d%s,?]? "
@@ -563,23 +567,23 @@
"d — без премахване на това и всички следващи парчета от файла от работното "
"дърво\n"
-#, c-format, perl-format
+#, c-format
msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Премахване на промяната в права̀та за достъп от индекса и работното дърво [y,"
"n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Премахване на изтриването от индекса и работното дърво [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Discard addition from index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Премахване на добавянето от индекса и работното дърво [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
msgstr "Премахване на парчето от индекса и работното дърво [y,n,q,a,d%s,?]? "
@@ -599,22 +603,22 @@
"d — без премахване на това и всички следващи парчета от файла от индекса и "
"работното дърво\n"
-#, c-format, perl-format
+#, c-format
msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Прилагане на промяната в права̀та за достъп от индекса и работното дърво [y,n,"
"q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Прилагане на изтриването от индекса и работното дърво [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply addition to index and worktree [y,n,q,a,d%s,?]? "
msgstr "Прилагане на добавянето от индекса и работното дърво [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
msgstr "Прилагане на парчето от индекса и работното дърво [y,n,q,a,d%s,?]? "
@@ -634,21 +638,21 @@
"d — без прилагане на това и всички следващи парчета от файла от индекса и "
"работното дърво\n"
-#, c-format, perl-format
+#, c-format
msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Прилагане на промяната в права̀та за достъп към работното дърво [y,n,q,a,"
"d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
msgstr "Прилагане на изтриването към работното дърво [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
msgstr "Прилагане на добавянето към работното дърво [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
msgstr "Прилагане на парчето към работното дърво [y,n,q,a,d%s,?]? "
@@ -725,8 +729,6 @@
"За да пропуснете редовете, започващи с „%c“: изтрийте ги.\n"
"Редовете, които започват с „%c“ ще бъдат пропуснати.\n"
-#. #-#-#-#-# git-add--interactive.perl.po #-#-#-#-#
-#. TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
msgid ""
"If it does not apply cleanly, you will be given an opportunity to\n"
"edit again. If all lines of the hunk are removed, then the edit is\n"
@@ -742,20 +744,12 @@
msgid "'git apply --cached' failed"
msgstr "неуспешно изпълнение на „git apply --cached“"
-#. #-#-#-#-# add-patch.c.po #-#-#-#-#
#. TRANSLATORS: do not translate [y/n]
#. The program will only accept that input at this point.
#. Consider translating (saying "no" discards!) as
#. (saying "n" for "no" discards!) if the translation
#. of the word "no" does not start with n.
#.
-#. #-#-#-#-# git-add--interactive.perl.po #-#-#-#-#
-#. TRANSLATORS: do not translate [y/n]
-#. The program will only accept that input
-#. at this point.
-#. Consider translating (saying "no" discards!) as
-#. (saying "n" for "no" discards!) if the translation
-#. of the word "no" does not start with n.
msgid ""
"Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
msgstr ""
@@ -1621,6 +1615,12 @@
msgid "report archived files on stderr"
msgstr "извеждане на архивираните файлове на стандартната грешка"
+msgid "time"
+msgstr "ВРЕМЕ"
+
+msgid "set modification time of archive entries"
+msgstr "задаване на ВРЕМЕ на промяна на елементите в архива"
+
msgid "set compression level"
msgstr "задаване на нивото на компресиране"
@@ -1661,6 +1661,13 @@
msgid "%.*s is not a valid attribute name"
msgstr "„%.*s“ е неправилно име за атрибут"
+msgid "unable to add additional attribute"
+msgstr "не може да се добави нов атрибут"
+
+#, c-format
+msgid "ignoring overly long attributes line %d"
+msgstr "прескачане на прекалено дълъг ред за атрибути: %d"
+
#, c-format
msgid "%s not allowed: %s:%d"
msgstr "%s: командата не е позволена: „%s:%d“"
@@ -1673,6 +1680,18 @@
"Ако ви трябва начална удивителна, ползвайте „\\!“."
#, c-format
+msgid "cannot fstat gitattributes file '%s'"
+msgstr "неуспешно изпълнение на „fstat“ върху файла за атрибути на git „%s“"
+
+#, c-format
+msgid "ignoring overly large gitattributes file '%s'"
+msgstr "прескачане на прекалено големия файл за атрибути на git: „%s“"
+
+#, c-format
+msgid "ignoring overly large gitattributes blob '%s'"
+msgstr "прескачане на прекалено големия обект-BLOB за атрибути на git: „%s“"
+
+#, c-format
msgid "Badly quoted content in file '%s': %s"
msgstr "Неправилно цитирано съдържание във файла „%s“: %s"
@@ -1951,12 +1970,12 @@
#, c-format
msgid ""
-"You may try updating the submodules using 'git checkout %s && git submodule "
-"update --init'"
+"You may try updating the submodules using 'git checkout --no-recurse-"
+"submodules %s && git submodule update --init'"
msgstr ""
"Може да обновите подмодулите с командата:\n"
"\n"
-" git checkout %s && git submodule update --init"
+" git checkout --no-recurse-submodules %s && git submodule update --init"
#, c-format
msgid "submodule '%s': cannot create branch '%s'"
@@ -1991,6 +2010,13 @@
msgid "Unstaged changes after refreshing the index:"
msgstr "Промѐни, които и след обновяването на индекса не са добавени към него:"
+msgid ""
+"the add.interactive.useBuiltin setting has been removed!\n"
+"See its entry in 'git help config' for details."
+msgstr ""
+"Настройката „add.interactive.useBuiltin“ е премахната!\n"
+"За подробности я потърсете в изхода от „git help config“."
+
msgid "Could not read the index"
msgstr "Индексът не може да бъде прочетен"
@@ -2399,6 +2425,11 @@
msgid "run interactively"
msgstr "интерактивна работа"
+msgid "bypass pre-applypatch and applypatch-msg hooks"
+msgstr ""
+"без изпълнение на куките преди прилагане на кръпка и съобщение преди "
+"прилагане на кръпка"
+
msgid "historical option -- no-op"
msgstr "изоставена опция, съществува по исторически причини, нищо не прави"
@@ -2548,31 +2579,28 @@
msgid "git archive: expected a flush"
msgstr "git archive: очакваше се изчистване на буферите чрез „flush“"
-msgid "git bisect--helper --bisect-reset [<commit>]"
-msgstr "git bisect--helper --bisect-reset [ПОДАВАНЕ]"
-
msgid ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}"
-"=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] "
-"[<paths>...]"
+"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-"
+"checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]"
msgstr ""
-"git bisect--helper --bisect-start [--term-{new,bad}=ЛОШО --term-{old,good}"
-"=ДОБРО] [--no-checkout] [--first-parent] [ЛОШО [ДОБРО…]] [--] [ПЪТ…]"
+"git bisect start [--term-{new,bad}=УПРАВЛЯВАЩА_ДУМА --term-{old,good}"
+"=УПРАВЛЯВАЩА_ДУМА] [--no-checkout] [--first-parent] [ЛОШО [ДОБРО…]] [--] "
+"[ПЪТ…]"
-msgid "git bisect--helper --bisect-state (bad|new) [<rev>]"
-msgstr "git bisect--helper --bisect-state (ЛОШО) [ВЕРСИЯ]"
+msgid "git bisect (good|bad) [<rev>...]"
+msgstr "git bisect (good|bad) [ВЕРСИЯ…]"
-msgid "git bisect--helper --bisect-state (good|old) [<rev>...]"
-msgstr "git bisect--helper --bisect-state (ДОБРО) [ВЕРСИЯ…]"
+msgid "git bisect skip [(<rev>|<range>)...]"
+msgstr "git bisect skip [(ВЕРСИЯ|ДИАПАЗОН)…]"
-msgid "git bisect--helper --bisect-replay <filename>"
-msgstr "git bisect--helper --bisect-replay ИМЕ_НА_ФАЙЛ"
+msgid "git bisect reset [<commit>]"
+msgstr "git bisect reset [ПОДАВАНЕ]"
-msgid "git bisect--helper --bisect-skip [(<rev>|<range>)...]"
-msgstr "git bisect--helper --bisect-skip [(ВЕРСИЯ|ДИАПАЗОН)…]"
+msgid "git bisect replay <logfile>"
+msgstr "git bisect replay ИМЕ_НА_ФАЙЛ"
-msgid "git bisect--helper --bisect-run <cmd>..."
-msgstr "git bisect--helper --bisect-run КОМАНДА…"
+msgid "git bisect run <cmd>..."
+msgstr "git bisect run КОМАНДА…"
#, c-format
msgid "cannot open file '%s' in mode '%s'"
@@ -2721,11 +2749,6 @@
"Неуспешно преминаване към „%s“. Изпълнете командата „git bisect start "
"СЪЩЕСТВУВАЩ_КЛОН“."
-msgid "won't bisect on cg-seek'ed tree"
-msgstr ""
-"не може да се търси двоично, когато е изпълнена командата „cg-seek“ от "
-"„cogito“"
-
msgid "bad HEAD - strange symbolic ref"
msgstr "Неправилен указател „HEAD“ — необичаен символен указател"
@@ -2781,7 +2804,7 @@
msgstr "неуспешно двоично търсене, не е зададена команда."
#, c-format
-msgid "unable to verify '%s' on good revision"
+msgid "unable to verify %s on good revision"
msgstr "„%s“ не може да провери с добра версия"
#, c-format
@@ -2789,7 +2812,7 @@
msgstr "неправилен изходен код %d за добро подаване"
#, c-format
-msgid "bisect run failed: exit code %d from '%s' is < 0 or >= 128"
+msgid "bisect run failed: exit code %d from %s is < 0 or >= 128"
msgstr ""
"неуспешно двоично търсене: изходният код от командата „%2$s“ е %1$d — това е "
"извън интервала [0, 128)"
@@ -2801,37 +2824,42 @@
msgid "bisect run cannot continue any more"
msgstr "двоичното търсене не може да продължи"
-#, c-format
msgid "bisect run success"
msgstr "успешно двоично търсене"
-#, c-format
msgid "bisect found first bad commit"
msgstr "двоичното търсене откри първото лошо подаване"
#, c-format
-msgid ""
-"bisect run failed: 'git bisect--helper --bisect-state %s' exited with error "
-"code %d"
-msgstr ""
-"неуспешно двоично търсене: „git bisect--helper --bisect-state %s“ завърши с "
-"код за грешка: %d"
+msgid "bisect run failed: 'git bisect %s' exited with error code %d"
+msgstr "неуспешно двоично търсене: „git bisect %s“ завърши с код за грешка: %d"
-msgid "--bisect-reset requires either no argument or a commit"
-msgstr "опцията „--bisect-reset“ изисква или 0 аргументи, или 1 — подаване"
+#, c-format
+msgid "'%s' requires either no argument or a commit"
+msgstr "„%s“ изисква или 0 аргументи, или едно подаване"
-msgid "--bisect-terms requires 0 or 1 argument"
-msgstr "опцията „--bisect-terms“ изисква 0 или 1 аргумента"
+#, c-format
+msgid "'%s' requires 0 or 1 argument"
+msgstr "„%s“ изисква 0 или 1 аргумент"
-msgid "--bisect-next requires 0 arguments"
-msgstr "опцията „--bisect-next“ не приема аргументи"
-
-msgid "--bisect-log requires 0 arguments"
-msgstr "опцията „--bisect-log“ не приема аргументи"
+#, c-format
+msgid "'%s' requires 0 arguments"
+msgstr "„%s“ изисква 0 аргументи"
msgid "no logfile given"
msgstr "не е зададен журнален файл"
+#, c-format
+msgid "'%s' failed: no command provided."
+msgstr "неуспешно изпълнение на „%s“: не е зададена команда."
+
+msgid "need a command"
+msgstr "необходима е команда"
+
+#, c-format
+msgid "unknown command: '%s'"
+msgstr "непозната команда: „%s“"
+
msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
msgstr "git blame [ОПЦИЯ…] [ОПЦИЯ_ЗА_ВЕРСИЯТА…] [ВЕРСИЯ] [--] ФАЙЛ"
@@ -3425,6 +3453,9 @@
msgid "git bundle unbundle [--progress] <file> [<refname>...]"
msgstr "git bundle unbundle [--progress] ФАЙЛ [ИМЕ_НА_УКАЗАТЕЛ…]"
+msgid "need a <file> argument"
+msgstr "необходим е аргумент ФАЙЛ"
+
msgid "do not show progress meter"
msgstr "без извеждане на напредъка"
@@ -3479,10 +3510,6 @@
msgid "%s takes no arguments"
msgstr "командата „%s“ не приема аргументи"
-#, c-format
-msgid "unknown command: '%s'"
-msgstr "непозната команда: „%s“"
-
msgid "only one batch option may be specified"
msgstr "може да укажете само една пакетна опция"
@@ -3625,11 +3652,18 @@
msgid "only two arguments allowed in <type> <object> mode, not %d"
msgstr "в режим с посочен ВИД ОБЕКТ се изискват точно два аргумента, а не %d"
-msgid "git check-attr [-a | --all | <attr>...] [--] <pathname>..."
-msgstr "git check-attr [-a | --all | АТРИБУТ…] [--] ПЪТ…"
+msgid ""
+"git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
+"<pathname>..."
+msgstr ""
+"git check-attr [--source УКАЗАТЕЛ_КЪМ_ДЪРВО] [-a | --all | АТРИБУТ…] [--] "
+"ПЪТ…"
-msgid "git check-attr --stdin [-z] [-a | --all | <attr>...]"
-msgstr "git check-attr --stdin [-z] [-a | --all | АТРИБУТ…]"
+msgid ""
+"git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
+msgstr ""
+"git check-attr --stdin [-z] [--source УКАЗАТЕЛ_КЪМ_ДЪРВО] [-a | --all | "
+"АТРИБУТ…]"
msgid "report all attributes set on file"
msgstr "извеждане на всички атрибути, зададени върху файл"
@@ -3643,6 +3677,12 @@
msgid "terminate input and output records by a NUL character"
msgstr "разделяне на входните и изходните записи с нулевия знак „NUL“"
+msgid "<tree-ish>"
+msgstr "УКАЗАТЕЛ_КЪМ_ДЪРВО"
+
+msgid "which tree-ish to check attributes at"
+msgstr "към кой УКАЗАТЕЛ_КЪМ_ДЪРВО да се премине"
+
msgid "suppress progress reporting"
msgstr "без показване на напредъка"
@@ -4231,7 +4271,7 @@
"* — избиране на всички обекти\n"
" — (празно) завършване на избирането\n"
-#, c-format, perl-format
+#, c-format
msgid "Huh (%s)?\n"
msgstr "Неправилен избор (%s).\n"
@@ -4382,9 +4422,6 @@
msgid "create a shallow clone of that depth"
msgstr "плитко клониране до тази ДЪЛБОЧИНА"
-msgid "time"
-msgstr "ВРЕМЕ"
-
msgid "create a shallow clone since a specific time"
msgstr "плитко клониране до момент във времето"
@@ -4635,6 +4672,9 @@
msgid "failed to fetch objects from bundle URI '%s'"
msgstr "неуспешно доставяне на обекти от пратка на адрес „%s“"
+msgid "failed to fetch advertised bundles"
+msgstr "неуспешно доставяне на обявените за налични пратки"
+
msgid "remote transport reported error"
msgstr "отдалеченият транспорт върна грешка"
@@ -5918,29 +5958,6 @@
msgid "no <cmd> given for --extcmd=<cmd>"
msgstr "не е зададена команда за „--extcmd=КОМАНДА“"
-msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
-msgstr "git env--helper --type=[bool|ulong] ОПЦИИ ПРОМЕНЛИВИ"
-
-msgid "default for git_env_*(...) to fall back on"
-msgstr "стандартна, резервна стойност за „git_env_*(…)“"
-
-msgid "be quiet only use git_env_*() value as exit code"
-msgstr ""
-"без извеждане на информация — стойността на „git_env_*()“ да е изходен код"
-
-#, c-format
-msgid "option `--default' expects a boolean value with `--type=bool`, not `%s`"
-msgstr ""
-"опцията „--default“ изисква булева стойност при „--type=bool“, а не „%s“"
-
-#, c-format
-msgid ""
-"option `--default' expects an unsigned long value with `--type=ulong`, not "
-"`%s`"
-msgstr ""
-"опцията „--default“ изисква целочислена стойност без знак при „--"
-"type=ulong“, а не „%s“"
-
msgid "git fast-export [<rev-list-opts>]"
msgstr "git fast-export [ОПЦИЯ_ЗА_СПИСЪКА_С_ВЕРСИИ…]"
@@ -6349,6 +6366,10 @@
msgid "--unshallow on a complete repository does not make sense"
msgstr "не може да използвате опцията „--unshallow“ върху пълно хранилище"
+#, c-format
+msgid "failed to fetch bundles from '%s'"
+msgstr "неуспешно доставяне на пратки от „%s“"
+
msgid "fetch --all does not take a repository argument"
msgstr "към „git fetch --all“ не може да добавите аргумент-хранилище"
@@ -7393,12 +7414,18 @@
msgid "'git help config' for more information"
msgstr "За повече информация изпълнете „git help config“"
-msgid "git hook run [--ignore-missing] <hook-name> [-- <hook-args>]"
-msgstr "git hook run [--ignore-missing] КУКА [-- АРГУМЕНТ_ЗА_КУКА…]"
+msgid ""
+"git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-"
+"args>]"
+msgstr ""
+"git hook run [--ignore-missing] [--to-stdin=ПЪТ] КУКА [-- АРГУМЕНТ_ЗА_КУКА…]"
msgid "silently ignore missing requested <hook-name>"
msgstr "прескачане на заявена КУКА, която липсва"
+msgid "file to read into hooks' stdin"
+msgstr "файл за изчитане от стандартния вход на куката"
+
#, c-format
msgid "object type mismatch at %s"
msgstr "неправилен вид на обекта „%s“"
@@ -8251,11 +8278,11 @@
msgid ""
"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
" [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
-" [--symref] [<repository> [<refs>...]]"
+" [--symref] [<repository> [<patterns>...]]"
msgstr ""
"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=КОМАНДА]\n"
" [-q | --quiet] [--exit-code] [--get-url] [--sort=КЛЮЧ]\n"
-" [--symref] [ХРАНИЛИЩЕ [УКАЗАТЕЛ…]]"
+" [--symref] [ХРАНИЛИЩЕ [ШАБЛОН]]"
msgid "do not print remote URL"
msgstr "без извеждане на адресите на отдалечените хранилища"
@@ -8507,9 +8534,15 @@
msgid "perform multiple merges, one per line of input"
msgstr "извършване на множество сливания, по едно на ред"
+msgid "specify a merge-base for the merge"
+msgstr "база за сливането"
+
msgid "--trivial-merge is incompatible with all other options"
msgstr "„--trivial-merge“ е несъвместима с другите опции"
+msgid "--merge-base is incompatible with --stdin"
+msgstr "опциите „--merge-base“ и „--stdin“ са несъвместими"
+
#, c-format
msgid "malformed input line: '%s'."
msgstr "входен ред с неправилен формат: „%s“."
@@ -10455,6 +10488,9 @@
msgid "could not switch to %s"
msgstr "не може да се премине към „%s“"
+msgid "apply options and merge options cannot be used together"
+msgstr "опциите за прилагане и сливане са несъвместими"
+
#, c-format
msgid ""
"unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
@@ -10700,8 +10736,19 @@
msgstr ""
"опцията „--strategy“ изисква някоя от опциите „--merge“ или „--interactive“"
-msgid "apply options and merge options cannot be used together"
-msgstr "опциите за прилагане и сливане са несъвместими"
+msgid ""
+"apply options are incompatible with rebase.autosquash. Consider adding --no-"
+"autosquash"
+msgstr ""
+"опциите за прилагане са несъвместими с „rebase.autosquash“. Пробвайте да "
+"добавите опцията „--no-autosquash“"
+
+msgid ""
+"apply options are incompatible with rebase.updateRefs. Consider adding --no-"
+"update-refs"
+msgstr ""
+"опциите за прилагане са несъвместими с „rebase.updateRefs“. Пробвайте да "
+"добавите опцията „--no-update-refs“"
#, c-format
msgid "Unknown rebase backend: %s"
@@ -12221,7 +12268,7 @@
msgstr "извеждане на недостижимите указатели"
msgid "show commits in topological order"
-msgstr "извеждане на подаванията в топологическа подредба"
+msgstr "извеждане на подаванията в топологична подредба"
msgid "show only commits not on the first branch"
msgstr "извеждане само на подаванията, които не са от първия клон"
@@ -12231,7 +12278,7 @@
msgid "topologically sort, maintaining date order where possible"
msgstr ""
-"топологическа подредба, при запазване на подредбата по дата, доколкото е\n"
+"топологична подредба, при запазване на подредбата по дата, доколкото е\n"
"възможно"
msgid "<n>[,<base>]"
@@ -13247,10 +13294,6 @@
msgid "git submodule--helper <command>"
msgstr "git submodule--helper КОМАНДА"
-#, c-format
-msgid "%s doesn't support --super-prefix"
-msgstr "„%s“ не поддържа опцията „--super-prefix“"
-
msgid "git symbolic-ref [-m <reason>] <name> <ref>"
msgstr "git symbolic-ref [-m ПРИЧИНА] ИМЕ УКАЗАТЕЛ"
@@ -14013,6 +14056,11 @@
msgstr "„core.fsyncMethod = batch“ не се поддържа на тази платформа"
#, c-format
+msgid "could not parse bundle list key %s with value '%s'"
+msgstr ""
+"ключът за списък с пратки „%s“ не може да се анализира със стойност „%s“"
+
+#, c-format
msgid "bundle list at '%s' has no mode"
msgstr "липсва режим в списъка от пратки „%s“"
@@ -14023,6 +14071,13 @@
msgstr "недостатъчно възможности"
#, c-format
+msgid "file downloaded from '%s' is not a bundle"
+msgstr "изтегленият от адрес „%s“ файл не е пратка"
+
+msgid "failed to store maximum creation token"
+msgstr "неуспешно запазване на данните за последно създаденото"
+
+#, c-format
msgid "unrecognized bundle mode from URI '%s'"
msgstr "непознат режим на пратки от адрес „%s“"
@@ -14039,6 +14094,13 @@
msgid "file at URI '%s' is not a bundle or bundle list"
msgstr "файлът на адрес „%s“ не е нито пратка, нито списък с пратки"
+#, c-format
+msgid "bundle-uri: unexpected argument: '%s'"
+msgstr "bundle-uri: непознат аргумент: %s"
+
+msgid "bundle-uri: expected flush after arguments"
+msgstr "bundle-uri: след аргументите се очаква изчистване на буферите"
+
msgid "bundle-uri: got an empty line"
msgstr "bundle-uri: получен е празен ред"
@@ -14070,6 +14132,13 @@
msgid "need a repository to verify a bundle"
msgstr "за проверката на пратка е необходимо хранилище"
+msgid ""
+"some prerequisite commits exist in the object store, but are not connected "
+"to the repository's history"
+msgstr ""
+"в хранилището на обекти съществуват необходими подавания, които не са "
+"свързани с историята на хранилището"
+
#, c-format
msgid "The bundle contains this ref:"
msgid_plural "The bundle contains these %<PRIuMAX> refs:"
@@ -15526,15 +15595,23 @@
msgstr "сървърът указа непознат формат на обект: „%s“"
#, c-format
+msgid "error on bundle-uri response line %d: %s"
+msgstr "грешка на ред %d в отговора на командата „bundle-uri“: %s"
+
+msgid "expected flush after bundle-uri listing"
+msgstr ""
+"след изброяването на адресите на пратките се очаква изчистване на буферите"
+
+msgid "expected response end packet after ref listing"
+msgstr "след изброяването на указателите се очаква пакет за край"
+
+#, c-format
msgid "invalid ls-refs response: %s"
msgstr "неправилен отговор на „ls-refs“: „%s“"
msgid "expected flush after ref listing"
msgstr "след изброяването на указателите се очаква изчистване на буферите"
-msgid "expected response end packet after ref listing"
-msgstr "след изброяването на указателите се очаква пакет за край"
-
#, c-format
msgid "protocol '%s' is not supported"
msgstr "протокол „%s“ не се поддържа"
@@ -16673,7 +16750,7 @@
#, c-format
msgid "Server does not allow request for unadvertised object %s"
-msgstr "Сървърът не позволява заявка за необявен обект „%s“"
+msgstr "Сървърът не позволява заявка за необявен за наличен обект „%s“"
#, c-format
msgid "fsmonitor_ipc__send_query: invalid path '%s'"
@@ -16720,16 +16797,20 @@
" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
"bare]\n"
" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
-" [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
-" <command> [<args>]"
+" [--config-env=<name>=<envvar>] <command> [<args>]"
msgstr ""
+"git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n"
+" [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
+" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
+"bare]\n"
+" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
+" [--config-env=<name>=<envvar>] <command> [<args>]\n"
"git [-v | --version] [-h | --help] [-C ПЪТ] [-c ИМЕ=СТОЙНОСТ]\n"
" [--exec-path[=ПЪТ]] [--html-path] [--man-path] [--info-path]\n"
" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
"bare]\n"
" [--git-dir=ПЪТ] [--work-tree=ПЪТ] [--namespace=ИМЕ]\n"
-" [--super-prefix=ПЪТ] [--config-env=ИМЕ=ПРОМЕНЛИВА_НА_СРЕДАТА]\n"
-" КОМАНДА [АРГ…]"
+" [--config-env=ИМЕ=ПРОМЕНЛИВА_НА_СРЕДАТА] КОМАНДА [АРГ…]"
msgid ""
"'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -16757,10 +16838,6 @@
msgstr "опцията „--namespace“ изисква име\n"
#, c-format
-msgid "no prefix given for --super-prefix\n"
-msgstr "опцията „--super-prefix“ изисква префикс\n"
-
-#, c-format
msgid "-c expects a configuration string\n"
msgstr "опцията „-c“ изисква низ за настройка\n"
@@ -16880,8 +16957,13 @@
msgid "gpg.ssh.defaultKeyCommand failed: %s %s"
msgstr "неуспешно изпълнение на „gpg.ssh.defaultKeyCommand“: %s %s"
-msgid "gpg failed to sign the data"
-msgstr "Програмата „gpg“ не подписа данните"
+#, c-format
+msgid ""
+"gpg failed to sign the data:\n"
+"%s"
+msgstr ""
+"Програмата „gpg“ не подписа данните:\n"
+"%s"
msgid "user.signingKey needs to be set for ssh signing"
msgstr ""
@@ -17473,7 +17555,7 @@
" or update to an existing commit which has merged those changes\n"
msgstr ""
" ⁃ преминаване към подмодула (%s), след които или де се слее подаването\n"
-" „%s“, или да се обновяви към съществуващо подаване, в които\n"
+" „%s“, или да се обнови към съществуващо подаване, в които\n"
" тези промени са слети\n"
#, c-format
@@ -18070,6 +18152,10 @@
msgstr "грешни данни в края на непакетирания обект „%s“"
#, c-format
+msgid "unable to open loose object %s"
+msgstr "непакетираният обект „%s“ не може да се отвори"
+
+#, c-format
msgid "unable to parse %s header"
msgstr "заглавната част на „%s“ не може да бъде анализирана"
@@ -18085,18 +18171,14 @@
msgstr "заглавната част на „%s“ е прекалено дълга — надхвърля %d байта"
#, c-format
-msgid "failed to read object %s"
-msgstr "обектът „%s“ не може да бъде прочетен"
+msgid "loose object %s (stored in %s) is corrupt"
+msgstr "непакетираният обект „%s“ (в „%s“) е повреден"
#, c-format
msgid "replacement %s not found for %s"
msgstr "заместителят „%s“ на „%s“ не може да бъде открит"
#, c-format
-msgid "loose object %s (stored in %s) is corrupt"
-msgstr "непакетираният обект „%s“ (в „%s“) е повреден"
-
-#, c-format
msgid "packed object %s (stored in %s) is corrupt"
msgstr "пакетираният обект „%s“ (в „%s“) е повреден"
@@ -18108,9 +18190,6 @@
msgid "unable to set permission to '%s'"
msgstr "права̀та за достъп до „%s“ не може да бъдат зададени"
-msgid "file write error"
-msgstr "грешка при запис на файл"
-
msgid "error when closing loose object file"
msgstr "грешка при затварянето на файла с непакетиран обект"
@@ -18157,11 +18236,12 @@
msgid "cannot read object for %s"
msgstr "обектът за „%s“ не може да се прочете"
-msgid "corrupt commit"
-msgstr "повредено подаване"
+#, c-format
+msgid "object fails fsck: %s"
+msgstr "„fsck“ откри грешка в обект: „%s“"
-msgid "corrupt tag"
-msgstr "повреден етикет"
+msgid "refusing to create malformed object"
+msgstr "не може да се създаде сгрешен обект"
#, c-format
msgid "read error while indexing %s"
@@ -18432,10 +18512,6 @@
msgid "cannot fstat bitmap file"
msgstr "не може да се получи информация за файла с битови маски с „fstat“"
-#, c-format
-msgid "ignoring extra bitmap file: '%s'"
-msgstr "игнориране на излишния файл с битови маски: „%s“"
-
msgid "checksum doesn't match in MIDX and bitmap"
msgstr ""
"сумата за проверка се различава във файла с индекса за множество пакети и "
@@ -18721,6 +18797,9 @@
msgid "use <n> digits to display object names"
msgstr "да се показват такъв БРОЙ цифри от имената на обектите"
+msgid "prefixed path to initial superproject"
+msgstr "път с префикс към първоначалния свръхпроект"
+
msgid "how to strip spaces and #comments from message"
msgstr "кои празни знаци и #коментари да се махат от съобщенията"
@@ -19240,6 +19319,14 @@
msgstr "напред с %d, назад с %d"
#, c-format
+msgid "%%(%.*s) does not take arguments"
+msgstr "%%(%.*s) не приема аргументи"
+
+#, c-format
+msgid "unrecognized %%(%.*s) argument: %s"
+msgstr "непознат аргумент за „%%(%.*s)“: %s"
+
+#, c-format
msgid "expected format: %%(color:<color>)"
msgstr "очакван формат: %%(color:ЦВЯТ)"
@@ -19256,22 +19343,6 @@
msgstr "очаква се цяло число за „refname:rstrip=%s“"
#, c-format
-msgid "unrecognized %%(%s) argument: %s"
-msgstr "непознат аргумент за „%%(%s)“: %s"
-
-#, c-format
-msgid "%%(objecttype) does not take arguments"
-msgstr "%%(objecttype) не приема аргументи"
-
-#, c-format
-msgid "%%(deltabase) does not take arguments"
-msgstr "%%(deltabase) не приема аргументи"
-
-#, c-format
-msgid "%%(body) does not take arguments"
-msgstr "%%(body) не приема аргументи"
-
-#, c-format
msgid "expected %%(trailers:key=<value>)"
msgstr "очаква се %%(trailers:key=ЕПИЛОГ)"
@@ -19288,10 +19359,6 @@
msgstr "очаква се положителна стойност за „%s“ в %%(%s)"
#, c-format
-msgid "unrecognized email option: %s"
-msgstr "непозната опция за е-поща: %s"
-
-#, c-format
msgid "expected format: %%(align:<width>,<position>)"
msgstr "очакван формат: %%(align:ШИРОЧИНА,ПОЗИЦИЯ)"
@@ -19304,12 +19371,12 @@
msgstr "непозната широчина: %s"
#, c-format
-msgid "positive width expected with the %%(align) atom"
-msgstr "очаква се положителна широчина с лексемата „%%(align)“"
+msgid "unrecognized %%(%s) argument: %s"
+msgstr "непознат аргумент за „%%(%s)“: %s"
#, c-format
-msgid "%%(rest) does not take arguments"
-msgstr "%%(rest) не приема аргументи"
+msgid "positive width expected with the %%(align) atom"
+msgstr "очаква се положителна широчина с лексемата „%%(align)“"
#, c-format
msgid "malformed field name: %.*s"
@@ -20601,6 +20668,23 @@
msgstr "git %s: неуспешно обновяване на индекса"
#, c-format
+msgid "'%s' is not a valid label"
+msgstr "„%s“ е неправилен етикет"
+
+#, c-format
+msgid "'%s' is not a valid refname"
+msgstr "„%s“ е неправилно име на указател"
+
+#, c-format
+msgid "update-ref requires a fully qualified refname e.g. refs/heads/%s"
+msgstr ""
+"командата „update-ref“ изисква пълно име на указател, напр. „refs/heads/%s“"
+
+#, c-format
+msgid "invalid command '%.*s'"
+msgstr "неправилна команда „%.*s“"
+
+#, c-format
msgid "%s does not accept arguments: '%s'"
msgstr "„%s“ не приема аргументи: „%s“"
@@ -21426,6 +21510,16 @@
msgid "failed to lstat '%s'"
msgstr "не може да бъде получена информация чрез „lstat“ за „%s“"
+msgid "no remote configured to get bundle URIs from"
+msgstr "не е настроено отдалечено хранилище за списъците с адреси на пратки"
+
+#, c-format
+msgid "remote '%s' has no configured URL"
+msgstr "не е зададен никакъв адрес за отдалеченото хранилище„%s“"
+
+msgid "could not get the bundle-uri list"
+msgstr "списъкът с адреси на пратки не може да се получи"
+
msgid "test-tool cache-tree <options> (control|prime|update)"
msgstr "test-tool cache-tree ОПЦИЯ… (control|prime|update)"
@@ -21785,6 +21879,14 @@
msgid "failed to push all needed submodules"
msgstr "неуспешно изтласкване на всички необходими подмодули"
+msgid "bundle-uri operation not supported by protocol"
+msgstr "операцията „bundle-uri“ (адреси на пратки) не се поддържа от протокола"
+
+msgid "could not retrieve server-advertised bundle-uri list"
+msgstr ""
+"спъсъкът с адреси на пратки обявени за налични от сървъра не може да се "
+"получи "
+
msgid "too-short tree object"
msgstr "прекалено кратък обект-дърво"
@@ -22533,14 +22635,18 @@
#, c-format
msgid ""
-"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')."
+"It took %.2f seconds to enumerate untracked files,\n"
+"but the results were cached, and subsequent runs may be faster."
msgstr ""
-"Бяха необходими %.2f секунди за изброяването на неследените файлове.\n"
-"Добавянето на опцията „-uno“ към командата „git status“ ще ускори\n"
-"изпълнението, но ще трябва да добавяте новите файлове ръчно.\n"
-"За повече подробности погледнете „git status help“."
+"Изброяването на неследените файлове отне %.2f секунди, но\n"
+"резултатите са запомнени и може да забързат последващиге изброявания."
+
+#, c-format
+msgid "It took %.2f seconds to enumerate untracked files."
+msgstr "Изброяването на неследените файлове отне %.2f секунди."
+
+msgid "See 'git help status' for information on how to improve this."
+msgstr "Вижте в „git help status“ за начините да подобрите това."
#, c-format
msgid "Untracked files not listed%s"
@@ -22689,294 +22795,6 @@
msgid "Unable to determine absolute path of git directory"
msgstr "Абсолютният път на работното дърво не може да се определи"
-#. TRANSLATORS: you can adjust this to align "git add -i" status menu
-#, perl-format
-msgid "%12s %12s %s"
-msgstr "%14s %14s %s"
-
-#, perl-format
-msgid "touched %d path\n"
-msgid_plural "touched %d paths\n"
-msgstr[0] "%d файл засегнат\n"
-msgstr[1] "%d файла засегнати\n"
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for staging."
-msgstr ""
-"Ако кръпката може да се приложи чисто, редактираното парче ще бъде "
-"незабавно\n"
-"добавено към индекса"
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for stashing."
-msgstr ""
-"Ако кръпката може да се приложи чисто, редактираното парче ще бъде "
-"незабавно\n"
-"скътано"
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for unstaging."
-msgstr ""
-"Ако кръпката може да се приложи чисто, редактираното парче ще бъде "
-"незабавно\n"
-"извадено от индекса."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for applying."
-msgstr ""
-"Ако кръпката може да се приложи чисто, редактираното парче ще бъде "
-"незабавно\n"
-"набелязано за прилагане."
-
-msgid ""
-"If the patch applies cleanly, the edited hunk will immediately be\n"
-"marked for discarding."
-msgstr ""
-"Ако кръпката може да се приложи чисто, редактираното парче ще бъде "
-"незабавно\n"
-"набелязано за зануляване."
-
-#, perl-format
-msgid "failed to open hunk edit file for writing: %s"
-msgstr "файлът за редактиране на парчето код не може да бъде отворен: „%s“"
-
-#, perl-format
-msgid ""
-"---\n"
-"To remove '%s' lines, make them ' ' lines (context).\n"
-"To remove '%s' lines, delete them.\n"
-"Lines starting with %s will be removed.\n"
-msgstr ""
-"———\n"
-"За да пропуснете редовете започващи с „%s“ — заменете знака със „ “ (стават "
-"контекст)\n"
-"За да пропуснете редовете започващи с „%s“ — изтрийте ги.\n"
-"Редовете, които започват с „%s“ ще бъдат пропуснати.\n"
-
-#, perl-format
-msgid "failed to open hunk edit file for reading: %s"
-msgstr ""
-"файлът за редактиране на парчето код не може да бъде отворен за четене: „%s“"
-
-msgid ""
-"y - stage this hunk\n"
-"n - do not stage this hunk\n"
-"q - quit; do not stage this hunk or any of the remaining ones\n"
-"a - stage this hunk and all later hunks in the file\n"
-"d - do not stage this hunk or any of the later hunks in the file"
-msgstr ""
-"y — добавяне на парчето в индекса\n"
-"n — без добавяне на парчето в индекса\n"
-"q — изход, без добавяне на това и всички оставащи парчета от файла\n"
-"a — добавяне на това и всички следващи парчета от файла в индекса\n"
-"d — без добавяне на това и всички следващи парчета от файла в индекса"
-
-msgid ""
-"y - stash this hunk\n"
-"n - do not stash this hunk\n"
-"q - quit; do not stash this hunk or any of the remaining ones\n"
-"a - stash this hunk and all later hunks in the file\n"
-"d - do not stash this hunk or any of the later hunks in the file"
-msgstr ""
-"y — скатаване на парчето\n"
-"n — без скатаване на парчето\n"
-"q — изход, без скатаване на това и всички оставащи парчета\n"
-"a — скатаване на това и всички следващи парчета от файла\n"
-"d — без скатаване на това и всички следващи парчета от файла"
-
-msgid ""
-"y - unstage this hunk\n"
-"n - do not unstage this hunk\n"
-"q - quit; do not unstage this hunk or any of the remaining ones\n"
-"a - unstage this hunk and all later hunks in the file\n"
-"d - do not unstage this hunk or any of the later hunks in the file"
-msgstr ""
-"y — изваждане на парчето от индекса\n"
-"n — без изваждане на парчето от индекса\n"
-"q — изход, без изваждане на това и всички оставащи парчета от индекса\n"
-"a — изваждане на това и всички следващи парчета от файла от индекса\n"
-"d — без изваждане на това и всички следващи парчета от файла от индекса"
-
-msgid ""
-"y - apply this hunk to index\n"
-"n - do not apply this hunk to index\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y — прилагане на парчето към индекса\n"
-"n — без прилагане на парчето към индекса\n"
-"q — изход, без прилагане на това и всички оставащи парчета към индекса\n"
-"a — прилагане на това и всички следващи парчета от файла към индекса\n"
-"d — без прилагане на това и всички следващи парчета от файла към индекса"
-
-msgid ""
-"y - discard this hunk from worktree\n"
-"n - do not discard this hunk from worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-"y — премахване на парчето от работното дърво\n"
-"n — без премахване на парчето от работното дърво\n"
-"q — изход, без премахване на това и всички оставащи парчета от работното "
-"дърво\n"
-"a — премахване на това и всички следващи парчета от файла от работното "
-"дърво\n"
-"d — без премахване на това и всички следващи парчета от файла от работното "
-"дърво"
-
-msgid ""
-"y - discard this hunk from index and worktree\n"
-"n - do not discard this hunk from index and worktree\n"
-"q - quit; do not discard this hunk or any of the remaining ones\n"
-"a - discard this hunk and all later hunks in the file\n"
-"d - do not discard this hunk or any of the later hunks in the file"
-msgstr ""
-"y — премахване на парчето от индекса и работното дърво\n"
-"n — без премахване на парчето от индекса и работното дърво\n"
-"q — изход, без премахване на това и всички оставащи парчета от индекса и "
-"работното дърво\n"
-"a — премахване на това и всички следващи парчета от файла от индекса и "
-"работното дърво\n"
-"d — без премахване на това и всички следващи парчета от файла от индекса и "
-"работното дърво"
-
-msgid ""
-"y - apply this hunk to index and worktree\n"
-"n - do not apply this hunk to index and worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y — прилагане на парчето от индекса и работното дърво\n"
-"n — без прилагане на парчето от индекса и работното дърво\n"
-"q — изход, без прилагане на това и всички оставащи парчета от индекса и "
-"работното дърво\n"
-"a — прилагане на това и всички следващи парчета от файла от индекса и "
-"работното дърво\n"
-"d — без прилагане на това и всички следващи парчета от файла от индекса и "
-"работното дърво"
-
-msgid ""
-"y - apply this hunk to worktree\n"
-"n - do not apply this hunk to worktree\n"
-"q - quit; do not apply this hunk or any of the remaining ones\n"
-"a - apply this hunk and all later hunks in the file\n"
-"d - do not apply this hunk or any of the later hunks in the file"
-msgstr ""
-"y — прилагане на парчето към работното дърво\n"
-"n — без прилагане на парчето към работното дърво\n"
-"q — изход, без прилагане на това и всички оставащи парчета\n"
-"a — прилагане на това и всички следващи парчета от файла\n"
-"d — без прилагане на това и всички следващи парчета от файла"
-
-msgid ""
-"g - select a hunk to go to\n"
-"/ - search for a hunk matching the given regex\n"
-"j - leave this hunk undecided, see next undecided hunk\n"
-"J - leave this hunk undecided, see next hunk\n"
-"k - leave this hunk undecided, see previous undecided hunk\n"
-"K - leave this hunk undecided, see previous hunk\n"
-"s - split the current hunk into smaller hunks\n"
-"e - manually edit the current hunk\n"
-"? - print help\n"
-msgstr ""
-"g — избор към кое парче да се премине\n"
-"/ — търсене на парче, напасващо към даден регулярен израз\n"
-"j — без решение за парчето, към следващото парче без решение\n"
-"J — без решение за парчето, към следващото парче\n"
-"k — без решение за парчето, към предишното парче без решение\n"
-"K — без решение за парчето, към предишното парче\n"
-"s — разделяне на текущото парче на по-малки\n"
-"e — ръчно редактиране на текущото парче\n"
-"? — извеждане не помощта\n"
-
-msgid "The selected hunks do not apply to the index!\n"
-msgstr "Избраните парчета не може да се добавят в индекса!\n"
-
-#, perl-format
-msgid "ignoring unmerged: %s\n"
-msgstr "пренебрегване на неслятото: „%s“\n"
-
-msgid "No other hunks to goto\n"
-msgstr "Няма други парчета\n"
-
-#, perl-format
-msgid "Invalid number: '%s'\n"
-msgstr "Неправилен номер: „%s“\n"
-
-#, perl-format
-msgid "Sorry, only %d hunk available.\n"
-msgid_plural "Sorry, only %d hunks available.\n"
-msgstr[0] "Има само %d парче.\n"
-msgstr[1] "Има само %d парчета.\n"
-
-msgid "No other hunks to search\n"
-msgstr "Няма други парчета за търсене\n"
-
-#, perl-format
-msgid "Malformed search regexp %s: %s\n"
-msgstr "Сгрешен регулярен израз „%s“: %s\n"
-
-msgid "No hunk matches the given pattern\n"
-msgstr "Никое парче не напасва на регулярния израз\n"
-
-msgid "No previous hunk\n"
-msgstr "Няма друго парче преди това\n"
-
-msgid "No next hunk\n"
-msgstr "Няма друго парче след това\n"
-
-msgid "Sorry, cannot split this hunk\n"
-msgstr "Това парче не може да бъде разделено\n"
-
-#, perl-format
-msgid "Split into %d hunk.\n"
-msgid_plural "Split into %d hunks.\n"
-msgstr[0] "Разделяне на %d парче.\n"
-msgstr[1] "Разделяне на %d парчета.\n"
-
-msgid "Sorry, cannot edit this hunk\n"
-msgstr "Това парче не може да бъде редактирано\n"
-
-#. TRANSLATORS: please do not translate the command names
-#. 'status', 'update', 'revert', etc.
-msgid ""
-"status - show paths with changes\n"
-"update - add working tree state to the staged set of changes\n"
-"revert - revert staged set of changes back to the HEAD version\n"
-"patch - pick hunks and update selectively\n"
-"diff - view diff between HEAD and index\n"
-"add untracked - add contents of untracked files to the staged set of "
-"changes\n"
-msgstr ""
-"status — извеждане на пътищата с промѐните\n"
-"update — добавяне на състоянието на работното дърво към промѐните в\n"
-" индекса\n"
-"revert — отмяна на промѐните в индекса към състоянието сочено от "
-"„HEAD“\n"
-"patch — избиране на парчета код и обновяване поединично\n"
-"diff — извеждане на разликата между състоянието на соченото от "
-"„HEAD“\n"
-" и индекса\n"
-"add untracked — добавяне на неследените файлове към промѐните в индекса\n"
-
-msgid "missing --"
-msgstr "„--“ липсва"
-
-#, perl-format
-msgid "unknown --patch mode: %s"
-msgstr "неизвестна стратегия за прилагане на кръпка към „--patch“: „%s“"
-
-#, perl-format
-msgid "invalid argument %s, expecting --"
-msgstr "указан е неправилен аргумент „%s“, а се очаква „--“."
-
msgid "local zone differs from GMT by a non-minute interval\n"
msgstr ""
"разликата между местния часови пояс и GMT съдържа дробна част от минута\n"
diff --git a/po/ca.po b/po/ca.po
index 9141148..c6d2dd6 100644
--- a/po/ca.po
+++ b/po/ca.po
@@ -1,7 +1,7 @@
# Catalan translations for Git.
# This file is distributed under the same license as the Git package.
# Alex Henrie <alexhenrie24@gmail.com>, 2014-2016.
-# Jordi Mas i Hernàndez <jmas@softcatala.org>, 2016-2022
+# Jordi Mas i Hernàndez <jmas@softcatala.org>, 2016-2023
#
# Terminologia i criteris utilitzats
#
@@ -68,8 +68,8 @@
msgstr ""
"Project-Id-Version: Git\n"
"Report-Msgid-Bugs-To: Git Mailing List <git@vger.kernel.org>\n"
-"POT-Creation-Date: 2022-12-07 07:33+0100\n"
-"PO-Revision-Date: 2022-12-07 19:00-0600\n"
+"POT-Creation-Date: 2023-03-01 01:20+0000\n"
+"PO-Revision-Date: 2023-03-01 19:00-0600\n"
"Last-Translator: Jordi Mas i Hernàndez <jmas@softcatala.org>\n"
"Language-Team: Catalan\n"
"Language: ca\n"
@@ -105,13 +105,13 @@
msgid "could not write index"
msgstr "no s'ha pogut escriure l'índex"
-#, c-format, perl-format
+#, c-format
msgid "updated %d path\n"
msgid_plural "updated %d paths\n"
msgstr[0] "actualitzat %d camí\n"
msgstr[1] "actualitzats %d camins\n"
-#, c-format, perl-format
+#, c-format
msgid "note: %s is untracked now.\n"
msgstr "nota: %s està ara sense seguiment.\n"
@@ -125,7 +125,7 @@
msgid "Could not parse HEAD^{tree}"
msgstr "No s'ha pogut analitzar HEAD^{tree}"
-#, c-format, perl-format
+#, c-format
msgid "reverted %d path\n"
msgid_plural "reverted %d paths\n"
msgstr[0] "revertit %d camí\n"
@@ -138,7 +138,7 @@
msgid "Add untracked"
msgstr "Afegeix sense seguiment"
-#, c-format, perl-format
+#, c-format
msgid "added %d path\n"
msgid_plural "added %d paths\n"
msgstr[0] "afegit %d camí\n"
@@ -232,19 +232,19 @@
msgid "Bye.\n"
msgstr "Adeu.\n"
-#, c-format, perl-format
+#, c-format
msgid "Stage mode change [y,n,q,a,d%s,?]? "
msgstr "Canvia el mode de «stage» [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Stage deletion [y,n,q,a,d%s,?]? "
msgstr "Suprimeix «stage» [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Stage addition [y,n,q,a,d%s,?]? "
msgstr "Afegeix a «stage» [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Stage this hunk [y,n,q,a,d%s,?]? "
msgstr "Fer un «stage» d'aquest tros [y,n,q,a,d%s,?]? "
@@ -268,19 +268,19 @@
"a - fes «stage» d'aquest tros i de tota la resta de trossos del fitxer\n"
"d - no facis «stage» d'aquest tros ni de cap altre restant del fitxer\n"
-#, c-format, perl-format
+#, c-format
msgid "Stash mode change [y,n,q,a,d%s,?]? "
msgstr "Canvia el mode de «stash» [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Stash deletion [y,n,q,a,d%s,?]? "
msgstr "Suprimeix «stash» [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Stash addition [y,n,q,a,d%s,?]? "
msgstr "Afegeix a «stash» [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Stash this hunk [y,n,q,a,d%s,?]? "
msgstr "Fer un «stash» d'aquest tros [y,n,q,a,d%s,?]? "
@@ -304,19 +304,19 @@
"a - fes «stash» d'aquest tros i de tota la resta de trossos del fitxer\n"
"d - no facis «stash» d'aquest tros ni de cap altre restant del fitxer\n"
-#, c-format, perl-format
+#, c-format
msgid "Unstage mode change [y,n,q,a,d%s,?]? "
msgstr "Canvia el mode de «unstage» [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Unstage deletion [y,n,q,a,d%s,?]? "
msgstr "Suprimeix «Unstage» [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Unstage addition [y,n,q,a,d%s,?]? "
msgstr "Afegeix a «unstage» [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Unstage this hunk [y,n,q,a,d%s,?]? "
msgstr "Fer un «unstage» d'aquest tros [y,n,q,a,d%s,?]? "
@@ -340,19 +340,19 @@
"a - fes «unstage» d'aquest tros i de tota la resta de trossos del fitxer\n"
"d - no facis «unstage» d'aquest tros ni de cap altre restant del fitxer\n"
-#, c-format, perl-format
+#, c-format
msgid "Apply mode change to index [y,n,q,a,d%s,?]? "
msgstr "Aplica el canvi de mode a l'índex [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply deletion to index [y,n,q,a,d%s,?]? "
msgstr "Aplica la supressió a l'índex [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply addition to index [y,n,q,a,d%s,?]? "
msgstr "Aplica l'addició a l'índex [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply this hunk to index [y,n,q,a,d%s,?]? "
msgstr "Aplica aquest tros a l'índex [y,n,q,a,d%s,?]? "
@@ -376,19 +376,19 @@
"a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
"d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer\n"
-#, c-format, perl-format
+#, c-format
msgid "Discard mode change from worktree [y,n,q,a,d%s,?]? "
msgstr "Descarta el canvi de mode de l'arbre de treball [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Discard deletion from worktree [y,n,q,a,d%s,?]? "
msgstr "Descarta suprimir de l'arbre de treball [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Discard addition from worktree [y,n,q,a,d%s,?]? "
msgstr "Descarta l'addició de l'arbre de treball [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Discard this hunk from worktree [y,n,q,a,d%s,?]? "
msgstr "Descarta aquest tros de l'arbre de treball [y,n,q,a,d%s,?]? "
@@ -412,22 +412,22 @@
"a - descarta aquest tros i tots els trossos posteriors en el fitxer\n"
"d - no descartis aquest tros ni cap dels trossos posteriors en el fitxer\n"
-#, c-format, perl-format
+#, c-format
msgid "Discard mode change from index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Descarta el canvi de mode de l'índex i de l'arbre de treball [y,n,q,a,"
"d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Discard deletion from index and worktree [y,n,q,a,d%s,?]? "
msgstr "Descarta suprimir de l'índex i de l'arbre de treball [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Discard addition from index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Descarta l'addició de l'índex i de l'arbre de treball [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Descarta aquest tros de l'índex i de l'arbre de treball [y,n,q,a,d%s,?]? "
@@ -445,20 +445,20 @@
"a - descarta aquest tros i tots els trossos posteriors en el fitxer\n"
"d - no descartis aquest tros ni cap dels trossos posteriors en el fitxer\n"
-#, c-format, perl-format
+#, c-format
msgid "Apply mode change to index and worktree [y,n,q,a,d%s,?]? "
msgstr ""
"Aplica el canvi de mode a l'índex i a l'arbre de treball [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply deletion to index and worktree [y,n,q,a,d%s,?]? "
msgstr "Aplica la supressió a l'índex i a l'arbre de treball [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply addition to index and worktree [y,n,q,a,d%s,?]? "
msgstr "Aplica l'addició a l'índex i a l'arbre de treball [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "
msgstr "Aplica aquest tros a l'índex i a l'arbre de treball [y,n,q,a,d%s,?]? "
@@ -475,19 +475,19 @@
"a - aplica aquest tros i tots els trossos posteriors en el fitxer\n"
"d - no apliquis aquest tros ni cap dels trossos posteriors en el fitxer\n"
-#, c-format, perl-format
+#, c-format
msgid "Apply mode change to worktree [y,n,q,a,d%s,?]? "
msgstr "Aplica el canvi de mode a l'arbre de treball [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply deletion to worktree [y,n,q,a,d%s,?]? "
msgstr "Aplica la supressió a l'arbre de treball [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply addition to worktree [y,n,q,a,d%s,?]? "
msgstr "Aplica l'addició a l'arbre de treball [y,n,q,a,d%s,?]? "
-#, c-format, perl-format
+#, c-format
msgid "Apply this hunk to worktree [y,n,q,a,d%s,?]? "
msgstr "Aplica aquest tros a l'arbre de treball [y,n,q,a,d%s,?]? "
@@ -564,8 +564,6 @@
"Per a eliminar les línies «%c», suprimiu-les.\n"
"Les línies que comencin per %c s'eliminaran.\n"
-#. #-#-#-#-# git-add--interactive.perl.po #-#-#-#-#
-#. TRANSLATORS: 'it' refers to the patch mentioned in the previous messages.
msgid ""
"If it does not apply cleanly, you will be given an opportunity to\n"
"edit again. If all lines of the hunk are removed, then the edit is\n"
@@ -581,20 +579,12 @@
msgid "'git apply --cached' failed"
msgstr "«git apply --cached» ha fallat"
-#. #-#-#-#-# add-patch.c.po #-#-#-#-#
#. TRANSLATORS: do not translate [y/n]
#. The program will only accept that input at this point.
#. Consider translating (saying "no" discards!) as
#. (saying "n" for "no" discards!) if the translation
#. of the word "no" does not start with n.
#.
-#. #-#-#-#-# git-add--interactive.perl.po #-#-#-#-#
-#. TRANSLATORS: do not translate [y/n]
-#. The program will only accept that input
-#. at this point.
-#. Consider translating (saying "no" discards!) as
-#. (saying "n" for "no" discards!) if the translation
-#. of the word "no" does not start with n.
msgid ""
"Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]? "
msgstr ""
@@ -1443,6 +1433,12 @@
msgid "report archived files on stderr"
msgstr "informa de fitxers arxivats en stderr"
+msgid "time"
+msgstr "data"
+
+msgid "set modification time of archive entries"
+msgstr "estableix l'hora de modificació de les entrades de l'arxiu"
+
msgid "set compression level"
msgstr "estableix el nivell de compressió"
@@ -1483,6 +1479,13 @@
msgid "%.*s is not a valid attribute name"
msgstr "%.*s no és un nom d'atribut vàlid"
+msgid "unable to add additional attribute"
+msgstr "no s'ha pogut afegir l'atribut addicional"
+
+#, c-format
+msgid "ignoring overly long attributes line %d"
+msgstr "s'ignorarà la línia d'atributs massa llarga %d"
+
#, c-format
msgid "%s not allowed: %s:%d"
msgstr "%s no està permès: %s:%d"
@@ -1495,6 +1498,18 @@
"Useu «\\!» per exclamació capdavantera literal."
#, c-format
+msgid "cannot fstat gitattributes file '%s'"
+msgstr "no es pot fer fstat gitattributes al fitxer «%s»"
+
+#, c-format
+msgid "ignoring overly large gitattributes file '%s'"
+msgstr "s'ignorarà el fitxer «%s» gitattributes per massa gran"
+
+#, c-format
+msgid "ignoring overly large gitattributes blob '%s'"
+msgstr "s'ignorarà la blob «%s» gitattributes per massa gran"
+
+#, c-format
msgid "Badly quoted content in file '%s': %s"
msgstr "Comentari amb cometes errònies en el fitxer «%s»: %s"
@@ -1773,11 +1788,11 @@
#, c-format
msgid ""
-"You may try updating the submodules using 'git checkout %s && git submodule "
-"update --init'"
+"You may try updating the submodules using 'git checkout --no-recurse-"
+"submodules %s && git submodule update --init'"
msgstr ""
-"Podeu provar d'actualitzar els submòduls utilitzant «git checkout %s && git "
-"submodule update --init»"
+"Podeu provar d'actualitzar els submòduls utilitzant «git checkout --no-"
+"recurse-submodules %s && git submodule update --init»"
#, c-format
msgid "submodule '%s': cannot create branch '%s'"
@@ -1812,6 +1827,13 @@
msgid "Unstaged changes after refreshing the index:"
msgstr "Canvis «unstaged» després d'actualitzar l'índex:"
+msgid ""
+"the add.interactive.useBuiltin setting has been removed!\n"
+"See its entry in 'git help config' for details."
+msgstr ""
+"s'ha eliminat la configuració add.interactive.useBuiltin\n"
+"Per a més detalls, vegeu la seva entrada a «git help config»."
+
msgid "Could not read the index"
msgstr "No s'ha pogut llegir l'índex"
@@ -2201,6 +2223,9 @@
msgid "run interactively"
msgstr "executa interactivament"
+msgid "bypass pre-applypatch and applypatch-msg hooks"
+msgstr "evita els lligams pre-applypatch i applypatch-msg"
+
msgid "historical option -- no-op"
msgstr "opció històrica -- no-op"
@@ -2344,32 +2369,27 @@
msgid "git archive: expected a flush"
msgstr "git archive: s'esperava una neteja"
-msgid "git bisect--helper --bisect-reset [<commit>]"
-msgstr "git bisect--helper --bisect-reset [<comissió>]"
-
msgid ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}"
-"=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] "
-"[<paths>...]"
+"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-"
+"checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]"
msgstr ""
-"git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}"
-"=<term>] [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] "
-"[<paths>...]"
+"git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>] [--no-"
+"checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]"
-msgid "git bisect--helper --bisect-state (bad|new) [<rev>]"
-msgstr "git bisect--helper --bisect-state (bad|new) [<rev>]"
+msgid "git bisect (good|bad) [<rev>...]"
+msgstr "git bisect (good|bad) [<rev>...]"
-msgid "git bisect--helper --bisect-state (good|old) [<rev>...]"
-msgstr "git bisect--helper --bisect-state (good|old) [<rev>...]"
+msgid "git bisect skip [(<rev>|<range>)...]"
+msgstr "git bisect skip [(<rev>|<range>)...]"
-msgid "git bisect--helper --bisect-replay <filename>"
-msgstr "git bisect--helper --bisect-replay <filename>"
+msgid "git bisect reset [<commit>]"
+msgstr "git bisect reset [<comissió>]"
-msgid "git bisect--helper --bisect-skip [(<rev>|<range>)...]"
-msgstr "git bisect--helper --bisect-skip [(<rev>|<range>)...]"
+msgid "git bisect replay <logfile>"
+msgstr "git bisect replay <logfile>"
-msgid "git bisect--helper --bisect-run <cmd>..."
-msgstr "git bisect--helper --bisect-run <ordre>..."
+msgid "git bisect run <cmd>..."
+msgstr "git bisect run <ordre>..."
#, c-format
msgid "cannot open file '%s' in mode '%s'"
@@ -2519,9 +2539,6 @@
msgstr ""
"l'agafament de «%s» ha fallat. Proveu «git bisect start <branca-vàlida>»."
-msgid "won't bisect on cg-seek'ed tree"
-msgstr "no es bisecarà en un arbre en el qual s'ha fet cg-seek"
-
msgid "bad HEAD - strange symbolic ref"
msgstr "HEAD incorrecte - referència simbòlica estranya"
@@ -2573,7 +2590,7 @@
msgstr "ha fallat l'execució de bisect: no s'ha proporcionat cap ordre."
#, c-format
-msgid "unable to verify '%s' on good revision"
+msgid "unable to verify %s on good revision"
msgstr "no s'ha pogut verificar «%s» en una bona revisió"
#, c-format
@@ -2581,10 +2598,10 @@
msgstr "codi d'error de sortida %d per a una bona revisió"
#, c-format
-msgid "bisect run failed: exit code %d from '%s' is < 0 or >= 128"
+msgid "bisect run failed: exit code %d from %s is < 0 or >= 128"
msgstr ""
-"l'execució de la de bisecció ha fallat: codi de sortida %d de «%s» és < 0 o "
-">= 128"
+"l'execució de la de bisecció ha fallat: codi de sortida %d de %s és < 0 o >= "
+"128"
#, c-format
msgid "cannot open file '%s' for writing"
@@ -2593,37 +2610,44 @@
msgid "bisect run cannot continue any more"
msgstr "l'execució de la bisecció no pot continuar més"
-#, c-format
msgid "bisect run success"
msgstr "execució de bisecció amb èxit"
-#, c-format
msgid "bisect found first bad commit"
msgstr "la bisecció ha trobat una primera comissió errònia"
#, c-format
-msgid ""
-"bisect run failed: 'git bisect--helper --bisect-state %s' exited with error "
-"code %d"
+msgid "bisect run failed: 'git bisect %s' exited with error code %d"
msgstr ""
-"l'execució de la bisecció ha fallat: «git bisect--helper --bisect-state %s» "
-"ha sortit amb el codi d'error %d"
+"ha fallat l'execució del bisect: «git bisect %s» ha sortit amb el codi "
+"d'error %d"
-msgid "--bisect-reset requires either no argument or a commit"
-msgstr "--bisect-reset no requereix cap argument ni comissió"
+#, c-format
+msgid "'%s' requires either no argument or a commit"
+msgstr "«%s» no requereix cap argument ni comissió"
-msgid "--bisect-terms requires 0 or 1 argument"
-msgstr "--bisect-terms requereix 0 o 1 argument"
+#, c-format
+msgid "'%s' requires 0 or 1 argument"
+msgstr "%s requereix 0 o 1 arguments"
-msgid "--bisect-next requires 0 arguments"
-msgstr "--bisect-next no requereix cap argument"
-
-msgid "--bisect-log requires 0 arguments"
-msgstr "--bisect-log no requereix cap argument"
+#, c-format
+msgid "'%s' requires 0 arguments"
+msgstr "«%s» requereix 0 arguments"
msgid "no logfile given"
msgstr "no s'ha donat cap fitxer de registre"
+#, c-format
+msgid "'%s' failed: no command provided."
+msgstr "«%s» ha fallat: no s'ha proporcionat cap ordre."
+
+msgid "need a command"
+msgstr "cal una subordre"
+
+#, c-format
+msgid "unknown command: '%s'"
+msgstr "ordre desconeguda: «%s»"
+
msgid "git blame [<options>] [<rev-opts>] [<rev>] [--] <file>"
msgstr "git blame [<opcions>] [<opcions-de-revisió>] [<revisió>] [--] fitxer"
@@ -3203,6 +3227,9 @@
msgid "git bundle unbundle [--progress] <file> [<refname>...]"
msgstr "git bundle unbundle [--progress] <fitxer> [<refname>...]"
+msgid "need a <file> argument"
+msgstr "necessita un argument <fitxer>"
+
msgid "do not show progress meter"
msgstr "no mostris l'indicador de progrés"
@@ -3256,10 +3283,6 @@
msgid "%s takes no arguments"
msgstr "%s no accepta cap valor"
-#, c-format
-msgid "unknown command: '%s'"
-msgstr "ordre desconeguda: «%s»"
-
msgid "only one batch option may be specified"
msgstr "només es pot especificar una opció per lots"
@@ -3395,11 +3418,17 @@
msgid "only two arguments allowed in <type> <object> mode, not %d"
msgstr "només es permeten dos arguments en el mode <tipus> <objecte>, no %d"
-msgid "git check-attr [-a | --all | <attr>...] [--] <pathname>..."
-msgstr "git check-attr [-a | --all | <atribut>...] [--] <nom-de-camí>..."
+msgid ""
+"git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
+"<pathname>..."
+msgstr ""
+"git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] "
+"<pathname>..."
-msgid "git check-attr --stdin [-z] [-a | --all | <attr>...]"
-msgstr "git check-attr --stdin [-z] [-a | --all | <atribut>...]"
+msgid ""
+"git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
+msgstr ""
+"git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"
msgid "report all attributes set on file"
msgstr "informa de tots els atributs establerts en el fitxer"
@@ -3413,6 +3442,12 @@
msgid "terminate input and output records by a NUL character"
msgstr "acaba els registres d'entrada i de sortida amb un caràcter NUL"
+msgid "<tree-ish>"
+msgstr "<tree-ish>"
+
+msgid "which tree-ish to check attributes at"
+msgstr "a quin tree-ish s'han de comprovar els atributs"
+
msgid "suppress progress reporting"
msgstr "omet els informes de progrés"
@@ -3993,7 +4028,7 @@
"* - tria tots els ítems\n"
" - (buit) finalitza la selecció\n"
-#, c-format, perl-format
+#, c-format
msgid "Huh (%s)?\n"
msgstr "Perdó (%s)?\n"
@@ -4142,9 +4177,6 @@
msgid "create a shallow clone of that depth"
msgstr "crea un clon superficial d'aquesta profunditat"
-msgid "time"
-msgstr "data"
-
msgid "create a shallow clone since a specific time"
msgstr "crea un clon superficial des d'una data específica"
@@ -4377,6 +4409,9 @@
msgid "failed to fetch objects from bundle URI '%s'"
msgstr "no s'han pogut obtenir els objectes de l'URI del paquet «%s»"
+msgid "failed to fetch advertised bundles"
+msgstr "no s'han pogut obtenir els paquets anunciats"
+
msgid "remote transport reported error"
msgstr "el transport remot ha informat d'un error"
@@ -5625,27 +5660,6 @@
msgid "no <cmd> given for --extcmd=<cmd>"
msgstr "no s'ha proporcionat l'<ordre> per a --extcmd=<ordre>"
-msgid "git env--helper --type=[bool|ulong] <options> <env-var>"
-msgstr "git env--helper --type=[bool|ulong] <opcions> <env-var>"
-
-msgid "default for git_env_*(...) to fall back on"
-msgstr "valor per defecte per a git_env_*(...) en cas d'absència"
-
-msgid "be quiet only use git_env_*() value as exit code"
-msgstr "silenciós només utilitza el valor git_env_*() com a codi de sortida"
-
-#, c-format
-msgid "option `--default' expects a boolean value with `--type=bool`, not `%s`"
-msgstr "l'opció «--default» espera un valor booleà amb «--type=bool», no «%s»"
-
-#, c-format
-msgid ""
-"option `--default' expects an unsigned long value with `--type=ulong`, not "
-"`%s`"
-msgstr ""
-"l'opció «--default» espera un valor llarg sense signe amb «--type=ulong», no "
-"«%s»"
-
msgid "git fast-export [<rev-list-opts>]"
msgstr "git fast-export [<rev-list-opts>]"
@@ -6055,6 +6069,10 @@
msgid "--unshallow on a complete repository does not make sense"
msgstr "--unshallow en un repositori complet no té sentit"
+#, c-format
+msgid "failed to fetch bundles from '%s'"
+msgstr "no s'han pogut obtenir els paquets de «%s»"
+
msgid "fetch --all does not take a repository argument"
msgstr "fetch --all no accepta un argument de repositori"
@@ -7087,12 +7105,19 @@
msgid "'git help config' for more information"
msgstr "«git help config» per a més informació"
-msgid "git hook run [--ignore-missing] <hook-name> [-- <hook-args>]"
-msgstr "git hook run [--ignore-missing] <hook-name> [-- <hook-args>]"
+msgid ""
+"git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-"
+"args>]"
+msgstr ""
+"git hook run [--ignore-missing] [--to-stdin=<camí>] <hook-name> [-- <hook-"
+"args>]"
msgid "silently ignore missing requested <hook-name>"
msgstr "ignora silenciosament la sol·licitud <hook-name> perduda"
+msgid "file to read into hooks' stdin"
+msgstr "fitxer per a llegir a l'entrada estàndard dels lligams"
+
#, c-format
msgid "object type mismatch at %s"
msgstr "hi ha una discordança de tipus d'objecte a %s"
@@ -7929,11 +7954,11 @@
msgid ""
"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
" [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
-" [--symref] [<repository> [<refs>...]]"
+" [--symref] [<repository> [<patterns>...]]"
msgstr ""
"git ls-remote [--heads] [--tags] [--refs] [--upload-pack=<exec>]\n"
" [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
-" [--symref] [<repository> [<refs>...]]"
+" [--symref] [<repository> [<patterns>...]]"
msgid "do not print remote URL"
msgstr "no imprimeixis l'URL remot"
@@ -8179,9 +8204,15 @@
msgid "perform multiple merges, one per line of input"
msgstr "realitza múltiples fusions, una per línia d'entrada"
+msgid "specify a merge-base for the merge"
+msgstr "cal especificar una referència base per a la fusió"
+
msgid "--trivial-merge is incompatible with all other options"
msgstr "--trivial-merge és incompatible amb totes les altres opcions"
+msgid "--merge-base is incompatible with --stdin"
+msgstr "--merge-base és incompatible amb --stdin"
+
#, c-format
msgid "malformed input line: '%s'."
msgstr "línia d'entrada mal formada: «%s»."
@@ -10102,6 +10133,9 @@
msgid "could not switch to %s"
msgstr "no s'ha pogut commutar a %s"
+msgid "apply options and merge options cannot be used together"
+msgstr "les opcions apply i merge no es poden usar juntes"
+
#, c-format
msgid ""
"unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and "
@@ -10312,7 +10346,7 @@
"and run me again. I am stopping in case you still have something\n"
"valuable there.\n"
msgstr ""
-"Sembla que ja exigeix un directori %s, i em pregunto\n"
+"Sembla que ja existeix un directori %s, i em pregunto\n"
"si esteu enmig d'un altre «rebase». Si aquest és el cas, proveu\n"
"\t%s\n"
"Si no és cas, feu:\n"
@@ -10330,8 +10364,19 @@
msgid "--strategy requires --merge or --interactive"
msgstr "--strategy requereix --merge o --interactive"
-msgid "apply options and merge options cannot be used together"
-msgstr "les opcions apply i merge no es poden usar juntes"
+msgid ""
+"apply options are incompatible with rebase.autosquash. Consider adding --no-"
+"autosquash"
+msgstr ""
+"les opcions «apply» són incompatibles amb rebase.autosquash. Considereu "
+"afegir-hi --no-autosquash"
+
+msgid ""
+"apply options are incompatible with rebase.updateRefs. Consider adding --no-"
+"update-refs"
+msgstr ""
+"les opcions «apply» són incompatibles amb rebase.updateRefs. Considereu "
+"afegir-hi --no-update-refs"
#, c-format
msgid "Unknown rebase backend: %s"
@@ -12846,10 +12891,6 @@
msgid "git submodule--helper <command>"
msgstr "git submodule--helper <command>"
-#, c-format
-msgid "%s doesn't support --super-prefix"
-msgstr "%s no admet --super-prefix"
-
msgid "git symbolic-ref [-m <reason>] <name> <ref>"
msgstr "git symbolic-ref [-m <reason>] <name> <ref>"
@@ -13597,6 +13638,11 @@
msgstr "core.fsyncMethod = batch no és compatible amb aquesta plataforma"
#, c-format
+msgid "could not parse bundle list key %s with value '%s'"
+msgstr ""
+"no s'ha pogut analitzar la clau de llista de paquets %s amb el valor «%s»"
+
+#, c-format
msgid "bundle list at '%s' has no mode"
msgstr "la llista de farcells a «%s» no té mode"
@@ -13607,6 +13653,13 @@
msgstr "capacitats insuficients"
#, c-format
+msgid "file downloaded from '%s' is not a bundle"
+msgstr "el fitxer baixat de «%s» no és un paquet"
+
+msgid "failed to store maximum creation token"
+msgstr "no s'ha pogut emmagatzemar el testimoni de creació màxim"
+
+#, c-format
msgid "unrecognized bundle mode from URI '%s'"
msgstr "no s'ha reconegut el model del farcell de l'URI «%s»"
@@ -13622,6 +13675,13 @@
msgid "file at URI '%s' is not a bundle or bundle list"
msgstr "el fitxer a l'URI «%s» no és farcell o una llista de farcells"
+#, c-format
+msgid "bundle-uri: unexpected argument: '%s'"
+msgstr "bundle-uri: argument inesperat: «%s»"
+
+msgid "bundle-uri: expected flush after arguments"
+msgstr "bundle-uri: s'esperava una neteja després dels arguments"
+
msgid "bundle-uri: got an empty line"
msgstr "bundle-uri: té una línia buida"
@@ -13653,6 +13713,13 @@
msgid "need a repository to verify a bundle"
msgstr "cal un repositori per a verificar un farcell"
+msgid ""
+"some prerequisite commits exist in the object store, but are not connected "
+"to the repository's history"
+msgstr ""
+"hi ha algunes comissions requerides al magatzem d'objectes, però no estan "
+"connectades a l'historial del repositori"
+
#, c-format
msgid "The bundle contains this ref:"
msgid_plural "The bundle contains these %<PRIuMAX> refs:"
@@ -15096,16 +15163,23 @@
msgstr "format d'objecte «%s» especificat pel servidor desconegut"
#, c-format
+msgid "error on bundle-uri response line %d: %s"
+msgstr "error a la línia de resposta de bundle-uri %d: %s"
+
+msgid "expected flush after bundle-uri listing"
+msgstr "s'esperava un buidatge després del llistat de bundle-uri"
+
+msgid "expected response end packet after ref listing"
+msgstr ""
+"s'esperava un paquet de final de resposta després del llistat de referències"
+
+#, c-format
msgid "invalid ls-refs response: %s"
msgstr "resposta de ls-refs no vàlida: %s"
msgid "expected flush after ref listing"
msgstr "s'esperava una neteja després del llistat de referències"
-msgid "expected response end packet after ref listing"
-msgstr ""
-"s'esperava un paquet de final de resposta després del llistat de referències"
-
#, c-format
msgid "protocol '%s' is not supported"
msgstr "el protocol «%s» no és compatible"
@@ -15479,7 +15553,7 @@
"unknown color-moved-ws mode '%s', possible values are 'ignore-space-change', "
"'ignore-space-at-eol', 'ignore-all-space', 'allow-indentation-change'"
msgstr ""
-"el mode «%s» de «color-moved-ws» és desconegut, els valor possibles són "
+"el mode «%s» de «color-moved-ws» és desconegut, els valors possibles són "
"«ignore-space-change», «ignore-space-at-eol», «ignore-all-space», «allow-"
"indentation-change»"
@@ -16284,16 +16358,14 @@
" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
"bare]\n"
" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
-" [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
-" <command> [<args>]"
+" [--config-env=<name>=<envvar>] <command> [<args>]"
msgstr ""
-"git [-v | --version] [-h | --help] [-C <camí>] [-c <name>=<value>]\n"
-" [--exec-path[=<camí>]] [--html-path] [--man-path] [--info-path]\n"
+"git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]\n"
+" [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--"
"bare]\n"
-" [--git-dir=<camí>] [--work-tree=<camí>] [--namespace=<name>]\n"
-" [--super-prefix=<camí>] [--config-env=<name>=<envvar>]\n"
-" <command> [<args>]"
+" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
+" [--config-env=<name>=<envvar>] <command> [<args>]"
msgid ""
"'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -16319,10 +16391,6 @@
msgstr "no s'ha especificat un nom d'espai per --namespace\n"
#, c-format
-msgid "no prefix given for --super-prefix\n"
-msgstr "no s'ha especificat cap prefix per a --super-prefix\n"
-
-#, c-format
msgid "-c expects a configuration string\n"
msgstr "-c espera una cadena de configuració\n"
@@ -16434,8 +16502,13 @@
msgid "gpg.ssh.defaultKeyCommand failed: %s %s"
msgstr "gpg.ssh.defaultKeyCommand ha fallat: %s %s"
-msgid "gpg failed to sign the data"
-msgstr "gpg ha fallat en signar les dades"
+#, c-format
+msgid ""
+"gpg failed to sign the data:\n"
+"%s"
+msgstr ""
+"gpg ha fallat en signar les dades:\n"
+"%s"
msgid "user.signingKey needs to be set for ssh signing"
msgstr "user.signingKey s'ha d'establir per a signar amb ssh"
@@ -17605,6 +17678,10 @@
msgstr "brossa al final de l'objecte solt «%s»"
#, c-format
+msgid "unable to open loose object %s"
+msgstr "no s'ha pogut obr