Compare commits

...

480 Commits

Author SHA1 Message Date
Junio C Hamano 3f2a94875d The twelfth batch 2025-07-21 09:14:29 -07:00
Junio C Hamano 3a112b53a4 Merge branch 'jb/gpg-program-variable-is-a-pathname'
The gpg.program configuration variable, which names a pathname to
the (custom) GPG compatible program, can now be spelled with ~tilde
expansion.

* jb/gpg-program-variable-is-a-pathname:
  gpg-interface: expand gpg.program as a path
2025-07-21 09:14:29 -07:00
Junio C Hamano d80b7640b1 Merge branch 'cb/daemon-reap-children'
Futz with SIGCHLD handling in "git daemon".

* cb/daemon-reap-children:
  daemon: use sigaction() to install child_handler()
  compat/mingw: allow sigaction(SIGCHLD)
2025-07-21 09:14:28 -07:00
Junio C Hamano fe02fe75fc Merge branch 'ja/doc-git-log-markup'
Doc mark-up updates.

* ja/doc-git-log-markup:
  doc: git-log: convert log config to new doc format
  doc: git-log: convert diff options to new doc format
  doc: git-log: convert pretty formats to new doc format
  doc: git-log: convert pretty options to new doc format
  doc: git-log: convert rev list options to new doc format
  doc: git-log: convert line range format to new doc format
  doc: git-log: convert line range options to new doc format
  doc: git-log convert rev-list-description to new doc format
  doc: convert git-log to new documentation format
2025-07-21 09:14:28 -07:00
Junio C Hamano b5e966dde7 Merge branch 'rh/doc-glob-pathspec-fix'
Docfix.

* rh/doc-glob-pathspec-fix:
  doc: correct doc for glob pathspec
2025-07-21 09:14:27 -07:00
Junio C Hamano 867d9b19be Merge branch 'ps/meson-cleanups'
Meson-based build update.

* ps/meson-cleanups:
  ci: use Meson's new `--slice` option
  meson: update subproject wrappers
  meson: fix lookup of shell on MINGW64
  meson: clean up unnecessary variables
  meson: improve summary of auto-detected features
  meson: stop printing 'https' option twice in our summaries
  meson: stop discovering native version of Python
2025-07-21 09:14:27 -07:00
Junio C Hamano 5f2b826b54 Merge branch 'jk/remote-avoid-overlapping-names'
"git remote" now detects remote names that overlap with each other
(e.g., remote nickname "outer" and "outer/inner" are used at the
same time), as it will lead to overlapping remote-tracking
branches.

* jk/remote-avoid-overlapping-names:
  remote: detect collisions in remote names
2025-07-21 09:14:26 -07:00
Junio C Hamano 205493d56d Merge branch 'tb/midx-avoid-cruft-packs'
"pack-objects" has been taught to avoid pointing into objects in
cruft packs from midx.

* tb/midx-avoid-cruft-packs:
  repack: exclude cruft pack(s) from the MIDX where possible
  pack-objects: introduce '--stdin-packs=follow'
  pack-objects: swap 'show_{object,commit}_pack_hint'
  pack-objects: fix typo in 'show_object_pack_hint()'
  pack-objects: perform name-hash traversal for unpacked objects
  pack-objects: declare 'rev_info' for '--stdin-packs' earlier
  pack-objects: factor out handling '--stdin-packs'
  pack-objects: limit scope in 'add_object_entry_from_pack()'
  pack-objects: use standard option incompatibility functions
2025-07-21 09:14:26 -07:00
Junio C Hamano a636d395ff Merge branch 'bc/use-sha256-by-default-in-3.0'
Prepare to flip the default hash function to SHA-256.

* bc/use-sha256-by-default-in-3.0:
  Enable SHA-256 by default in breaking changes mode
  help: add a build option for default hash
  t5300: choose the built-in hash outside of a repo
  t4042: choose the built-in hash outside of a repo
  t1007: choose the built-in hash outside of a repo
  t: default to compile-time default hash if not set
  setup: use the default algorithm to initialize repo format
  Use legacy hash for legacy formats
  builtin: use default hash when outside a repository
  hash: add a constant for the legacy hash algorithm
  hash: add a constant for the default hash algorithm
2025-07-21 09:14:25 -07:00
Junio C Hamano 90c0775e97 The eleventh batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-16 09:42:29 -07:00
Junio C Hamano fe6fb09c27 Merge branch 'ag/doc-send-email'
Documentation updates for "git send-email".

* ag/doc-send-email:
  docs: mention possible options for Proton Mail users
  docs: add a paragraph explaining the `sendmailCmd` option of sendemail
  docs: add an OAuth2.0 credential helper for AOL accounts
  docs: add outlookidfix config option to sendemail documentation
  docs: link OpenSSL's verify(1) manual page to know about -CAfile and -CApath options
2025-07-16 09:42:29 -07:00
Junio C Hamano 0fd2a2ec14 Merge branch 'rs/parse-options-precision'
Define .precision to more canned parse-options type to avoid bugs
coming from using a variable with a wrong type to capture the
parsed values.

* rs/parse-options-precision:
  parse-options: add precision handling for OPTION_COUNTUP
  parse-options: add precision handling for OPTION_BITOP
  parse-options: add precision handling for OPTION_NEGBIT
  parse-options: add precision handling for OPTION_BIT
  parse-options: add precision handling for OPTION_SET_INT
  parse-options: add precision handling for PARSE_OPT_CMDMODE
  parse-options: require PARSE_OPT_NOARG for OPTION_BITOP
2025-07-16 09:42:28 -07:00
Junio C Hamano edb4fd9669 Merge branch 'ps/doc-pack-refs-auto-with-files-backend-fix'
Doc update.

* ps/doc-pack-refs-auto-with-files-backend-fix:
  docs/git-pack-refs: document heuristic used for packing loose refs
2025-07-16 09:42:28 -07:00
Junio C Hamano ac5fd29581 Merge branch 'ps/refs-files-remove-empty-parent'
When a ref creation at refs/heads/foo/bar fails, the files backend
now removes refs/heads/foo/ if the directory is otherwise not used.

* ps/refs-files-remove-empty-parent:
  refs/files: remove empty parent dirs when ref creation fails
2025-07-16 09:42:27 -07:00
Junio C Hamano 362f69547f Merge branch 'ps/t1006-tap-fix'
Test fix.

* ps/t1006-tap-fix:
  t1006: fix broken TAP format
2025-07-16 09:42:27 -07:00
Junio C Hamano 7b625c2a35 Merge branch 'ph/fetch-prune-optim'
"git fetch --prune" used to be O(n^2) expensive when there are many
refs, which has been corrected.

* ph/fetch-prune-optim:
  clean up interface for refs_warn_dangling_symrefs
  refs: remove old refs_warn_dangling_symref
  fetch-prune: optimize dangling-ref reporting
2025-07-16 09:42:27 -07:00
Junio C Hamano 32571a0222 The tenth batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-15 15:18:18 -07:00
Junio C Hamano f31d155266 Merge branch 'ly/load-bitmap-leakfix'
Leakfix with a new and a bit invasive test.

* ly/load-bitmap-leakfix:
  pack-bitmap: add load corrupt bitmap test
  pack-bitmap: reword comments in test_bitmap_commits()
  pack-bitmap: fix memory leak if load_bitmap() failed
2025-07-15 15:18:18 -07:00
Junio C Hamano 51b50c55a9 Merge branch 'ps/object-store'
Code clean-up around object access API.

* ps/object-store:
  odb: rename `read_object_with_reference()`
  odb: rename `pretend_object_file()`
  odb: rename `has_object()`
  odb: rename `repo_read_object_file()`
  odb: rename `oid_object_info()`
  odb: trivial refactorings to get rid of `the_repository`
  odb: get rid of `the_repository` when handling submodule sources
  odb: get rid of `the_repository` when handling the primary source
  odb: get rid of `the_repository` in `for_each()` functions
  odb: get rid of `the_repository` when handling alternates
  odb: get rid of `the_repository` in `odb_mkstemp()`
  odb: get rid of `the_repository` in `assert_oid_type()`
  odb: get rid of `the_repository` in `find_odb()`
  odb: introduce parent pointers
  object-store: rename files to "odb.{c,h}"
  object-store: rename `object_directory` to `odb_source`
  object-store: rename `raw_object_store` to `object_database`
2025-07-15 15:18:18 -07:00
Junio C Hamano d30e120486 The ninth batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-14 11:19:29 -07:00
Junio C Hamano f5b69ee6ab Merge branch 'rp/apply-intent-to-add-fix'
"git apply -N" should start from the current index and register
only new files, but it instead started from an empty index, which
has been corrected.

* rp/apply-intent-to-add-fix:
  apply docs: clarify wording for --intent-to-add
  t4140: test apply --intent-to-add interactions
  apply: only write intents to add for new files
  apply: read in the index in --intent-to-add mode
2025-07-14 11:19:29 -07:00
Junio C Hamano 2b5bf70039 Merge branch 'sj/string-list'
Code and test clean-up around string-list API.

* sj/string-list:
  u-string-list: move "remove duplicates" test to "u-string-list.c"
  u-string-list: move "filter string" test to "u-string-list.c"
  u-string-list: move "test_split_in_place" to "u-string-list.c"
  u-string-list: move "test_split" into "u-string-list.c"
  string-list: enable sign compare warnings check
  string-list: return index directly when inserting an existing element
  string-list: remove unused "insert_at" parameter from add_entry
  string-list: fix sign compare warnings for loop iterator
2025-07-14 11:19:28 -07:00
Junio C Hamano e78bca2eb7 Merge branch 'rj/freebsd-sysinfo-build-fix'
Build fix for FreeBSD.

* rj/freebsd-sysinfo-build-fix:
  build: fix FreeBSD build when sysinfo compat library installed
2025-07-14 11:19:28 -07:00
Junio C Hamano 8c5f7db806 Merge branch 'ts/merge-orig-head-doc-fix'
Doc fix.

* ts/merge-orig-head-doc-fix:
  docs: correct ORIG_HEAD example in "git merge" documentation
2025-07-14 11:19:28 -07:00
Junio C Hamano 18cd7563d4 Merge branch 'ps/perlless-test-fixes'
Test fixes.

* ps/perlless-test-fixes:
  t5333: fix missing terminator for sed(1) 's' command
  t4150: fix warning printed by awk due to escaped '\@'
2025-07-14 11:19:27 -07:00
Junio C Hamano f4fd906350 Merge branch 're/ssh-sign-buffer-fix'
Tempfile removal fix in the codepath to sign commits with SSH keys.

* re/ssh-sign-buffer-fix:
  ssh signing: don't detach the filename strbuf from key_file tempfile
2025-07-14 11:19:27 -07:00
Junio C Hamano 69ea767bc3 Merge branch 'hy/read-cache-lock-error-fix'
A failure to open the index file for writing due to conflicting
access did not state what went wrong, which has been corrected.

* hy/read-cache-lock-error-fix:
  read-cache: report lock error when refreshing index
2025-07-14 11:19:26 -07:00
Junio C Hamano 38349d1160 Merge branch 'kn/clang-format-updates'
Update ".clang-format" and ".editorconfig" to match our style guide
a bit better.

* kn/clang-format-updates:
  meson: add rule to run 'git clang-format'
  clang-format: add 'RemoveBracesLLVM' to the main config
  clang-format: set 'ColumnLimit' to 0
2025-07-14 11:19:26 -07:00
Junio C Hamano a35b8c8b9e Merge branch 'kh/doc-config-subcommands'
Documentation updates.

* kh/doc-config-subcommands:
  config: mention --url in the synopsis
  config: use --value instead of value-pattern
  config: document --[no-]value
  config: use --value=<pattern> consistently
  config: document --[no-]show-names
2025-07-14 11:19:26 -07:00
Junio C Hamano db4a912c4a Merge branch 'mc/netrc-service-names'
"netrc" credential helper has been improved to understand textual
service names (like smtp) in addition to the numeric port numbers
(like 25).

* mc/netrc-service-names:
  contrib: better support symbolic port names in git-credential-netrc
  contrib: warn for invalid netrc file ports in git-credential-netrc
  contrib: use a more portable shebang for git-credential-netrc
2025-07-14 11:19:25 -07:00
Junio C Hamano 0d046cba65 Merge branch 'jc/coccicheck-fails-make-when-it-fails'
"make coccicheck" succeeds even when spatch made suggestions, which
has been updated to fail in such a case.

* jc/coccicheck-fails-make-when-it-fails:
  coccicheck: fail "make" when it fails
2025-07-14 11:19:25 -07:00
Junio C Hamano 5e458c1cfb Merge branch 'ps/use-reftable-as-default-in-3.0'
The reftable ref backend has matured enough; Git 3.0 will make it
the default format in a newly created repositories by default.

* ps/use-reftable-as-default-in-3.0:
  setup: use "reftable" format when experimental features are enabled
  BreakingChanges: announce switch to "reftable" format
2025-07-14 11:19:24 -07:00
Junio C Hamano 50d9c342b4 Merge branch 'jk/all-negative-diff-filter-fix'
A diff-filter with negative-only specification like "git log
--diff-filter=d" did not trigger correctly, which has been fixed.

* jk/all-negative-diff-filter-fix:
  setup_revisions(): turn on diffs for all-negative diff filter
2025-07-14 11:19:24 -07:00
Junio C Hamano f96878e5d3 Merge branch 'ac/prune-wo-the-repository'
Some code paths in the "git prune" used to ignore passed in
repository object and used the_repository singleton instance
instead, which has been corrected.

* ac/prune-wo-the-repository:
  builtin/prune: stop depending on 'the_repository'
  repository: move 'repository_format_precious_objects' to repo scope
2025-07-14 11:19:23 -07:00
Junio C Hamano 45c50a10cf Merge branch 'bs/config-mak-freebsd'
Drop FreeBSD 4 support and assume we are at least at FreeBSD 6 with
memmem() supported.

* bs/config-mak-freebsd:
  build: retire NO_UINTMAX_T
  config.mak.uname: set NO_MEMMEM only for functional version
2025-07-14 11:19:23 -07:00
Junio C Hamano e02d718846 Merge branch 'cb/total-ram-bsd-fix'
Use of sysctl() system call to learn the total RAM size used on
BSDs has been corrected.

* cb/total-ram-bsd-fix:
  builtin/gc: correct total_ram calculation with HAVE_BSD_SYSCTL
2025-07-14 11:19:23 -07:00
Junio C Hamano cc876f2c7f Merge branch 'bs/remote-helpers-doc-markup-fix'
Docfix.

* bs/remote-helpers-doc-markup-fix:
  gitremote-helpers.adoc: fix formatting
2025-07-14 11:19:22 -07:00
Jonas Brandstötter 7d275cd5c0 gpg-interface: expand gpg.program as a path
This allows using a custom gpg program under the user's home directory
by specifying a path starting with '~'

[gpg]
        program = "~/.local/bin/mygpg"

Signed-off-by: Jonas Brandstötter <jonas.brandstoetter@gmx.at>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-14 10:07:02 -07:00
Patrick Steinhardt d3d6493dcf ci: use Meson's new `--slice` option
As executing our test suite is notoriously slow on Windows we use matrix
jobs in our CI systems to slice up tests and run them via multiple jobs.
On Meson this is done with a comparatively complex PowerShell invocation
as Meson didn't yet have a native way to slice tests like this.

I have upstreamed a new `--slice` option [1] that addresses this use
case though, which has been merged and released with Meson 1.8. Both
GitLab and GitHub CI have Meson 1.8.2 available by now, so let's update
the jobs to use that new option.

[1]: https://github.com/mesonbuild/meson/pull/14092

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-11 09:56:34 -07:00
Patrick Steinhardt 164cbd679c meson: update subproject wrappers
Update subproject wrappers to newer versions by executing `meson wrap
update` in the project's root directory

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-11 09:56:34 -07:00
Russell Hanneken f4fa8a3687 doc: correct doc for glob pathspec
gitglossary documents Git pathspecs. One type of pathspec is the "glob"
pathspec, prefixed with the magic word "glob".

Regarding glob pathspecs, gitglossary says, '"**/foo" matches file or
directory "foo" anywhere, the same as pattern "foo".' That last phrase
('the same as pattern "foo") is incorrect. "**/foo" and "foo" are not
equivalent. "**/foo" matches foo anywhere, but "foo" does not.

This change removes the incorrect phrase from the glob pathspec doc.

Signed-off-by: Russell Hanneken <rhanneken@pobox.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-11 09:44:06 -07:00
Carlo Marcelo Arenas Belón d83e1eef3b daemon: use sigaction() to install child_handler()
Replace signal() with an equivalent invocation of sigaction(), but
make sure to NOT set SA_RESTART so the original code that expects
to be interrupted when children complete still works as designed.

This change has the added benefit of using BSD signal semantics reliably
and therefore not needing the rearming call in the signal handler.

Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-10 14:19:57 -07:00
Carlo Marcelo Arenas Belón ef03aa432a compat/mingw: allow sigaction(SIGCHLD)
A future change will start using sigaction to setup a SIGCHLD signal
handler.

The current code uses signal(), which returns SIG_ERR (but doesn't
seem to set errno) so instruct sigaction() to do the same.

A new SA flag will be needed, so copy the one from Cygwin; note that
the sigaction() implementation that is provided won't use it, so
its value is otherwise irrelevant.

Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-10 14:19:15 -07:00
René Scharfe c1e616c39b parse-options: add precision handling for OPTION_COUNTUP
Similar to 09705696f7 (parse-options: introduce precision handling for
`OPTION_INTEGER`, 2025-04-17) support value variables of different sizes
for OPTION_COUNTUP.  Do that by requiring their "precision" to be set,
casting their "value" pointer accordingly and checking whether the value
fits.

Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-09 08:40:32 -07:00
René Scharfe 1d918bf2a5 parse-options: add precision handling for OPTION_BITOP
Similar to 09705696f7 (parse-options: introduce precision handling for
`OPTION_INTEGER`, 2025-04-17) support value variables of different sizes
for OPTION_BITOP.  Do that by requiring their "precision" to be set,
casting their "value" pointer accordingly and checking whether the value
fits.

Check if "devfal" fits into an integer variable with the given
"precision", but don't check "extra", as its value is only used to clear
bits, so cannot lead to an overflow.  Not checking continues to allow
e.g., using -1 to clear all bits even if the value variable has a
narrower type than intptr_t.

Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-09 08:39:46 -07:00
René Scharfe feeebbf1b7 parse-options: add precision handling for OPTION_NEGBIT
Similar to 09705696f7 (parse-options: introduce precision handling for
`OPTION_INTEGER`, 2025-04-17) support value variables of different sizes
for OPTION_NEGBIT.  Do that by requiring their "precision" to be set,
casting their "value" pointer accordingly and checking whether the value
fits.

Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-09 08:39:46 -07:00
René Scharfe 5228211c4b parse-options: add precision handling for OPTION_BIT
Similar to 09705696f7 (parse-options: introduce precision handling for
`OPTION_INTEGER`, 2025-04-17) support value variables of different sizes
for OPTION_BIT.  Do that by requiring their "precision" to be set,
casting their "value" pointer accordingly and checking whether the value
fits.

Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-09 08:39:28 -07:00
René Scharfe c898bbc5e4 parse-options: add precision handling for OPTION_SET_INT
Similar to 09705696f7 (parse-options: introduce precision handling for
`OPTION_INTEGER`, 2025-04-17) support value variables of different sizes
for OPTION_SET_INT.  Do that by requiring their "precision" to be set,
casting their "value" pointer accordingly and checking whether the value
fits.

Factor out the casting code from the part of do_get_value() that handles
OPTION_INTEGER to avoid code duplication.  We're going to use it in the
next patches as well.

Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-09 08:39:26 -07:00
René Scharfe 0d3e045b34 parse-options: add precision handling for PARSE_OPT_CMDMODE
Build on 09705696f7 (parse-options: introduce precision handling for
`OPTION_INTEGER`, 2025-04-17) to support value variables of different
sizes for PARSE_OPT_CMDMODE options.  Do that by requiring their
"precision" to be set and casting their "value" pointer accordingly.

Call the function that does the raw casting do_get_int_value() to
reserve the name get_int_value() for a more friendly wrapper we're
going to introduce in one of the next patches.

Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-09 08:39:10 -07:00
René Scharfe 369e6d94b2 parse-options: require PARSE_OPT_NOARG for OPTION_BITOP
OPTION_BITOP options don't take arguments.  Make sure they are declared
that way using the flag PARSE_OPT_NOARG.

Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-09 08:39:00 -07:00
Patrick Steinhardt fcf1014c5f meson: fix lookup of shell on MINGW64
In 4cba20fbdc (meson: prefer shell at "/bin/sh", 2025-04-25) we have
addressed an issue where the shell path embedded into Git was looked up
via PATH, which easily led to unportable shell paths other than the
usual "/bin/sh" location. The fix was to simply add '/bin' to the search
path explicitly, which made us prefer that directory over the PATH-based
lookup.

This fix causes issues on MINGW64 though, which uses Windows-style
paths. "/bin" is not an absolute Windows-style path, but Meson expects
the directories to be absolute. This leads to the following error:

    meson.build:248:15: ERROR: Search directory /bin is not an absolute path.

Fix this by instead searching for both '/bin/sh' and 'sh', which also
causes us to prefer '/bin/sh' over a PATH-based lookup. Meson does
accept that path alright on MINGW64, even though it's not an absolute
Windows-style path, either.

Furthermore, this continues to work alright with cross-files, as well,
in case one wants to explicitly override the shell path:

    $ meson setup build
    ...
      Runtime executable paths
        perl       : /nix/store/gy10hw004rl2xfbfq41vnw0yb1w8rvbl-perl-5.40.0/bin/perl
        python     : /nix/store/sd81bvmch7njdpwx3lkjslixcbj5mivz-python3-3.13.4/bin/python3
        shell      : /bin/sh

    $ cat >cross.ini <<-EOF
    [binaries]
    sh = '/nix/store/94lg0shvsfc845zy8gnflvpqxxiyijbz-bash-interactive-5.2p37/bin/bash'
    EOF

    $ meson setup build --cross-file=cross.ini --wipe
    ...
      Runtime executable paths
        perl       : /nix/store/gy10hw004rl2xfbfq41vnw0yb1w8rvbl-perl-5.40.0/bin/perl
        python     : /nix/store/sd81bvmch7njdpwx3lkjslixcbj5mivz-python3-3.13.4/bin/python3
        shell      : /nix/store/94lg0shvsfc845zy8gnflvpqxxiyijbz-bash-interactive-5.2p37/bin/bash

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-09 08:19:33 -07:00
Patrick Steinhardt e69b3b367f meson: clean up unnecessary variables
The `manpage_target` variable isn't used at all, and the `manpage_path`
variable is only used in a single location. Remove the former variable
and inline the latter.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-09 08:19:32 -07:00
Patrick Steinhardt dfc4617a53 meson: improve summary of auto-detected features
The summary of auto-detected features prints a boolean for every option
to tell the user whether or not the feature has been auto-enabled or
not. This summary can be improved though, as in some cases this boolean
is derived from a dependency. So if we pass in the dependency directly,
then Meson knows to both print a boolean and, if the dependency was
found, it also prints a version number.

Adapt the code accordingly and enable `bool_yn` so that actual booleans
are formatted similarly to dependencies. Before this change:

  Auto-detected features
    benchmarks      : true
    curl            : true
    expat           : true
    gettext         : true
    gitweb          : true
    iconv           : true
    pcre2           : true
    perl            : true
    python          : true

And after this change, we now see the version numbers as expected:

  Auto-detected features
    benchmarks      : YES
    curl            : YES 8.14.1
    expat           : YES 2.7.1
    gettext         : YES
    gitweb          : YES
    iconv           : YES
    pcre2           : YES 10.44
    perl            : YES
    python          : YES

Note that this change also enables colorization of the boolean options,
green for "YES" and red for "NO".

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-09 08:19:32 -07:00
Patrick Steinhardt f61f538576 meson: stop printing 'https' option twice in our summaries
The value for the 'https' backend option is printed twice: once via the
summary of auto-detected features and once via our summary of backends.
Drop it from the former summary.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-09 08:19:32 -07:00
Patrick Steinhardt 10f048fcd1 meson: stop discovering native version of Python
When Python features are enabled we search both for a native and
non-native version of Python. This is wrong though: we don't use Python
in our build process, so there is no need to search for it in the first
place.

There is one location where we use the native version of Python, namely
when deciding whether or not we want to wire up git-p4(1). This check is
invalid though, as we shouldn't check for the build host to have Python,
but for the target host.

Fix this invalid check to use the non-native version of Python and stop
searching for a native version of Python altogether.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-09 08:19:32 -07:00
Jeff King a5a727c448 remote: detect collisions in remote names
When two remotes collide in the destinations of their fetch refspecs,
the results can be confusing. For example, in this silly example:

  git config remote.one.url [...]
  git config remote.one.fetch +refs/heads/*:refs/remotes/collide/*
  git config remote.two.url [...]
  git config remote.two.fetch +refs/heads/*:refs/remotes/collide/*
  git fetch --all

we may try to write to the same ref twice (once for each remote we're
fetching). There's also a more subtle version of this. If you have
remotes "outer/inner" and "outer", then the ref "inner/branch" on the
second remote will conflict with just "branch" on the former (they both
want to write to "refs/remotes/outer/inner/branch").

We probably don't want to forbid this kind of overlap completely. While
the results can be confusing, there are legitimate reasons to have
multiple refs write into the same namespace (e.g., if one is a "backup"
of the other that is rarely fetched from).

But it may be worth limiting the porcelain "git remote" command to avoid
this confusion. The example above cannot be done with "git remote",
because it always[1] matches the refspecs to the remote name, and you
can only have one instance of each remote name. But you can still
trigger the more subtle variant like this:

  git remote add outer [...]
  git remote add outer/inner [...]

So let's detect that kind of name collision (in both directions) and
forbid it. You can still do whatever you like by manipulating the config
directly, but this should prevent the most obvious foot-gun.

[1] Almost always. With the --mirror option, the resulting refspec will
    just write into "refs/*"; the remote name does not appear in the ref
    namespace at all.

    Our new "names must not overlap" rule is not necessary for that
    case, but it seems reasonable to enforce it consistently. We already
    require all remote names to be valid in the ref namespace, even
    though we won't ever use them in that context for --mirror remotes.

    Likewise, our new rule doesn't help with overlap here. Any two
    mirror remotes will always overlap (in fact, any mirror remote along
    with any other single one, since refs/remotes/ is a subset of the
    mirrored refs). I'm not sure this is worth worrying about, but if it
    is, we'd want an additional rule like "mirror remotes must be the
    only remote".

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-08 16:30:19 -07:00
Junio C Hamano a30f80fde9 The eighth batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-08 15:51:23 -07:00
Junio C Hamano cdb7872247 Merge branch 'kn/fetch-push-bulk-ref-update'
"git push" and "git fetch" are taught to update refs in batches to
gain performance.

* kn/fetch-push-bulk-ref-update:
  receive-pack: handle reference deletions separately
  refs/files: skip updates with errors in batched updates
  receive-pack: use batched reference updates
  send-pack: fix memory leak around duplicate refs
  fetch: use batched reference updates
  refs: add function to translate errors to strings
2025-07-08 15:49:19 -07:00
Junio C Hamano 0ba1a581df Merge branch 'maint-2.50'
* maint-2.50:
  t: avoid git config syntax from newer releases
  Documentation/RelNotes: use .adoc extension for new security releases
2025-07-08 15:43:31 -07:00
Junio C Hamano f368df439b Merge branch 'maint-2.49' into maint-2.50
* maint-2.49:
  t: avoid git config syntax from newer releases
2025-07-08 15:42:33 -07:00
Junio C Hamano 47243eeed1 Merge branch 'maint-2.48' into maint-2.49
* maint-2.48:
  t: avoid git config syntax from newer releases
2025-07-08 15:42:14 -07:00
Junio C Hamano a1cf0cf13a Merge branch 'maint-2.47' into maint-2.48
* maint-2.47:
  t: avoid git config syntax from newer releases
2025-07-08 15:42:02 -07:00
Junio C Hamano 515a060550 Merge branch 'maint-2.46' into maint-2.47
* maint-2.46:
  t: avoid git config syntax from newer releases
2025-07-08 15:41:51 -07:00
Junio C Hamano 3d6d1296a4 Merge branch 'maint-2.45' into maint-2.46
This turns into a no-op merge, since more recent versions of Git
newer than 2.46 track do support the newer "git config" syntax.

* maint-2.45:
  t: avoid git config syntax from newer releases
2025-07-08 15:40:52 -07:00
Junio C Hamano a98e34b5a7 Merge branch 'maint-2.44' into maint-2.45
* maint-2.44:
  t: avoid git config syntax from newer releases
2025-07-08 15:35:35 -07:00
Junio C Hamano 09669c729a Merge branch 'maint-2.43' into maint-2.44
* maint-2.43:
  t: avoid git config syntax from newer releases
2025-07-08 15:33:02 -07:00
Junio C Hamano 18e6be837a Merge branch 'tz/avoid-newer-config-syntax-in-older-maint-tracks' into maint-2.43
* tz/avoid-newer-config-syntax-in-older-maint-tracks:
  t: avoid git config syntax from newer releases
2025-07-08 15:31:56 -07:00
Todd Zullinger 428c9241c6 t: avoid git config syntax from newer releases
In a recent security release, 05e9cd64ee (config: quote values
containing CR character, 2025-05-19) added calls to `git config get`,
`git config set`, and `git config unset` which are not present on the
maint-2.43 branch.

These subcommands were added in the following commits, released in
git-2.46.0:

  4e51389000 (builtin/config: introduce "get" subcommand, 2024-05-06),
  00bbdde141 (builtin/config: introduce "set" subcommand, 2024-05-06),
  95ea69c67b (builtin/config: introduce "unset" subcommand, 2024-05-06)

Revert to the previous `git config` syntax for older maintenance
branches.

Signed-off-by: Todd Zullinger <tmz@pobox.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-08 15:06:35 -07:00
Patrick Steinhardt 52d0c32b9f t1006: fix broken TAP format
When running t1006 via Meson we receive an error about invalid TAP
format:

    $ meson test t1006-cat-file
    1/1 t1006-cat-file        OK              3.86s   420 subtests passed

    stdout: 147: UNKNOWN: c308ae01840d8e620ad554ee5d77fe114dc2d912:path with spaces
    stdout: 159: UNKNOWN: 3625298bf5e7c464a7d0e38ea80c2a5b5904d9a3e5b2b025b67f360e09b68dc7:path with spaces
    ERROR: Unknown TAP output lines for a supported TAP version.
    This is probably a bug in the test; if they are not TAP syntax, prefix them with a #

    Ok:                1
    Fail:              0

While Meson copes with it alright, it's still annoying to see these
errors on every test run.

The root cause of the broken format is a call to grep(1) that gets
executed outside of a test case, which has been added recently via
9fd38038b9 (t1006: update 'run_tests' to test generic object
specifiers, 2025-06-02). This call is done to determine whether a
subsequent test case is expected to succeed or fail, so it makes sense
to have it execute outside of a test case. But whenever we do that, we
must be extra careful to not generate any output that breaks the TAP
format.

Fix the issue by adding '-q' to the command so that it doesn't print
any matching lines.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-08 14:54:43 -07:00
Patrick Steinhardt a3a7f20516 refs/files: remove empty parent dirs when ref creation fails
When creating a new reference in the "files" backend we first create the
directory hierarchy for that reference, then create the lockfile for
that reference, and finally rename the lockfile into place. When the
transaction gets aborted we prune the lockfile, but we don't clean up
the directory hierarchy that we may have created for the lockfile.

In some egde cases this can lead to lots of empty directories being
cluttered in the ".git/refs" directory that really serve no purpose at
all. We know to prune such empty directories when packing refs, but that
only patches over the issue.

Improve this by removing empty parents when cleaning up still-locked
references in `files_transaction_cleanup()`. This function is also
called when preparing or committing the transaction, so this change also
helps when not explicitly aborting the transaction.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-08 14:52:56 -07:00
Patrick Steinhardt ad7780b38f docs/git-pack-refs: document heuristic used for packing loose refs
The `git pack-refs --auto` flag asks the ref backend to decide for
itself whether or not references need to be repacked. This is done to
ensure that we don't repack in cases where the backend is already in a
good-enough state, which is typically the case for the "reftable"
backend that performs auto-compaction on writes.

As such, we initially only had heuristics in place for the "reftable"
backend. The "files" backend didn't have any heuristics, so we'd repack
loose references every time `git pack-refs --auto` was executed. This
caused excessive repacking with that backend though, which is why we
eventually implemented a heuristic via c3459ae9ef (refs/files: use
heuristic to decide whether to repack with `--auto`, 2024-09-04).

The documentation for the `--auto` flag hasn't been updated accordingly
and still claims that we don't have any metrics for the "files" backend.
Update it to reflect the new reality.

Reported-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-08 13:44:31 -07:00
Junio C Hamano 463c211685 Merge branch 'maint-2.49' into maint-2.50
* maint-2.49:
  Documentation/RelNotes: use .adoc extension for new security releases
2025-07-08 13:04:39 -07:00
Taylor Blau 7f5dd143ac Documentation/RelNotes: use .adoc extension for new security releases
When preparing the latest round of security fixes, we wrote release
notes in v2.43.7, and then successively merged those up through to the
various 'maint' branches.

However, the 2.49 release series is the first to have commit 1f010d6bdf
(doc: use .adoc extension for AsciiDoc files, 2025-01-20). This means
that we should have renamed the new-but-historical release notes from
*.txt to *.adoc during the merge into the 'maint-2.49' branch, but
neglected to do so.

Rename them accordingly to match the convention introduced by
1f010d6bdf. Since the release materials in question here were prepared
before v2.50.0 was tagged, the 'maint' track for that release series is
OK as is.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-08 13:03:27 -07:00
Junio C Hamano 038143def7 Sync with Git 2.50.1 2025-07-07 15:08:10 -07:00
Junio C Hamano 41905d6022 The seventh batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 14:12:58 -07:00
Junio C Hamano 649162c7a9 Merge branch 'cb/ci-freebsd-update-to-14.3'
CI updates.

* cb/ci-freebsd-update-to-14.3:
  ci: update FreeBSD image to 14.3
2025-07-07 14:12:58 -07:00
Junio C Hamano 0dc5b7627e Merge branch 'jj/doc-branch-markup-fix'
Doc markup fix.

* jj/doc-branch-markup-fix:
  doc: improve formatting in branch section
2025-07-07 14:12:57 -07:00
Junio C Hamano 844911960c Merge branch 'cb/daemon-retry-interrupted-accept'
When "git daemon" sees a signal while attempting to accept() a new
client, instead of retrying, it skipped it by mistake, which has
been corrected.

* cb/daemon-retry-interrupted-accept:
  daemon: correctly handle soft accept() errors in service_loop
2025-07-07 14:12:57 -07:00
Junio C Hamano d4a59c5a29 Merge branch 'jk/fix-leak-send-pack'
Leakfix.

* jk/fix-leak-send-pack:
  send-pack: clean-up even when taking an early exit
  send-pack: clean up extra_have oid array
2025-07-07 14:12:57 -07:00
Junio C Hamano 0629460757 Merge branch 'cb/daemon-fd-check-fix'
Remove unnecessary check from "git daemon" code.

* cb/daemon-fd-check-fix:
  daemon: remove unnecesary restriction for listener fd
2025-07-07 14:12:56 -07:00
Junio C Hamano 7310e539ad Merge branch 'jk/submodule-remote-lookup-cleanup'
Updating submodules from the upstream did not work well when
submodule's HEAD is detached, which has been improved.

* jk/submodule-remote-lookup-cleanup:
  submodule: look up remotes by URL first
  submodule: move get_default_remote_submodule()
  submodule--helper: improve logic for fallback remote name
  remote: remove the_repository from some functions
  dir: move starts_with_dot(_dot)_slash to dir.h
  remote: fix tear down of struct remote
  remote: remove branch->merge_name and fix branch_release()
2025-07-07 14:12:56 -07:00
Jean-Noël Avila b27be108c8 doc: git-log: convert log config to new doc format
- Use `backticks` for keywords and more complex option
descriptions. The new rendering engine will apply synopsis rules to
these spans.
- Explain possible options in description list instead of in a paragraph.

Signed-off-by: Jean-Noël Avila <jn.avila@free.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 13:46:47 -07:00
Jean-Noël Avila 0b4ccb2199 doc: git-log: convert diff options to new doc format
- Use `backticks` for keywords and more complex option
descriptions. The new rendering engine will apply synopsis rules to
these spans.
- In description lists, put each option on its own line, to make them more
searchable and enable automatic translation of the options.

Signed-off-by: Jean-Noël Avila <jn.avila@free.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 13:45:00 -07:00
Jean-Noël Avila ca484a90e2 doc: git-log: convert pretty formats to new doc format
- Use _<placeholder>_ instead of <placeholder> in the description
- Use `backticks` for keywords and more complex option
descriptions. The new rendering engine will apply synopsis rules to
these spans.

For all the formats in the form of %(foo), the formatting needs to be
heavier because we not want the parentheses to be rendered as syntax
elements,but as keywords, i.e. we need to circumvent the syntax highlighting
of synopsis.  In this particular case, this requires the heavy escaping of
the parts that contain parentheses with ++.

Signed-off-by: Jean-Noël Avila <jn.avila@free.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 13:45:00 -07:00
Jean-Noël Avila 06db6a3c4a doc: git-log: convert pretty options to new doc format
- Use _<placeholder>_ instead of <placeholder> in the description
- Use `backticks` for keywords and more complex option
descriptions. The new rendering engine will apply synopsis rules to
these spans.

Signed-off-by: Jean-Noël Avila <jn.avila@free.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 13:45:00 -07:00
Jean-Noël Avila d9d297a5f7 doc: git-log: convert rev list options to new doc format
- Fix some malformed synopis of options
- Use _<placeholder>_ instead of <placeholder> in the description
- Use `backticks` for keywords and more complex option
descriptions. The new rendering engine will apply synopsis rules to
these spans.
- Add the '%' sign to the characters of keywords.

Signed-off-by: Jean-Noël Avila <jn.avila@free.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 13:45:00 -07:00
Jean-Noël Avila 204f730894 doc: git-log: convert line range format to new doc format
- Use _<placeholder>_ instead of <placeholder> in the description
- Use `backticks` for keywords and more complex option
descriptions. The new rendering engine will apply synopsis rules to
these spans.

Signed-off-by: Jean-Noël Avila <jn.avila@free.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 13:45:00 -07:00
Jean-Noël Avila 0c25856722 doc: git-log: convert line range options to new doc format
format placeholders in italics and keywords in monospace
- Use _<placeholder>_ instead of <placeholder> in the description
- Use `backticks` for keywords and more complex option
descriptions. The new rendering engine will apply synopsis rules to
these spans.

Signed-off-by: Jean-Noël Avila <jn.avila@free.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 13:45:00 -07:00
Jean-Noël Avila ffe24e00a5 doc: git-log convert rev-list-description to new doc format
Use `backticks` for commit ranges. The new rendering engine will apply
synopsis rules to these spans.

Signed-off-by: Jean-Noël Avila <jn.avila@free.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 13:45:00 -07:00
Jean-Noël Avila 026f2e3be2 doc: convert git-log to new documentation format
- Switch the synopsis to a synopsis block which will automatically
  format placeholders in italics and keywords in monospace
- Use _<placeholder>_ instead of <placeholder> in the description
- Use `backticks` for keywords and more complex option
descriptions. The new rendering engine will apply synopsis rules to
these spans.

We also transform inline descriptions of possible values of option
--decorate into a list, which is more readable and extensible.

Signed-off-by: Jean-Noël Avila <jn.avila@free.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 13:45:00 -07:00
redoste 4498127b04 ssh signing: don't detach the filename strbuf from key_file tempfile
Detaching the filename string from the tempfile structure used to cause
delete_tempfile() to fail and the temporary file was not cleaned up.

While it's possible to get rid of the allocation and copy from
xstrdup(), it keeps the code symetric with the other branch since
interpolate_path() also allocates and ssh_signing_key_file is freed
in both cases.

The exisiting test was updated to check if the temporary files are
properly deleted. To prevent TMPDIR from leaking into the other tests, a
new subshell is created, however this prevents test_config from working.
The cleanup of the config changed in the subshell is done by
test_unconfig in a call to test_when_finished outside of it.

Helped-by: brian m. carlson <sandals@crustytoothpaste.net>
Helped-by: Patrick Steinhardt <ps@pks.im>
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: redoste <redoste@redoste.xyz>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 13:41:25 -07:00
Carlo Marcelo Arenas Belón 781c1cf571 builtin/gc: correct total_ram calculation with HAVE_BSD_SYSCTL
The calls to sysctl() assume a 64-bit memory size for the variable
holding the value, but the actual size depends on the key name and
platform, at least for HW_PHYSMEM.

Detect any mismatched reads, and retry with a shorter variable
when needed.

Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 10:04:32 -07:00
Patrick Steinhardt de404249ab t5333: fix missing terminator for sed(1) 's' command
In 6aec8d38fd (t: refactor tests depending on Perl to print data,
2025-04-03) we have changed some of the tests in t4150 to use sed(1)
instead of Perl. One of the conversions is broken though:

    sed: -e expression #1, char 41: unterminated `s' command

Curiously enough, the test itself still passes. This is caused by a
sequence of failures:

  1. The output of sed(1) is piped into git-update-ref(1), and because
     sed(1) is the upstream command we don't notice that it fails.

  2. git-update-ref(1) does not receive any input and thus won't create
     any references.

  3. We then repack the repository with the configured pseudo merges
     pattern, but as we didn't create any references the pattern doesn't
     match anything.

  4. We use `test_pseudo_merges()` to compute the list of pseudo-merges
     and write it into a file. This file is empty as there are none.

  5. The loop over the pseudo-merges becomes a no-op.

  6. The final test succeeds as well because the number of lines in an
     empty file is obviously the same as the number of unique lines,
     namely zero.

Fix the issue by adding the terminating '|' to the sed(1) command.
Furthermore, make the test a tiny bit more robust by not using it as
part of a pipe.

Reported-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 09:12:44 -07:00
Patrick Steinhardt 385e175cb5 t4150: fix warning printed by awk due to escaped '\@'
In 6aec8d38fd (t: refactor tests depending on Perl to print data,
2025-04-03) we have changed one of the tests in t4150 to use awk(1)
instead of Perl. The test works, but at least gawk(1) prints a warning
now:

    awk: cmd. line:3: warning: escape sequence `\@' treated as plain `@'

Fix this by removing the backslash.

Reported-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 09:12:43 -07:00
Timur Sultanaev 953049eed8 docs: correct ORIG_HEAD example in "git merge" documentation
Documentation for git-merge incorrectly notes that
tip of the current branch on ascii diagram is C,
while it is actually G (current branch is master,
HEAD on diagram is G).

Additionally diagrams on the page are adjusted
to use spaces instead of tabs, so that they align
regardless of tab size. This is in line with
diagrams on other git documentation pages.

Signed-off-by: Timur Sultanaev <str.write@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 08:52:58 -07:00
Ramsay Jones 0c83bbc704 build: fix FreeBSD build when sysinfo compat library installed
Commit 50dec7c566 ("config.mak.uname: add sysinfo() configuration for
cygwin", 2025-04-17) and later commit 187ce0222f ("configure.ac: upgrade
to a compilation check for sysinfo", 2025-05-19) added a 'sysinfo()'
check to the autoconf build.

The FreeBSD system has an optional sysinfo compatibility library, used
to assist in porting software, which causes the build to fail when it
is installed. The reason for the failure is the lack of '-lsysinfo'
during the linking step.

Several solutions were considered:

  - add a 'linking' check to configure.ac in order to determine the
    need to link a separate library (-lsysinfo). (This would require
    a similar change to meson.build).

  - change the order of the preprocessor conditionals in the total_ram()
    function in 'builtin/gc.c', so that the *BSD sysctl() function
    (in the HAVE_BSD_SYSCTL block) takes priority over the sysinfo()
    function (in the HAVE_SYSINFO block).

  - suppress the setting of HAVE_SYSINFO when HAVE_BSD_SYSCTL has been
    defined (in both configure.ac and meson.build).

The first solution above, while simple, adds unnecessary code (the
sysinfo compat function is likely implemented using sysctl() anyway)
when git is happy to use sysctl() on *BSD systems.

The second solution would only be required by the autoconf and meson
build systems, the Makefile already sets the build variables to the
required values (since they are not 'auto-detected').

Here we opt for the final solution above, since it only requires that
we prioritise the 'auto-detected' build variables in the autoconf and
meson builds.

In order to fix the FreeBSD build, move the sysinfo() check after the
determination of the HAVE_BSD_SYSCTL build variable, suppressing the
setting of HAVE_SYSINFO if HAVE_BSD_SYSCTL is defined. Apply this logic
to both the configure.ac and meson.build file.

[Thanks go to Renato Botelho <garga@FreeBSD.org> for testing this patch
on FreeBSD.]

Tested-by: Renato Botelho <garga@FreeBSD.org>
Signed-off-by: Ramsay Jones <ramsay@ramsayjones.plus.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 08:40:41 -07:00
Ayush Chandekar 7cd03a555a builtin/prune: stop depending on 'the_repository'
Refactor builtin/prune.c to remove the dependency on the global
'the_repository'. Replace all the occurrences of 'the_repository' with
repo and thus remove the definition '#define
USE_THE_REPOSITORY_VARIABLE'. Also, add a test to make sure that 'git
prune -h' can be called when the repository is `NULL`.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Ghanshyam Thakkar <shyamthakkar001@gmail.com>
Signed-off-by: Ayush Chandekar <ayu.chandekar@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 08:31:13 -07:00
Ayush Chandekar 44e300a974 repository: move 'repository_format_precious_objects' to repo scope
The 'extensions.preciousObjects' setting when set true, prevents
operations that might drop objects from the object storage. This setting
is populated in the global variable
'repository_format_precious_objects'.

Move this global variable to repo scope by adding it to 'struct
repository and also refactor all the occurences accordingly.

This change is part of an ongoing effort to eliminate global variables,
improve modularity and help libify the codebase.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Ghanshyam Thakkar <shyamthakkar001@gmail.com>
Signed-off-by: Ayush Chandekar <ayu.chandekar@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 08:31:13 -07:00
shejialuo 6e5b26c3ff u-string-list: move "remove duplicates" test to "u-string-list.c"
We use "test-tool string-list remove_duplicates" to test the
"string_list_remove_duplicates" function. As we have introduced the unit
test, we'd better remove the logic from shell script to C program to
improve test speed and readability.

As all the tests in shell script are removed, let's just delete the
"t0063-string-list.sh" and update the "meson.build" file to align with
this change.

Also we could simply remove "DISABLE_SIGN_COMPARE_WARNINGS" due to we
have already deleted related code.

Unfortunately, we cannot totally remove "test-string-list.c" due to that
we would test the performance of sorting about string list by executing
"test-tool string-list sort" in "p0071-sort.sh".

Signed-off-by: shejialuo <shejialuo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 08:07:47 -07:00
shejialuo 7e7ce78265 u-string-list: move "filter string" test to "u-string-list.c"
We use "test-tool string-list filter" to test the "filter_string_list"
function. As we have introduced the unit test, we'd better remove the
logic from shell script to C program to improve test speed and
readability.

Signed-off-by: shejialuo <shejialuo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 08:07:46 -07:00
shejialuo 62c514a9ef u-string-list: move "test_split_in_place" to "u-string-list.c"
We use "test-tool string-list split_in_place" to test the
"string_list_split_in_place" function. As we have introduced the unit
test, we'd better remove the logic from shell script to C program to
improve test speed and readability.

Signed-off-by: shejialuo <shejialuo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 08:07:46 -07:00
shejialuo 07d90fda58 u-string-list: move "test_split" into "u-string-list.c"
We rely on "test-tool string-list" command to test the functionality of
the "string-list". However, as we have introduced clar test framework,
we'd better move the shell script into C program to improve speed and
readability.

Create a new file "u-string-list.c" under "t/unit-tests", then update
the Makefile and "meson.build" to build the file. And let's first move
"test_split" into unit test and gradually convert the shell script into
C program.

In order to create `string_list` easily by simply specifying strings in
the function call, create "t_vcreate_string_list_dup" function to do
this.

Then port the shell script tests to C program and remove unused
"test-tool" code and tests.

Signed-off-by: shejialuo <shejialuo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 08:07:46 -07:00
shejialuo 67cfd2924d string-list: enable sign compare warnings check
In "add_entry", we call "get_entry_index" function to get the inserted
position. However, as the return type of "get_entry_index" function is
`int`, there is a sign compare warning when comparing the `index` with
the `list-nr` of unsigned type.

"get_entry_index" would always return unsigned index. However, the
current binary search algorithm initializes "left" to be "-1", which
necessitates the use of signed `int` return type.

The reason why we need to assign "left" to be "-1" is that in the
`while` loop, we increment "left" by 1 to determine whether the loop
should end. This design choice, while functional, forces us to use
signed arithmetic throughout the function.

To resolve this sign comparison issue, let's modify the binary search
algorithm with the following approach:

1. Initialize "left" to 0 instead of -1
2. Use `left < right` as the loop termination condition instead of
   `left + 1 < right`
3. When searching the right part, set `left = middle + 1` instead of
   `middle`

Then, we could delete "#define DISABLE_SIGN_COMPARE_WARNING" to enable
sign warnings check for "string-list".

Signed-off-by: shejialuo <shejialuo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 08:07:46 -07:00
shejialuo 885becd9c4 string-list: return index directly when inserting an existing element
When inserting an existing element, "add_entry" would convert "index"
value to "-1-index" to indicate the caller that this element is in the
list already. However, in "string_list_insert", we would simply convert
this to the original positive index without any further action.

In 8fd2cb4069 (Extract helper bits from c-merge-recursive work,
2006-07-25), we create "path-list.c" and then introduce above code path.

Let's directly return the index as we don't care about whether the
element is in the list by using "add_entry". In the future, if we want
to let "add_entry" tell the caller, we may add "int *exact_match"
parameter to "add_entry" instead of converting the index to negative to
indicate.

Signed-off-by: shejialuo <shejialuo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 08:07:46 -07:00
shejialuo 394e063bf9 string-list: remove unused "insert_at" parameter from add_entry
In "add_entry", we accept "insert_at" parameter which must be either -1
(auto) or between 0 and `list->nr` inclusive. Any other value is
invalid. When caller specify any invalid "insert_at" value, we won't
check the range and move the element, which would definitely cause the
trouble.

However, we only use "add_entry" in "string_list_insert" function and we
always pass the "-1" for "insert_at" parameter. So, we never use this
parameter to insert element in a user specified position.

And we should know why there is such code path in the first place. We
used to have another function "string_list_insert_at_index()", which
uses the extra "insert_at" parameter. And in f8c4ab611a (string_list:
remove string_list_insert_at_index() from its API, 2014-11-24), we
remove this function but we don't clean all the code path.

Let's simply delete this parameter as we'd better use "strmap" for such
functionality.

Signed-off-by: shejialuo <shejialuo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 08:07:45 -07:00
shejialuo ba472ab2f1 string-list: fix sign compare warnings for loop iterator
There are a couple of "-Wsign-compare" warnings in "string-list.c". Fix
trivial ones that result from a mismatched loop iterator type.

There is a single warning left after these fixes. This warning needs
a bit more care and is thus handled in subsequent commits.

Signed-off-by: shejialuo <shejialuo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 08:07:45 -07:00
Han Young 9455397a5c read-cache: report lock error when refreshing index
In the repo_refresh_and_write_index of read-cache.c, we return -1 to
indicate that writing the index to disk failed.
However, callers do not use this information. Commands such as stash print
  "could not write index"
and then exit, which does not help to discover the exact problem.

We can let repo_hold_locked_index print the error message if the locking
failed.

Signed-off-by: Han Young <hanyang.tony@bytedance.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 06:49:07 -07:00
Raymond E. Pasco 2b49d97fcb apply docs: clarify wording for --intent-to-add
Avoid using a double negative, and keep in mind that --index and
--cached are distinct modes of operation.

Signed-off-by: Raymond E. Pasco <ray@ameretat.dev>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 06:41:11 -07:00
Raymond E. Pasco a4c969aa0d t4140: test apply --intent-to-add interactions
Test that applying a new file creation patch with --intent-to-add to
an existing index does not modify the index outside adding the correct
intents-to-add, and that applying a patch with both modifications
and new file creations with --intent-to-add correctly only adds
intents-to-add to the index.

Signed-off-by: Raymond E. Pasco <ray@ameretat.dev>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 06:41:11 -07:00
Raymond E. Pasco 7c6e61f877 apply: only write intents to add for new files
In the "apply only to files" mode (i.e., neither --index nor --cached
mode), the index should not be touched except to record intents to
add when --intent-to-add is on. Because having --intent-to-add on sets
update_index, to indicate that we may touch the index, we can't rely
only on that flag in create_file() (which is called to write both new
files and updated files) to decide whether to write an index entry;
if we did, we would write an index entry for every file being patched
(which would moreover be an intent-to-add entry despite not being a
new file, because we are going to turn on the CE_INTENT_TO_ADD flag
in add_index_entry() if we enter it here and ita_only is true).

To decide whether to touch the index, we need to check the
specific reason the index would be updated, rather than merely
their aggregate in the update_index flag. Because we have already
entered write_out_results() and are performing writes, we know that
state->apply is true. If state->check_index is additionally true, we
are in --index or --cached mode, which updates the index and should
always write, whereas if we are merely in ita_only mode we must only
write if the patch is a new file creation patch.

Signed-off-by: Raymond E. Pasco <ray@ameretat.dev>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 06:41:10 -07:00
Raymond E. Pasco 57391a96fb apply: read in the index in --intent-to-add mode
There are three main modes of operation for apply: applying only to the
worktree, applying to the worktree and index (--index), and applying
only to the index (--cached).

The --intent-to-add flag modifies the first of these modes, applying
only to the worktree, in a way which touches the index, because intents
to add are special index entries. However, since its introduction
in cff5dc09ed (apply: add --intent-to-add, 2018-05-26), it has not
worked correctly in any but the most trivial (empty repository)
cases, because the index is never read in (in apply, this is done in
read_apply_cache()) before writing to it.

This causes the operation to clobber the old, correct index with a
new empty-tree index before writing intent-to-add entries to this
empty index; the final result is that the index now records every
existing file in the repository as deleted, which is incorrect.

This error can be corrected by first reading the index. The
update_index flag is correctly set if ita_only is true, because this
flag causes the index to be updated. However, if we merely gate the
call to read_apply_cache() behind update_index, then it will not be
read when state->apply is false, even if it must be checked due to
being in --index or --cached mode. Therefore, we instead read the
index if it will be either checked or updated, because reading the
index is a prerequisite to either.

Reported-by: Ryan Hodges <rhodges@cisco.com>
Original-patch-by: Johannes Altmanninger <aclopte@gmail.com>
Signed-off-by: Raymond E. Pasco <ray@ameretat.dev>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 06:41:10 -07:00
Jeff King 375ac087c5 setup_revisions(): turn on diffs for all-negative diff filter
When the user gives us a diff filter like --diff-filter=D, we need to do
a tree diff even if we're not planning to show the diff result itself,
in order to decide whether to show the commit at all. So there's an
explicit check of revs->diffopt.filter in setup_revisions(), and we set
revs->diff if any bits are set.

Originally that "filter" field covered both positive capital-letter
filters (like "D") and also negative lowercase filters (like "d"), so it
was sufficient for both cases. But later, 75408ca949 (diff-filter: be
more careful when looking for negative bits, 2022-01-28) split the
negative bits out into a "filter_not" field.

We eventually fold those into "filter", but not until diff_setup_done()
is called, which happens after our explicit check. As a result, a purely
negative filter like:

  git log --diff-filter=d

failed to turn on diffs at all. But rather than fail to filter by diff,
because the filter variable is eventually set, we mistakenly show no
commits at all, thinking that the empty diffs were cases where nothing
passed through the filter.

The smallest fix here is to just have our check look for any bits in
either "filter" or "filter_not". I suspect it would also be OK to
reorder the function a bit to call diff_setup_done() earlier, but that
risks violating some other subtle ordering dependency. So I went with
the simple and safe solution here.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 06:40:23 -07:00
Patrick Steinhardt 793b14e1c8 setup: use "reftable" format when experimental features are enabled
With the preceding commit we have announced the switch to the "reftable"
format in Git 3.0 for newly created repositories. The format is being
battle tested by GitLab and a couple of other developers, and except for
a small handful of issues exposed early after it has been merged it has
been rock solid. Regardless of that though the test user base is still
comparatively small, which increases the risk that we miss critical
bugs.

Address this by enabling the reftable format when experimental features
are enabled. This should increase the test user base by some margin and
thus give us more input before making the format the default.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 06:26:21 -07:00
Patrick Steinhardt d0b94577dd BreakingChanges: announce switch to "reftable" format
The "reftable" format has come a long way and has matured nicely since
it has been merged into git via 57db2a094d (refs: introduce reftable
backend, 2024-02-07). It fixes longstanding issues that cannot be fixed
with the "files" format in a backwards-compatible way and performs
significantly better in many use cases.

Announce that we will switch to the "reftable" format in Git 3.0 for
newly created repositories and wire up the change, hidden behind the
WITH_BREAKING_CHANGES preprocessor define.

This switch is dependent on support in the larger Git ecosystem. Most
importantly, libraries like JGit, libgit2 and Gitoxide should support
the reftable backend so that we don't break all applications and tools
built on top of those libraries.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-07 06:26:21 -07:00
Junio C Hamano 8b6f19ccfc The sixth batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-02 12:08:05 -07:00
Junio C Hamano 41d0310a83 Merge branch 'jt/imap-send-message-fix'
Update some error messages from "git imap-send".

* jt/imap-send-message-fix:
  imap-send: improve error messages with configuration hints
  imap-send: fix confusing 'store' terminology in error message
2025-07-02 12:08:05 -07:00
Junio C Hamano 94c9350a67 Merge branch 'ps/contrib-sweep'
Remove bunch of stuff from contrib/ hierarchy.

* ps/contrib-sweep:
  contrib: remove some scripts in "stats" directory
  contrib: remove "git-new-workdir"
  contrib: remove "emacs" directory
  contrib: remove "git-resurrect.sh"
  contrib: remove "persistent-https" remote helper
  contrib: remove "mw-to-git"
  contrib: remove "hooks" directory
  contrib: remove "thunderbird-patch-inline"
  contrib: remove remote-helper stubs
  contrib: remove "examples" directory
  contrib: remove "remotes2config.sh"
2025-07-02 12:08:05 -07:00
Junio C Hamano e6c30289c6 Merge branch 'ag/imap-send-resurrection'
"git imap-send" has been broken for a long time, which has been
resurrected and then taught to talk OAuth2.0 etc.

* ag/imap-send-resurrection:
  imap-send: fix minor mistakes in the logs
  imap-send: display the destination mailbox when sending a message
  imap-send: display port alongwith host when git credential is invoked
  imap-send: add ability to list the available folders
  imap-send: enable specifying the folder using the command line
  imap-send: add PLAIN authentication method to OpenSSL
  imap-send: add support for OAuth2.0 authentication
  imap-send: gracefully fail if CRAM-MD5 authentication is requested without OpenSSL
  imap-send: fix memory leak in case auth_cram_md5 fails
  imap-send: fix bug causing cfg->folder being set to NULL
2025-07-02 12:08:05 -07:00
Brett A C Sheffield f3a9558c8c gitremote-helpers.adoc: fix formatting
Add missing colon to fix formatting.

Signed-off-by: Brett A C Sheffield <bacs@librecast.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-02 11:59:54 -07:00
Carlo Marcelo Arenas Belón 0392f976a7 build: retire NO_UINTMAX_T
A previous commit removed the last user of it, and it is no
longer useful with the codebase moving towards C99, which
specifies its definition.

Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-02 09:10:01 -07:00
Carlo Marcelo Arenas Belón 46a3ab744b config.mak.uname: set NO_MEMMEM only for functional version
FreeBSD 6 introduced memmem(), but the implementation diverged
from what was standard everywhere else (including our "compat"
fallback).

FreeBSD 10.4 (went EOL in 2018) corrected the functionality bugs
but kept a suboptimal implementation until FreeBSD 11.4 (the last
version of FreeBSD 11, that went EOL in September 2021).

Let's draw the line to require FreeBSD 12 or newer, which allows us
to drop the special casing of FreeBSD 4.x and rely on the platform
implementation of memmem() unconditionally for all versions that are
still being supported.

Suggested-by: Brad Smith <brad@comstyle.com>
Helped-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-02 09:10:01 -07:00
Karthik Nayak 3f7e447aaf meson: add rule to run 'git clang-format'
The Makefile has a 'style' rule to run 'git clang-format'. While Meson
intrinsically supports a 'clang-format' target, which can be run when
using the ninja backend by running 'ninja clang-format', this runs the
formatting on all existing files.

Our Meson build doesn't yet support a way to run 'git clang-format',
which runs the formatter between the working directory and commit
provided. Add a new 'style' target to Meson to mimic the target in the
Makefile.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-02 09:05:29 -07:00
Karthik Nayak 73d8380e56 clang-format: add 'RemoveBracesLLVM' to the main config
In 1b8f306612 (ci/style-check: add `RemoveBracesLLVM` in CI job,
2024-07-23) we added 'RemoveBracesLLVM' to the CI job of running the
clang formatter.

This rule checks and warns against using braces on simple
single-statement bodies of statements. Since we haven't had any issues
regarding this rule, we can now move it into the main clang-format
config and remove it from being CI exclusive.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-02 09:05:29 -07:00
Karthik Nayak 9e45fc6ce5 clang-format: set 'ColumnLimit' to 0
When clang-format was introduced to the Git project in
6134de6ac1 (clang-format: outline the git project's coding style,
2017-08-14), the 'ColumnLimit' was set to 80. This is inline with our
recommendation in 'Documentation/CodingGuidelines', which states:

  We try to keep to at most 80 characters per line.

However while this is recommended limit, this is not the enforced
limit. In some cases in we do overflow this limit to prioritize
readability. Setting the 'ColumnLimit' also means that shorter lines are
concatenated to simply as the result would still be below 80 characters,
which is undesirable.

In the past, we tried to adjust the penalties around line wrapping, once
in 42efde4c29 (clang-format: adjust line break penalties, 2017-09-29)
and another time in 5e9fa0f9fa (clang-format: re-adjust line break
penalties, 2024-10-18). While these settings help tweak the line break
penalties to be more in-line with the requirements of the Git project,
using 'clang-format' still produces a lot of false positives.

So to make 'clang-format' more usable, set the 'ColumnLimit' to 0. This
means that line-wrapping is no-longer a concern of the formatter and
something that the user needs to take care of. The previous commit also
added a more flexible guideline to the '.editorconfig' setting a
'max_line_length' of 120 characters. This should provide some guidance
to users.

In the future, it would be nice to re-instate this limit with adequate
penalties which would follow our guidelines, but currently, it makes
more sense to have a working formatter which we can rely on and which
doesn't create too many false positives.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-02 09:05:29 -07:00
Phil Hord 87d8d8c5d0 clean up interface for refs_warn_dangling_symrefs
The refs_warn_dangling_symrefs interface is a bit fragile as it passes
in printf-formatting strings with expectations about the number of
arguments. This patch series made it worse by adding a 2nd positional
argument. But there are only two call sites, and they both use almost
identical display options.

Make this safer by moving the format strings into the function that uses
them to make it easier to see when the arguments don't match. Pass a
prefix string and a dry_run flag so the decision logic can be handled
where needed.

Signed-off-by: Phil Hord <phil.hord@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 18:42:25 -07:00
Phil Hord 0f84695499 refs: remove old refs_warn_dangling_symref
The dangling warning function that takes a single ref to search for
is no longer used.  Remove it.

Signed-off-by: Phil Hord <phil.hord@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 18:42:25 -07:00
Phil Hord cc7dc407fe fetch-prune: optimize dangling-ref reporting
When pruning during `git fetch` we check each pruned ref against the
ref_store one at a time to decide whether to report it as dangling.
This causes every local ref to be scanned for each ref being pruned.

If there are N refs in the repo and M refs being pruned, this code is
O(M*N). However, `git remote prune` uses a very similar function that
is only O(N*log(M)).

Remove the wasteful ref scanning for each pruned ref and use the faster
version already available in refs_warn_dangling_symrefs. Change the
message to include the original refname since the message is no longer
printed immediately after the line that did just print the refname.

In a repo with 126,000 refs, where I was pruning 28,000 refs, this
code made about 3.6 billion calls to strcmp and consumed 410 seconds
of CPU. (Invariably in that time, my remote would timeout and the
fetch would fail anyway.)

After this change, the same operation completes in under a second.

Signed-off-by: Phil Hord <phil.hord@gmail.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 18:42:25 -07:00
brian m. carlson c79bb70a2e Enable SHA-256 by default in breaking changes mode
Our document on breaking changes indicates that we intend to default to
SHA-256 in Git 3.0.  Since most people choose the default option, this
is an important security upgrade to our defaults.

To allow people to test this case, when WITH_BREAKING_CHANGES is set in
the configuration, build Git with SHA-256 as the default hash.  Update
the testsuite to use the build options information to automatically
choose the right value.

Note that if the command substitution for GIT_TEST_BUILTIN_HASH fails,
so does the testsuite—and quite spectacularly at that.  Thus, the case
where the Git binary is somehow subtly broken will not go undetected.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:58:26 -07:00
brian m. carlson 39153c8097 help: add a build option for default hash
We'd like users to be able to determine the hash algorithm that is the
builtin default in their version of Git.  This is useful for
troubleshooting, especially when we decide to change the default.  Add
an entry for the default hash in the output of git version
--build-options so that users can easily access that information and
include it in bug reports.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:58:26 -07:00
brian m. carlson 9d619f2ef8 t5300: choose the built-in hash outside of a repo
Right now, the built-in default hash is always SHA-1, but that will
change in a future commit.  Instead of assuming that operating outside
of a repository will always use SHA-1, look up the default hash
algorithm for operating outside of a repository using an appropriate
environment variable, which will always be correct.

Additionally, for operations outside of a repository, use the
DEFAULT_HASH_ALGORITHM prerequisite rather than SHA1.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:58:26 -07:00
brian m. carlson f957ce078f t4042: choose the built-in hash outside of a repo
Right now, the built-in default hash is always SHA-1, but that will
change in a future commit.  Instead of assuming that operating outside
of a repository will always use SHA-1, provide constants for both
algorithms and then simply ask test_oid for the built-in hash instead,
which will always be correct.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:58:25 -07:00
brian m. carlson 6866b42260 t1007: choose the built-in hash outside of a repo
Right now, the built-in default hash is always SHA-1, but that will
change in a future commit.  Instead of assuming that operating outside
of a repository will always use SHA-1, simply ask test_oid for the
built-in hash instead, which will always be correct.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:58:25 -07:00
brian m. carlson c470ac4ac4 t: default to compile-time default hash if not set
Right now, the default compile-time hash is SHA-1.  However, in the
future, this might change and it would be helpful to gracefully handle
this case in our testsuite.

To avoid making these assumptions, let's introduce a variable that
contains the built-in default hash and use it in our setup code as the
fallback value if no hash was explicitly set.  For now, this is always
SHA-1, but in a future commit, we'll allow adjusting this and the
variable will be more useful.

To allow us to make our tests more robust, allow test_oid to take the
--hash=builtin option to specify this hash, whatever it is.

Additionally, add a DEFAULT_HASH_ALGORITHM prerequisite to check for the
compile-time hash.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:58:25 -07:00
brian m. carlson d6e616cee7 setup: use the default algorithm to initialize repo format
When we define a new repository format with REPOSITORY_FORMAT_INIT, we
always use GIT_HASH_SHA1, and this value ends up getting used as the
default value to initialize a repository if none of the command line,
environment, or config tell us to do otherwise.

Because we might not always want to use SHA-1 as the default, let's
instead specify the default hash algorithm constant so that we will use
whatever the specified default is.

However, we also need to continue to read older repositories.  If we're
in a v0 repository or extensions.objectformat is not set, then we must
continue to default to the original hash algorithm: SHA-1.  If an
algorithm is set explicitly, however, it will override the hash_algo
member of the repository_format struct and we'll get the right value.

Similarly, if the repository was initialized before Git 0.99.3, then it
may lack a core.repositoryformatversion key, and some repositories lack
a config file altogether.  In both cases, format->version is -1 and we
need to assume that SHA-1 is in use.

Because clear_repository_format reinitializes the struct
repository_format and therefore sets the hash_algo member to the default
(which could in the future not be SHA-1), we need to reset this member
explicitly.  We know, however, that at the point we call
read_repository_format, we are actually reading an existing repository
and not initializing a new one or operating outside of a repository, so
we are not changing the default behavior back to SHA-1 if the default
algorithm is different.

It is potentially questionable that we ignore all repository
configuration if there is a config file but it doesn't have
core.repositoryformatversion set, in which case we reset all of the
configuration to the default.  However, it is unclear what the right
thing to do instead with such an old repository is and a simple git init
will add the missing entry, so for now, we simply honor what the
existing code does and reset the value to the default, simply adding our
initialization to SHA-1.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:58:24 -07:00
brian m. carlson 667d251a04 Use legacy hash for legacy formats
We have a large variety of data formats and protocols where no hash
algorithm was defined and the default was assumed to always be SHA-1.
Instead of explicitly stating SHA-1, let's use the constant to represent
the legacy hash algorithm (which is still SHA-1) so that it's clear
for documentary purposes that it's a legacy fallback option and not an
intentional choice to use SHA-1.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:58:24 -07:00
brian m. carlson dc9c16c2fc builtin: use default hash when outside a repository
We have some commands that can operate inside or outside a repository.
If we're operating outside a repository, we clearly cannot use the
repository's hash algorithm as a default since it doesn't exist, so
instead, let's pick the default instead of specifically SHA-1.  Right
now this results in no functional change since the default is SHA-1, but
that may change in the future.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:58:24 -07:00
brian m. carlson 1f68f3da87 hash: add a constant for the legacy hash algorithm
We have a a variety of uses of GIT_HASH_SHA1 littered throughout our
code.  Some of these really mean to represent specifically SHA-1, but
some actually represent the original hash algorithm used in Git which is
implied by older, legacy formats and protocols which do not contain hash
information.  For instance, the bundle v1 and v2 formats do not contain
hash algorithm information, and thus SHA-1 is implied by the use of
these formats.

Add a constant for documentary purposes which indicates this value.  It
will always be the same as SHA-1, since this is an essential part of
these formats, but its use indicates this particular reason and not any
other reason why SHA-1 might be used.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:58:23 -07:00
brian m. carlson ca6daa1368 hash: add a constant for the default hash algorithm
Right now, SHA-1 is the default hash algorithm in Git.  However, this
may change in the future.

We have many places in our code that use the SHA-1 constant to indicate
the default hash if none is specified, but it will end up being more
practical to specify this explicitly and clearly using a constant for
whatever the default hash algorithm is.  Then, if we decide to change it
in the future, we can simply replace the constant representing the
default with a new value.

For these reasons, introduce GIT_HASH_DEFAULT to represent the default
hash algorithm.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:58:23 -07:00
Patrick Steinhardt 841a03b404 odb: rename `read_object_with_reference()`
Rename `read_object_with_reference()` to `odb_read_object_peeled()` to
match other functions related to the object database and our modern
coding guidelines. Furthermore though, the old name didn't really
describe very well what this function actually does, which is to walk
down any commit and tag objects until an object of the required type has
been found. This is generally referred to as "peeling", so the new name
should be way more descriptive.

No compatibility wrapper is introduced as the function is not used a lot
throughout our codebase.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:46:39 -07:00
Patrick Steinhardt 08218b8cd4 odb: rename `pretend_object_file()`
Rename `pretend_object_file()` to `odb_pretend_object()` to match other
functions related to the object database and our modern coding
guidelines.

No compatibility wrapper is introduced as the function is not used a lot
throughout our codebase.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:46:38 -07:00
Patrick Steinhardt fcf8e3e111 odb: rename `has_object()`
Rename `has_object()` to `odb_has_object()` to match other functions
related to the object database and our modern coding guidelines.

Introduce a compatibility wrapper so that any in-flight topics will
continue to compile.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:46:38 -07:00
Patrick Steinhardt d4ff88aee3 odb: rename `repo_read_object_file()`
Rename `repo_read_object_file()` to `odb_read_object()` to match other
functions related to the object database and our modern coding
guidelines.

Introduce a compatibility wrapper so that any in-flight topics will
continue to compile.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:46:38 -07:00
Patrick Steinhardt e989dd96b8 odb: rename `oid_object_info()`
Rename `oid_object_info()` to `odb_read_object_info()` as well as their
`_extended()` variant to match other functions related to the object
database and our modern coding guidelines.

Introduce compatibility wrappers so that any in-flight topics will
continue to compile.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:46:37 -07:00
Patrick Steinhardt 16cf749496 odb: trivial refactorings to get rid of `the_repository`
All of the external functions provided by the object database subsystem
don't depend on `the_repository` anymore, but some internal functions
still do. Refactor those cases by plumbing through the repository that
owns the object database.

This change allows us to get rid of the `USE_THE_REPOSITORY_VARIABLE`
preprocessor define.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:46:37 -07:00
Patrick Steinhardt fc28a8a856 odb: get rid of `the_repository` when handling submodule sources
The "--recursive" flag for git-grep(1) allows users to grep for a string
across submodule boundaries. To make this work we add each submodule's
object sources to our own object database so that the objects can be
accessed directly.

The infrastructure for this depends on a global string list of submodule
paths. The caller is expected to call `add_submodule_odb_by_path()` for
each source and the object database will then eventually register all
submodule sources via `do_oid_object_info_extended()` in case it isn't
able to look up a specific object.

This reliance on global state is of course suboptimal with regards to
our libification efforts.

Refactor the logic so that the list of submodule sources is instead
tracked in the object database itself. This allows us to lose the
condition of `r == the_repository` before registering submodule sources
as we only ever add submodule sources to `the_repository` anyway. As
such, behaviour before and after this refactoring should always be the
same.

Rename the functions accordingly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:46:37 -07:00
Patrick Steinhardt 7eafd4472d odb: get rid of `the_repository` when handling the primary source
The functions `set_temporary_primary_odb()` and `restore_primary_odb()`
are responsible for managing a temporary primary source for the
database. Both of these functions implicitly rely on `the_repository`.

Refactor them to instead take an explicit object database parameter as
argument and adjust callers. Rename the functions accordingly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:46:36 -07:00
Patrick Steinhardt 798c661ce3 odb: get rid of `the_repository` in `for_each()` functions
There are a couple of iterator-style functions that execute a callback
for each instance of a given set, all of which currently depend on
`the_repository`. Refactor them to instead take an object database as
parameter so that we can get rid of this dependency.

Rename the functions accordingly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:46:36 -07:00
Patrick Steinhardt c44185f6c1 odb: get rid of `the_repository` when handling alternates
The functions to manage alternates all depend on `the_repository`.
Refactor them to accept an object database as a parameter and adjust all
callers. The functions are renamed accordingly.

Note that right now the situation is still somewhat weird because we end
up using the object store path provided by the object store's repository
anyway. Consequently, we could have instead passed in a pointer to the
repository instead of passing in the pointer to the object store. This
will be addressed in subsequent commits though, where we will start to
use the path owned by the object store itself.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:46:36 -07:00
Patrick Steinhardt 1b1679c688 odb: get rid of `the_repository` in `odb_mkstemp()`
Get rid of our dependency on `the_repository` in `odb_mkstemp()` by
passing in the object database as a parameter and adjusting all callers.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:46:35 -07:00
Patrick Steinhardt 961038856b odb: get rid of `the_repository` in `assert_oid_type()`
Get rid of our dependency on `the_repository` in `assert_oid_type()` by
passing in the object database as a parameter and adjusting all callers.

Rename the function to `odb_assert_oid_type()`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:46:35 -07:00
Patrick Steinhardt bd52ea343d odb: get rid of `the_repository` in `find_odb()`
Get rid of our dependency on `the_repository` in `find_odb()` by passing
in the object database in which we want to search for the source and
adjusting all callers.

Rename the function to `odb_find_source()`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:46:35 -07:00
Patrick Steinhardt 2f5181fce6 odb: introduce parent pointers
In subsequent commits we'll get rid of our use of `the_repository` in
"odb.c" in favor of explicitly passing in a `struct object_database` or
a `struct odb_source`. In some cases though we'll need access to the
repository, for example to read a config value from it, but we don't
have a way to access the repository owning a specific object database.

Introduce parent pointers for `struct object_database` to its owning
repository as well as for `struct odb_source` to its owning object
database, which will allow us to adapt those use cases.

Note that this change requires us to pass through the object database to
`link_alt_odb_entry()` so that we can set up the parent pointers for any
source there. The callchain is adapted to pass through the object
database accordingly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:46:34 -07:00
Patrick Steinhardt 8f49151763 object-store: rename files to "odb.{c,h}"
In the preceding commits we have renamed the structures contained in
"object-store.h" to `struct object_database` and `struct odb_backend`.
As such, the code files "object-store.{c,h}" are confusingly named now.
Rename them to "odb.{c,h}" accordingly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:46:34 -07:00
Patrick Steinhardt a1e2581a1e object-store: rename `object_directory` to `odb_source`
The `object_directory` structure is used as an access point for a single
object directory like ".git/objects". While the structure isn't yet
fully self-contained, the intent is for it to eventually contain all
information required to access objects in one specific location.

While the name "object directory" is a good fit for now, this will
change over time as we continue with the agenda to make pluggable object
databases a thing. Eventually, objects may not be accessed via any kind
of directory at all anymore, but they could instead be backed by any
kind of durable storage mechanism. While it seems quite far-fetched for
now, it is thinkable that eventually this might even be some form of a
database, for example.

As such, the current name of this structure will become worse over time
as we evolve into the direction of pluggable ODBs. Immediate next steps
will start to carve out proper self-contained object directories, which
requires us to pass in these object directories as parameters. Based on
our modern naming schema this means that those functions should then be
named after their subsystem, which means that we would start to bake the
current name into the codebase more and more.

Let's preempt this by renaming the structure. There have been a couple
alternatives that were discussed:

  - `odb_backend` was discarded because it led to the association that
    one object database has a single backend, but the model is that one
    alternate has one backend. Furthermore, "backend" is more about the
    actual backing implementation and less about the high-level concept.

  - `odb_alternate` was discarded because it is a bit of a stretch to
    also call the main object directory an "alternate".

Instead, pick `odb_source` as the new name. It makes it sufficiently
clear that there can be multiple sources and does not cause confusion
when mixed with the already-existing "alternate" terminology.

In the future, this change allows us to easily introduce for example a
`odb_files_source` and other format-specific implementations.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:46:34 -07:00
Patrick Steinhardt 1ace066449 object-store: rename `raw_object_store` to `object_database`
The `raw_object_store` structure is the central entry point for reading
and writing objects in a repository. The main purpose of this structure
is to manage object directories and provide an interface to access and
write objects in those object directories.

Right now, many of the functions associated with the raw object store
implicitly rely on `the_repository` to get access to its `objects`
pointer, which is the `raw_object_store`. As we want to generally get
rid of using `the_repository` across our codebase we will have to
convert this implicit dependency on this global variable into an
explicit parameter.

This conversion can be done by simply passing in an explicit pointer to
a repository and then using its `->objects` pointer. But there is a
second effort underway, which is to make the object subsystem more
selfcontained so that we can eventually have pluggable object backends.
As such, passing in a repository wouldn't make a ton of sense, and the
goal is to convert the object store interfaces such that we always pass
in a reference to the `raw_object_store` instead.

This will expose the `raw_object_store` type to a lot more callers
though, which surfaces that this type is named somewhat awkwardly. The
"raw_" prefix makes readers wonder whether there is a non-raw variant of
the object store, but there isn't. Furthermore, we nowadays want to name
functions in a way that they can be clearly attributed to a specific
subsystem, but calling them e.g. `raw_object_store_has_object()` is just
too unwieldy, even when dropping the "raw_" prefix.

Instead, rename the structure to `object_database`. This term is already
used a lot throughout our codebase, and it cannot easily be mistaken for
"object directories", either. Furthermore, its acronym ODB is already
well-known and works well as part of a function's name, like for example
`odb_has_object()`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:46:33 -07:00
Lidong Yan bfd5522e98 pack-bitmap: add load corrupt bitmap test
t5310 lacks a test to ensure git works correctly when commit bitmap
data is corrupted. So this patch add test helper in pack-bitmap.c to
list each commit bitmap position in bitmap file and `load corrupt bitmap`
test case in t/t5310 to corrupt a commit bitmap before loading it.

Signed-off-by: Lidong Yan <502024330056@smail.nju.edu.cn>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:41:54 -07:00
Lidong Yan 73bf771b95 pack-bitmap: reword comments in test_bitmap_commits()
The comment in pack-bitmap.c:test_bitmap_commits(), suggests that
we can avoid reading the commit table altogether. However, this
comment is misleading. The reason we load bitmap entries here is
because test_bitmap_commits() needs to print the commit IDs from the
bitmap, and we must read the bitmap entries to obtain those commit IDs.
So reword this comment.

Signed-off-by: Lidong Yan <502024330056@smail.nju.edu.cn>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:41:53 -07:00
Taylor Blau 3367b6657c pack-bitmap: fix memory leak if load_bitmap() failed
After going through the "failed" label, load_bitmap() will return -1,
and its caller (either prepare_bitmap_walk() or prepare_bitmap_git())
will then call free_bitmap_index().

That function would have done:

    struct stored_bitmap *sb;
    kh_foreach_value(b->bitmaps, sb {
      ewah_pool_free(sb->root);
      free(sb);
    });

, but won't since load_bitmap() already called kh_destroy_oid_map() and
NULL'd the "bitmaps" pointer from within its "failed" label. Thus if you
got part of the way through loading bitmap entries and then failed, you
would leak all of the previous entries that you were able to load
successfully.

The solution is to remove the error handling code in load_bitmap(), because
its caller will always call free_bitmap_index() in case of an error.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Lidong Yan <502024330056@smail.nju.edu.cn>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:41:53 -07:00
Junio C Hamano b0e9d25865 send-pack: clean-up even when taking an early exit
Previous commit has plugged one leak in the normal code path, but
there is an early exit that leaves without releasing any resources
acquired in the function.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 14:17:25 -07:00
Kristoffer Haugsbakk c4e9775c60 config: mention --url in the synopsis
4e51389000 (builtin/config: introduce "get" subcommand, 2024-05-06)
introduced `get` and `--url` but didn’t add `--url` to the synopsis.

Acked-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 10:28:48 -07:00
Kristoffer Haugsbakk d46f698626 config: use --value instead of value-pattern
This option was introduced in a series of commits from fe3ccc7aab (Merge
branch 'ps/config-subcommands', 2024-05-15) and deprecated
`value-pattern`.  But `value-pattern` is still used throughout the doc.

The deprecated modes have been quarantined in the “Deprecated Modes”
section.  So let’s only use `--value=<pattern>` in the rest of the doc.

Acked-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 10:28:44 -07:00
Kristoffer Haugsbakk 5ba6e6cfe3 config: document --[no-]value
These options were introduced in a series of commits from
fe3ccc7aab (Merge branch 'ps/config-subcommands', 2024-05-15).[1]
But they were not documented here.

Document this option and the negated form according to the current
convention.[2]

[1]: `--value` is a replacement for the `value-pattern`
    positional argument
[2]: https://lore.kernel.org/git/xmqqcyct1mtq.fsf@gitster.g/

Acked-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 10:28:41 -07:00
Kristoffer Haugsbakk f322f86e30 config: use --value=<pattern> consistently
This option was introduced in a series of commits from fe3ccc7aab (Merge
branch 'ps/config-subcommands', 2024-05-15).  But two styles were used
for the value provided to the option:

1. Synopsis: `--value=<value>`
2. Deprecated Modes: `--value=<pattern>`

(2) is also used in the synopsis on the command.

Use (2) consistently throughout since it’s a pattern in the general
case (`value` sounds more generic).

Acked-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 10:28:41 -07:00
Kristoffer Haugsbakk 88a4ed40c0 config: document --[no-]show-names
These options were introduced in 4e51389000 (builtin/config:
introduce "get" subcommand, 2024-05-06) but not documented here.
Use the description from the source code.

Document this option and the negated form according to the current
convention.[1]

`--show-names` is also the default when `--get-regexp` is given.  But
don’t mention it here since all the deprecated modes are quarantined in
the “Deprecated Modes” section.

[1]: https://lore.kernel.org/git/xmqqcyct1mtq.fsf@gitster.g/

Acked-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 10:28:38 -07:00
Carlo Marcelo Arenas Belón 1e77de1864 ci: update FreeBSD image to 14.3
FreeBSD 13.4 is no longer supported, and 13.5 will be the last
release from that series, so jump instead to 14.3 which should
be supported for another 10 months and will be at that point
the oldest supported release with the interim release of 15.

While at it, move some variables to the environment and make
sure to skip a git grep test that assumes glibc regex.

Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-07-01 07:46:22 -07:00
Junio C Hamano 83014dc05f The fifth batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-30 14:30:31 -07:00
Junio C Hamano e3aa0eafbd Merge branch 'jk/test-seq-format'
A test helper "test_seq" function learned the "-f <fmt>" option,
which allowed us to simplify a lot of test scripts.

* jk/test-seq-format:
  test-lib: teach test_seq the -f option
  t7422: replace confusing printf with echo
2025-06-30 14:30:31 -07:00
Junio C Hamano d2e49d2b76 Merge branch 'jc/merge-compact-summary'
"git merge/pull" has been taught the "--compact-summary" option to
use the compact-summary format, intead of diffstat, when showing
the summary of the incoming changes.

* jc/merge-compact-summary:
  merge/pull: extend merge.stat configuration variable to cover --compact-summary
  merge/pull: add the "--compact-summary" option
2025-06-30 14:30:31 -07:00
Junio C Hamano 91f10d7ca2 Merge branch 'bc/stash-export-import'
An interchange format for stash entries is defined, and subcommand
of "git stash" to import/export has been added.

* bc/stash-export-import:
  builtin/stash: provide a way to import stashes from a ref
  builtin/stash: provide a way to export stashes to a ref
  builtin/stash: factor out revision parsing into a function
  object-name: make get_oid quietly return an error
2025-06-30 14:30:31 -07:00
Junio C Hamano a013680162 Merge branch 'jc/cocci-avoid-regexp-constraint'
Avoid regexp_constraint and instead use comparison_constraint when
listing functions to exclude from application of coccinelle rules,
as spatch can be built with different regexp engine X-<.

* jc/cocci-avoid-regexp-constraint:
  cocci: matching (multiple) identifiers
2025-06-30 14:30:30 -07:00
Aditya Garg ac1a32ea52 docs: mention possible options for Proton Mail users
Proton Mail is an privacy-focused email service gaining popularity.
Unfortunately, it does not provide an SMTP server to send emails.
Proton Mail Bridge is an official solution for paid users, and for free
users, a client named git-protonmail is available. Mention the same in the
docs.

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-30 14:14:59 -07:00
Aditya Garg 95ce81f68d docs: add a paragraph explaining the `sendmailCmd` option of sendemail
`sendmailCmd` is a configuration option in `git-send-email` that allows
users to send emails using an external application that supports
sendmail-like commands. This ability has been very useful to support
proprietary email APIs without modifying the `git-send-email` codebase.
It is also useful for users who prefer to use another SMTP client
instead of the SMTP perl library used by `git-send-email`.
This commit adds a paragraph to the documentation explaining this
option.

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-30 14:14:59 -07:00
Aditya Garg 18617b2afd docs: add an OAuth2.0 credential helper for AOL accounts
Yahoo and AOL, both advertise that they support app passwords for third-party
applications. But generating app passwords for them is broken and unreliable
for quite some time now. Yahoo already had an OAuth2.0 credential helper
added in the documentation, so I thought it would be a good idea to add one
for AOL accounts as well, which is more reliable and secure.

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-30 14:14:58 -07:00
Aditya Garg a717ef18f2 docs: add outlookidfix config option to sendemail documentation
The documentation for command line option `--outlook-id-fix` is there in
the sendemail documentation, but the config option `sendemail.outlookidfix`
was missing. Add the same to the documentation.

White at it, also enclose the values `true` and `false` in backticks in
the documentation for `sendemail.mailmap`.

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-30 14:14:58 -07:00
Aditya Garg 96e5b72d1a docs: link OpenSSL's verify(1) manual page to know about -CAfile and -CApath options
The description of `--smtp-ssl-cert-path` in the git-send-email documentation
mentions consulting OpenSSL's verify(1) manual page for details about the
`-CAfile` and `-CApath` options. However, the way it was written was quite
confusing, and it didn't mention that OpenSSL's verify(1) is the manual page
to refer to.

Fix this by slightly rewording the description and also add a link to the
OpenSSL verify(1) manual page.

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-30 14:14:58 -07:00
Jakub Ječmínek 996f14c02b doc: improve formatting in branch section
The 'branch' section of the git-config documentation was missing
inline code formatting and emphasis for the <name> placeholder.

Both changes improve readability, especially when viewed online.

Signed-off-by: Jakub Ječmínek <kuba@kubajecminek.cz>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-30 11:11:36 -07:00
Carlo Marcelo Arenas Belón 78b6601ca3 daemon: correctly handle soft accept() errors in service_loop
Since df076bdbcc ([PATCH] GIT: Listen on IPv6 as well, if available.,
2005-07-23), the original error checking was included in an inner loop
unchanged, where its effect was different.

Instead of retrying, after a EINTR during accept() in the listening
socket, it will advance to the next one and try with that instead,
leaving the client waiting for another round.

Make sure to retry with the same listener socket that failed originally.

To avoid an unlikely busy loop, fallback to the old behaviour after a
couple of attempts.

Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>
Acked-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-30 08:31:06 -07:00
Jacob Keller d1c44861f9 send-pack: clean up extra_have oid array
Commit c800963578 ("fetch-pack, send-pack: clean up shallow oid
array", 2024-09-25) cleaned up the shallow oid array in cmd_send_pack,
but didn't clean up extra_have, which is still leaked at program exit.
I suspect the particular tests in t5539 don't trigger any additions to
the extra_have array, which explains why the tests can pass leak free
despite this gap.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-27 15:17:57 -07:00
Carlo Marcelo Arenas Belón 0c856224d2 daemon: remove unnecesary restriction for listener fd
Since df076bdbcc ([PATCH] GIT: Listen on IPv6 as well, if available.,
2005-07-23), any file descriptor assigned to a listening socket was
validated to be within the range to be used in an FDSET later.

6573faff34 (NO_IPV6 support for git daemon, 2005-09-28), moves to
use poll() instead of select(), that doesn't have that restriction,
so remove the original check.

Signed-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>
Acked-by: Phillip Wood <phillip.wood123@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-26 08:35:08 -07:00
Junio C Hamano cf6f63ea6b The fourth batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-25 14:07:37 -07:00
Junio C Hamano d5ee0e2961 Merge branch 'jg/mailinfo-leakfix'
Leakfix.

* jg/mailinfo-leakfix:
  mailinfo.c: fix memory leak in function handle_content_type()
2025-06-25 14:07:37 -07:00
Junio C Hamano 567dc419b2 Merge branch 'jc/diff-no-index-with-pathspec-fix'
Recent code added a direct access to the d_type member in "struct
dirent", but some platforms lack it, which has been corrected.

* jc/diff-no-index-with-pathspec-fix:
  diff-no-index: do not reference .d_type member of struct dirent
2025-06-25 14:07:36 -07:00
Junio C Hamano 4c9a5d7729 Merge branch 'ps/maintenance-ref-lock'
"git maintenance" lacked the care "git gc" had to avoid holding
onto the repository lock for too long during packing refs, which
has been remedied.

* ps/maintenance-ref-lock:
  builtin/maintenance: fix locking race when handling "gc" task
  builtin/gc: avoid global state in `gc_before_repack()`
  usage: allow dying without writing an error message
  builtin/maintenance: fix locking race with refs and reflogs tasks
  builtin/maintenance: split into foreground and background tasks
  builtin/maintenance: fix typedef for function pointers
  builtin/maintenance: extract function to run tasks
  builtin/maintenance: stop modifying global array of tasks
  builtin/maintenance: mark "--task=" and "--schedule=" as incompatible
  builtin/maintenance: centralize configuration of explicit tasks
  builtin/gc: drop redundant local variable
  builtin/gc: use designated field initializers for maintenance tasks
2025-06-25 14:07:36 -07:00
Junio C Hamano a5cc6a2bc5 Merge branch 'jc/you-still-use-whatchanged'
"git whatchanged" that is longer to type than "git log --raw"
which is its modern rough equivalent has outlived its usefulness
more than 10 years ago.  Plan to deprecate and remove it.

* jc/you-still-use-whatchanged:
  whatschanged: list it in BreakingChanges document
  whatchanged: remove when built with WITH_BREAKING_CHANGES
  whatchanged: require --i-still-use-this
  tests: prepare for a world without whatchanged
  doc: prepare for a world without whatchanged
  you-still-use-that??: help deprecating commands for removal
2025-06-25 14:07:35 -07:00
Maxim Cournoyer 1926d9b6da contrib: better support symbolic port names in git-credential-netrc
To improve support for symbolic port names in netrc files, this
changes does the following:

 - Treat symbolic port names as ports, not protocols in git-credential-netrc
 - Validate the SMTP server port provided to send-email
 - Convert the above symbolic port names to their numerical values.

Before this change, it was not possible to have a SMTP server port set
to "smtps" in a netrc file (e.g. Emacs' ~/.authinfo.gpg), as it would
be registered as a protocol and break the match for a "smtp" protocol
host, as queried for by git-send-email.

Signed-off-by: Maxim Cournoyer <maxim@guixotic.coop>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-25 09:43:59 -07:00
Maxim Cournoyer 53ca38298d contrib: warn for invalid netrc file ports in git-credential-netrc
Invalid ports were previously silently dropped; now a warning message
is produced.

Signed-off-by: Maxim Cournoyer <maxim@guixotic.coop>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-25 09:43:59 -07:00
Maxim Cournoyer 3570fba943 contrib: use a more portable shebang for git-credential-netrc
While the installed scripts have their Perl shebang set to PERL_PATH,
it is nevertheless useful to be able to run the uninstalled script for
manual tests while developing. This change makes the shebang more
portable by having the perl command looked from PATH instead of from a
fixed location.

Signed-off-by: Maxim Cournoyer <maxim@guixotic.coop>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-25 09:43:59 -07:00
Karthik Nayak 5c697f0b7d receive-pack: handle reference deletions separately
In 9d2962a7c4 (receive-pack: use batched reference updates, 2025-05-19)
we updated the 'git-receive-pack(1)' command to use batched reference
updates. One edge case which was missed during this implementation was
when a user pushes multiple branches such as:

  delete refs/heads/branch/conflict
  create refs/heads/branch

Before using batched updates, the references would be applied
sequentially and hence no conflicts would arise. With batched updates,
while the first update applies, the second fails due to D/F conflict. A
similar issue was present in 'git-fetch(1)' and was fixed by separating
out reference pruning into a separate transaction in the commit 'fetch:
use batched reference updates'. Apply a similar mechanism for
'git-receive-pack(1)' and separate out reference deletions into its own
batch.

This means 'git-receive-pack(1)' will now use up to two transactions,
whereas before using batched updates it would use _at least_ two
transactions. So using batched updates is still the better option.

Add a test to validate this behavior.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-25 08:20:27 -07:00
Karthik Nayak 15c45c7458 refs/files: skip updates with errors in batched updates
The commit 23fc8e4f61 (refs: implement batch reference update support,
2025-04-08) introduced support for batched reference updates. This
allows users to batch updates together, while allowing some of the
updates to fail.

Under the hood, batched updates use the reference transaction mechanism.
Each update which fails is marked as such. Any failed updates must be
skipped over in the rest of the code, as they wouldn't apply any more.
In two of the loops within 'files_transaction_finish()' of the files
backend, the failed updates aren't skipped over. This can cause a
SEGFAULT otherwise. Add the missing skips and a test to validate the
same.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-25 08:20:27 -07:00
Junio C Hamano f0135a9047 The third batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-24 09:48:52 -07:00
Junio C Hamano 277c3e82ed Merge branch 'ly/run-builtin-use-passed-in-repo'
Code clean-up.

* ly/run-builtin-use-passed-in-repo:
  git.c: remove the_repository dependence in run_builtin()
2025-06-24 09:48:52 -07:00
Junio C Hamano da59201dfc Merge branch 'rm/t2400-modernize'
Test clean-up.

* rm/t2400-modernize:
  t2400: replace 'test -[efd]' with 'test_path_is_*'
2025-06-24 09:48:52 -07:00
Junio C Hamano 1e60e1d6d8 Merge branch 'sa/multi-mailmap-fix'
When asking to apply mailmap to both author and committer field
while showing a commit object, the field that appears later was not
correctly parsed and replaced, which has been corrected.

* sa/multi-mailmap-fix:
  cat-file: fix mailmap application for different author and committer
2025-06-24 09:48:51 -07:00
Junio C Hamano 1f082506ba Merge branch 'jc/cg-let-bss-do-its-job'
Clarify "do not explicitly initialize to zero" rule in the
CodingGuidelines document.

* jc/cg-let-bss-do-its-job:
  CodingGuidelines: let BSS do its job
2025-06-24 09:48:50 -07:00
Junio C Hamano 2859812ca3 Merge branch 'ac/preload-index-wo-the-repository'
Code clean-up.

* ac/preload-index-wo-the-repository:
  preload-index: stop depending on 'the_repository'
  environment: remove the global variable 'core_preload_index'
2025-06-24 09:48:49 -07:00
Junio C Hamano f6e507f7cb Merge branch 'ly/prepare-show-merge-leakfix'
Leakfix.

* ly/prepare-show-merge-leakfix:
  revision: fix memory leak in prepare_show_merge()
2025-06-24 09:48:49 -07:00
Junio C Hamano 77eb1dc722 Merge branch 'kj/stash-onbranch-submodule-fix'
"git stash" recorded a wrong branch name when submodules are
present in the current checkout, which has been corrected.

* kj/stash-onbranch-submodule-fix:
  stash: fix incorrect branch name in stash message
2025-06-24 09:48:48 -07:00
Junio C Hamano 91e15c5e0c Merge branch 'ag/send-email-edit-threading-fix'
"git send-email" incremented its internal message counter when a
message was edited, which made logic that treats the first message
specially misbehave, which has been corrected.

* ag/send-email-edit-threading-fix:
  send-email: show the new message id assigned by outlook in the logs
  send-email: fix bug resulting in broken threads if a message is edited
2025-06-24 09:48:47 -07:00
Junio C Hamano d2fb103447 Merge branch 'pw/stash-p-pathspec-fixes'
"git stash -p <pathspec>" improvements.

* pw/stash-p-pathspec-fixes:
  stash: allow "git stash [<options>] --patch <pathspec>" to assume push
  stash: allow "git stash -p <pathspec>" to assume push again
2025-06-24 09:48:47 -07:00
Junio C Hamano afe1a7aee7 Merge branch 'pw/subtree-gpg-sign'
"git subtree" (in contrib/) learns to grok GPG signing its commits.

* pw/subtree-gpg-sign:
  contrib/subtree: add -S/--gpg-sign
  contrib/subtree: parse using --stuck-long
2025-06-24 09:48:46 -07:00
Jeff King b32c7ec02f test-lib: teach test_seq the -f option
The "seq" tool has a "-f" option to produce printf-style formatted
lines. Let's teach our test_seq helper the same trick. This lets us get
rid of some shell loops in test snippets (which are particularly verbose
in our test suite because we have to "|| return 1" to keep the &&-chain
going).

This converts a few call-sites I found by grepping around the test
suite. A few notes on these:

  - In "seq", the format specifier is a "%g" float. Since test_seq only
    supports integers, I've kept the more natural "%d" (which is what
    these call sites were using already).

  - Like "seq", test_seq automatically adds a newline to the specified
    format. This is what all callers are doing already except for t0021,
    but there we do not care about the exact format. We are just trying
    to printf a large number of bytes to a file. It's not worth
    complicating other callers or adding an option to avoid the newline
    in that caller.

  - Most conversions are just replacing a shell loop (which does get rid
    of an extra fork, since $() requires a subshell). In t0612 we can
    replace an awk invocation, which I think makes the end result more
    readable, as there's less quoting.

  - In t7422 we can replace one loop, but sadly we have to leave the
    loop directly above it. This is because that earlier loop wants to
    include the seq value twice in the output, which test_seq does not
    support (nor does regular seq). If you run:

      test_seq -f "foo-%d %d" 10

    the second "%d" will always be the empty string. You might naively
    think that test_seq could add some extra arguments, like:

      # 3 ought to be enough for anyone...
      printf "$fmt\n" "$i "$i" $i"

    but that just triggers printf to format multiple lines, one per
    extra set of arguments.

    So we'd have to actually parse the format string, figure out how
    many "%" placeholders are there, and then feed it that many
    instances of the sequence number. The complexity isn't worth it.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-24 06:34:25 -07:00
Jacob Keller ca62f524c1 submodule: look up remotes by URL first
The get_default_remote_submodule() function performs a lookup to find
the appropriate remote to use within a submodule. The function first
checks to see if it can find the remote for the current branch. If this
fails, it then checks to see if there is exactly one remote. It will use
this, before finally falling back to "origin" as the default.

If a user happens to rename their default remote from origin, either
manually or by setting something like clone.defaultRemoteName, this
fallback will not work.

In such cases, the submodule logic will try to use a non-existent
remote. This usually manifests as a failure to trigger the submodule
update.

The parent project already knows and stores the submodule URL in either
.gitmodules or its .git/config.

Add a new repo_remote_from_url() helper which will iterate over all the
remotes in a repository and return the first remote which has a matching
URL.

Refactor get_default_remote_submodule to find the submodule and get its
URL. If a valid URL exists, first try to obtain a remote using the new
repo_remote_from_url(). Fall back to the repo_default_remote()
otherwise.

The fallback logic is kept in case for some reason the user has manually
changed the URL within the submodule. Additionally, we still try to use
a remote rather than directly passing the URL in the
fetch_in_submodule() logic. This ensures that an update will properly
update the remote refs within the submodule as expected, rather than
just fetching into FETCH_HEAD.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-23 16:38:57 -07:00
Jacob Keller fedfb0735b submodule: move get_default_remote_submodule()
A future refactor got get_default_remote_submodule() is going to depend on
resolve_relative_url(). That function depends on get_default_remote().

Move get_default_remote_submodule() after resolve_relative_url() first
to make the additional functionality easier to review.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-23 16:38:57 -07:00
Jacob Keller e759275c8f submodule--helper: improve logic for fallback remote name
The repo_get_default_remote() function in submodule--helper currently
tries to figure out the proper remote name to use for a submodule based
on a few factors.

First, it tries to find the remote for the currently checked out branch.
This works if the submodule is configured to checkout to a branch
instead of a detached HEAD state.

In the detached HEAD state, the code calls back to using "origin", on
the assumption that this is the default remote name. Some users may
change this, such as by setting clone.defaultRemoteName, or by changing
the remote name manually within the submodule repository.

As a first step to improving this situation, refactor to reuse the logic
from remotes_remote_for_branch(). This function uses the remote from the
branch if it has one. If it doesn't then it checks to see if there is
exactly one remote. It uses this remote first before attempting to fall
back to "origin".

To allow using this helper function, introduce a repo_default_remote()
helper to remote.c which takes a repository structure. This helper will
load the remote configuration and get the "HEAD" branch. Then it will
call remotes_remote_for_branch to find the default remote.

Replace calls of repo_get_default_remote() with the calls to this new
function. To maintain consistency with the existing callers, continue
copying the returned string with xstrdup.

This isn't a perfect solution for users who change remote names, but it
should help in cases where the remote name is changed but users haven't
added any additional remotes.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-23 16:38:57 -07:00
Jacob Keller f8542961da remote: remove the_repository from some functions
The remotes_remote_get_1 (and its caller, remotes_remote_get, have an
implicit dependency on the_repository due to calling
read_branches_file() and read_remotes_file(), both of which use
the_repository. The branch_get() function calls set_merge() which has an
implicit dependency on the_repository as well.

Because of this use of the_repository, the helper functions cannot be
used in code paths which operate on other repositories. A future
refactor of the submodule--helper will want to make use of some of these
functions.

Refactor to break the dependency by passing struct repository *repo
instead of struct remote_state *remote_state in a few places.

The public callers and many other helper functions still depend on
the_repository. A repo-aware function will be exposed in a following
change for git submodule--helper.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-23 16:38:56 -07:00
Jacob Keller 059268fd05 dir: move starts_with_dot(_dot)_slash to dir.h
Both submodule--helper.c and submodule-config.c have an implementation
of starts_with_dot_slash and starts_with_dot_dot_slash. The dir.h header
has starts_with_dot(_dot)_slash_native, which sets PATH_MATCH_NATIVE.

Move the helpers to dir.h as static inlines. I thought about renaming
them to postfix with _platform but that felt too long and ugly. On the
other hand it might be slightly confusing with _native.

This simplifies a submodule refactor which wants to use the helpers
earlier in the submodule--helper.c file.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-23 16:38:56 -07:00
Jacob Keller 2084f119b4 remote: fix tear down of struct remote
The remote_clear() function failed to free the remote->push and
remote->fetch refspec fields.

This should be caught by the leak sanitizer. However, for callers which
use ``the_repository``, the values never go out of scope and the
sanitizer doesn't complain.

A future change is going to add a caller of read_config() for a
submodule repository structure, which would result in the leak sanitizer
complaining.

Fix remote_clear(), updating it to properly call refspec_clear() for
both the push and fetch members.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-23 16:38:56 -07:00
Jacob Keller f62dcc7f30 remote: remove branch->merge_name and fix branch_release()
The branch structure has both branch->merge_name and branch->merge for
tracking the merge information. The former is allocated by add_merge()
and stores the names read from the configuration file. The latter is
allocated by set_merge() which is called by branch_get() when an
external caller requests a branch.

This leads to the confusing situation where branch->merge_nr tracks both
the size of branch->merge (once its allocated) and branch->merge_name.
The branch_release() function incorrectly assumes that branch->merge is
always set when branch->merge_nr is non-zero, and can potentially crash
if read_config() is called without branch_get() being called on every
branch.

In addition, branch_release() fails to free some of the memory
associated with the structure including:

 * Failure to free the refspec_item containers in branch->merge[i]
 * Failure to free the strings in branch->merge_name[i]
 * Failure to free the branch->merge_name parent array.

The set_merge() function sets branch->merge_nr to 0 when there is no
valid remote_name, to avoid external callers seeing a non-zero merge_nr
but a NULL merge array. This results in failure to release most of the
merge data as well.

These issues could be fixed directly, and indeed I initially proposed
such a change at [1] in the past. While this works, there was some
confusion during review because of the inconsistencies.

Instead, its time to clean up the situation properly. Remove
branch->merge_name entirely. Instead, allocate branch->merge earlier
within add_merge() instead of within set_merge(). Instead of having
set_merge() copy from merge_name[i] to merge[i]->src, just have
add_merge() directly initialize merge[i]->src.

Modify the add_merge() to call xstrdup() itself, instead of having
the caller of add_merge() do so. This makes it more obvious which code
owns the memory.

Update all callers which use branch->merge_name[i] to use
branch->merge[i]->src instead.

Add a merge_clear() function which properly releases all of the
merge-related memory, and which sets branch->merge_nr to zero. Use this
both in branch_release() and in set_merge(), fixing the leak when
set_merge() finds no valid remote_name.

Add a set_merge variable to the branch structure, which indicates
whether set_merge() has been called. This replaces the previous use of a
NULL check against the branch->merge array.

With these changes, the merge array is always allocated when merge_nr is
non-zero.

This use of refspec_item to store the names should be safe. External
callers should be using branch_get() to obtain a pointer to the branch,
which will call set_merge(), and the callers internal to remote.c
already handle the partially initialized refpsec_item structure safely.

This end result is cleaner, and avoids duplicating the merge names
twice.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
Link: [1] https://lore.kernel.org/git/20250617-jk-submodule-helper-use-url-v2-1-04cbb003177d@gmail.com/
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-23 16:38:55 -07:00
Taylor Blau 5ee86c273b repack: exclude cruft pack(s) from the MIDX where possible
In ddee3703b3 (builtin/repack.c: add cruft packs to MIDX during
geometric repack, 2022-05-20), repack began adding cruft pack(s) to the
MIDX with '--write-midx' to ensure that the resulting MIDX was always
closed under reachability in order to generate reachability bitmaps.

While the previous patch added the '--stdin-packs=follow' option to
pack-objects, it is not yet on by default. Given that, suppose you have
a once-unreachable object packed in a cruft pack, which later becomes
reachable from one or more objects in a geometrically repacked pack.
That once-unreachable object *won't* appear in the new pack, since the
cruft pack was not specified as included or excluded when the
geometrically repacked pack was created with 'pack-objects
--stdin-packs' (*not* '--stdin-packs=follow', which is not on). If that
new pack is included in a MIDX without the cruft pack, then trying to
generate bitmaps for that MIDX may fail. This happens when the bitmap
selection process picks one or more commits which reach the
once-unreachable objects.

To mitigate this failure mode, commit ddee3703b3 ensures that the MIDX
will be closed under reachability by including cruft pack(s). If cruft
pack(s) were not included, we would fail to generate a MIDX bitmap. But
ddee3703b3 alludes to the fact that this is sub-optimal by saying

    [...] it's desirable to avoid including cruft packs in the MIDX
    because it causes the MIDX to store a bunch of objects which are
    likely to get thrown away.

, which is true, but hides an even larger problem. If repositories
rarely prune their unreachable objects and/or have many of them, the
MIDX must keep track of a large number of objects which bloats the MIDX
and slows down object lookup.

This is doubly unfortunate because the vast majority of objects in cruft
pack(s) are unlikely to be read. But any object lookups that go through
the MIDX must binary search over them anyway, slowing down object
lookups using the MIDX.

This patch causes geometrically-repacked packs to contain a copy of any
once-unreachable object(s) with 'git pack-objects --stdin-packs=follow',
allowing us to avoid including any cruft packs in the MIDX. This is
because a sequence of geometrically-repacked packs that were all
generated with '--stdin-packs=follow' are guaranteed to have their union
be closed under reachability.

Note that you cannot guarantee that a collection of packs is closed
under reachability if not all of them were generated with "following" as
above. One tell-tale sign that not all geometrically-repacked packs in
the MIDX were generated with "following" is to see if there is a pack in
the existing MIDX that is not going to be somehow represented (either
verbatim or as part of a geometric rollup) in the new MIDX.

If there is, then starting to generate packs with "following" during
geometric repacking won't work, since it's open to the same race as
described above.

But if you're starting from scratch (e.g., building the first MIDX after
an all-into-one '--cruft' repack), then you can guarantee that the union
of subsequently generated packs from geometric repacking *is* closed
under reachability.

(One exception here is when "starting from scratch" results in a noop
repack, e.g., because the non-cruft pack(s) in a repository already form
a geometric progression. Since we can't tell whether or not those were
generated with '--stdin-packs=follow', they may depend on
once-unreachable objects, so we have to include the cruft pack in the
MIDX in this case.)

Detect when this is the case and avoid including cruft packs in the MIDX
where possible. The existing behavior remains the default, and the new
behavior is available with the config 'repack.midxMustIncludeCruft' set
to 'false'.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-23 15:41:38 -07:00
Taylor Blau cd846bacc7 pack-objects: introduce '--stdin-packs=follow'
When invoked with '--stdin-packs', pack-objects will generate a pack
which contains the objects found in the "included" packs, less any
objects from "excluded" packs.

Packs that exist in the repository but weren't specified as either
included or excluded are in practice treated like the latter, at least
in the sense that pack-objects won't include objects from those packs.
This behavior forces us to include any cruft pack(s) in a repository's
multi-pack index for the reasons described in ddee3703b3
(builtin/repack.c: add cruft packs to MIDX during geometric repack,
2022-05-20).

The full details are in ddee3703b3, but the gist is if you
have a once-unreachable object in a cruft pack which later becomes
reachable via one or more commits in a pack generated with
'--stdin-packs', you *have* to include that object in the MIDX via the
copy in the cruft pack, otherwise we cannot generate reachability
bitmaps for any commits which reach that object.

Note that the traversal here is best-effort, similar to the existing
traversal which provides name-hash hints. This means that the object
traversal may hand us back a blob that does not actually exist. We
*won't* see missing trees/commits with 'ignore_missing_links' because:

 - missing commit parents are discarded at the commit traversal stage by
   revision.c::process_parents()

 - missing tag objects are discarded by revision.c::handle_commit()

 - missing tree objects are discarded by the list-objects code in
   list-objects.c::process_tree()

But we have to handle potentially-missing blobs specially by making a
separate check to ensure they exist in the repository. Failing to do so
would mean that we'd add an object to the packing list which doesn't
actually exist, rendering us unable to write out the pack.

This prepares us for new repacking behavior which will "resurrect"
objects found in cruft or otherwise unspecified packs when generating
new packs. In the context of geometric repacking, this may be used to
maintain a sequence of geometrically-repacked packs, the union of which
is closed under reachability, even in the case described earlier.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-23 15:41:37 -07:00
Taylor Blau 63195f013b pack-objects: swap 'show_{object,commit}_pack_hint'
show_commit_pack_hint() has heretofore been a noop, so its position
within its compilation unit only needs to appear before its first use.

But the following commit will sometimes have `show_commit_pack_hint()`
call `show_object_pack_hint()`, so reorder the former to appear after
the latter to minimize the code movement in that patch.

Suggested-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-23 15:41:37 -07:00
Taylor Blau 8ed5d87bdd pack-objects: fix typo in 'show_object_pack_hint()'
Noticed-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-23 15:41:37 -07:00
Taylor Blau d6220cce6b pack-objects: perform name-hash traversal for unpacked objects
With '--unpacked', pack-objects adds loose objects (which don't appear
in any of the excluded packs from '--stdin-packs') to the output pack
without considering them as reachability tips for the name-hash
traversal.

This was an oversight in the original implementation of '--stdin-packs',
since the code which enumerates and adds loose objects to the output
pack (`add_unreachable_loose_objects()`) did not have access to the
'rev_info' struct found in `read_packs_list_from_stdin()`.

Excluding unpacked objects from that traversal doesn't affect the
correctness of the resulting pack, but it does make it harder to
discover good deltas for loose objects.

Now that the 'rev_info' struct is declared outside of
`read_packs_list_from_stdin()`, we can pass it to
`add_objects_in_unpacked_packs()` and add any loose objects as tips to
the above-mentioned traversal, in theory producing slightly tighter
packs as a result.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-23 15:41:36 -07:00
Taylor Blau 97ec43247c pack-objects: declare 'rev_info' for '--stdin-packs' earlier
Once 'read_packs_list_from_stdin()' has called for_each_object_in_pack()
on each of the input packs, we do a reachability traversal to discover
names for any objects we picked up so we can generate name hash values
and hopefully get higher quality deltas as a result.

A future commit will change the purpose of this reachability traversal
to find and pack objects which are reachable from commits in the input
packs, but are packed in an unknown (not included nor excluded) pack.

Extract the code which initializes and performs the reachability
traversal to take place in the caller, not the callee, which prepares us
to share this code for the '--unpacked' case (see the function
add_unreachable_loose_objects() for more details).

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-23 15:41:36 -07:00
Taylor Blau 67e1a7827b pack-objects: factor out handling '--stdin-packs'
At the bottom of cmd_pack_objects() we check which mode the command is
running in (e.g., generating a cruft pack, handling '--stdin-packs',
using the internal rev-list, etc.) and handle the mode appropriately.

The '--stdin-packs' case is handled inline (dating back to its
introduction in 339bce27f4 (builtin/pack-objects.c: add '--stdin-packs'
option, 2021-02-22)) since it is relatively short. Extract the body of
"if (stdin_packs)" into its own function to prepare for the
implementation to become lengthier in a following commit.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-23 15:41:36 -07:00
Taylor Blau 9809d4ae9f pack-objects: limit scope in 'add_object_entry_from_pack()'
In add_object_entry_from_pack() we declare 'revs' (given to us through
the miscellaneous context argument) earlier in the "if (p)" conditional
than is necessary.  Move it down as far as it can go to reduce its
scope.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-23 15:41:36 -07:00
Taylor Blau 798ddd947f pack-objects: use standard option incompatibility functions
pack-objects has a handful of explicit checks for pairs of command-line
options which are mutually incompatible. Many of these pre-date
a699367bb8 (i18n: factorize more 'incompatible options' messages,
2022-01-31).

Convert the explicit checks into die_for_incompatible_opt2() calls,
which simplifies the implementation and standardizes pack-objects'
output when given incompatible options (e.g., --stdin-packs with
--filter gives different output than --keep-unreachable with
--unpack-unreachable).

There is one minor piece of test fallout in t5331 that expects the old
format, which has been corrected.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-23 15:41:35 -07:00
Jeff King 1129596dc8 t7422: replace confusing printf with echo
While looping over a counter "i", we do:

  printf "[submodule \"sm-$i\"]\npath = recursive-submodule-path-$i\n" "$i"

So we are passing "$i" as an argument to be filled in, but there is no
"%" placeholder in the format string, which is a bit confusing to read.

We could switch both instances of "$i" to "%d" (and pass $i twice). But
that makes the line even longer. Let's just keep interpolating the value
in the string, and drop the confusing extra "$i" argument.

And since we are not using any printf specifiers at all, it becomes
clear that we can swap it out for echo. We do use a "\n" in the middle
of the string, but breaking this into two separate echo statements
actually makes it easier to read.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-23 10:30:40 -07:00
Junio C Hamano 819d3a55fc coccicheck: fail "make" when it fails
With "make coccicheck", we generate contrib/coccinelle/*.cocci.patch
files that contain changes suggested by semantic patches, but "make"
succeeds.  Admittedly, not many developers may run "make coccicheck"
in the first place, but it makes it harder to notice when they do
run it after they introduced an iffy piece of code.

Check that the resulting cocci.patch files are all empty.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-23 09:33:31 -07:00
Junio C Hamano f2ad545813 cocci: matching (multiple) identifiers
"make coccicheck" seems to work OK at GitHub CI using

    $ spatch --version
    spatch version 1.1.1 compiled with OCaml version 4.13.1
    OCaml scripting support: yes
    Python scripting support: yes
    Syntax of regular expressions: PCRE

but not with

    $ spatch --version
    spatch version 1.3 compiled with OCaml version 5.3.0
    OCaml scripting support: yes
    Python scripting support: yes
    Syntax of regular expressions: Str

Judging from https://ocaml.org/manual/5.3/api/Str.html, I suspect
that this probably is caused by the distinction between BRE vs PCRE.
As there is no reasonably clean way to write the multiple choice
matches portably between these two pattern languages, let's stop
using regexp_constraint and use compare_constraint instead when
listing the function names to exclude.

There are other uses of "!~" but they all want to match a single
simple token, that should work fine either with BRE or PCRE.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-20 15:41:47 -07:00
Jörg Thalheim d30bf28d09 imap-send: improve error messages with configuration hints
Replace basic error messages with more helpful ones that guide users
on how to resolve configuration issues. When imap.host or imap.folder
are missing, provide the exact git config commands needed to fix the
problem, along with examples of typical values.

Use the advise() API to display hints in a multi-line format with
proper "hint:" prefixes for each line.

Signed-off-by: Jörg Thalheim <joerg@thalheim.io>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-20 14:14:44 -07:00
Jörg Thalheim 1d304ce130 imap-send: fix confusing 'store' terminology in error message
The error message 'no imap store specified' is misleading because
it refers to 'store' when the actual missing configuration is
'imap.folder'. Update the message to use the correct terminology
that matches the configuration variable name.

This reduces confusion for users who might otherwise look for
non-existent 'imap.store' configuration when they see this error.

Signed-off-by: Jörg Thalheim <joerg@thalheim.io>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-20 14:14:43 -07:00
Junio C Hamano 0ed16dc3c4 Merge branch 'ag/imap-send-resurrection' into jt/imap-send-message-fix
* ag/imap-send-resurrection:
  imap-send: fix minor mistakes in the logs
  imap-send: display the destination mailbox when sending a message
  imap-send: display port alongwith host when git credential is invoked
  imap-send: add ability to list the available folders
  imap-send: enable specifying the folder using the command line
  imap-send: add PLAIN authentication method to OpenSSL
  imap-send: add support for OAuth2.0 authentication
  imap-send: gracefully fail if CRAM-MD5 authentication is requested without OpenSSL
  imap-send: fix memory leak in case auth_cram_md5 fails
  imap-send: fix bug causing cfg->folder being set to NULL
2025-06-20 08:29:34 -07:00
Aditya Garg 5ec81b33b0 imap-send: fix minor mistakes in the logs
Some minor mistakes have been found in the logs. Most of them include
error messages starting with a capital letter, and ending with a period.
Abbreviations like "IMAP" and "OK" should also be in uppercase. Another
mistake was that the error message showing unknown authentication
mechanism used was displaying the host rather than the mechanism in the
logs. Fix them.

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-20 08:11:18 -07:00
Aditya Garg bf22c370b9 imap-send: display the destination mailbox when sending a message
Whenever we sent a message using the `imap-send` command, it would
display a log showing the number of messages which are to be sent.
For example:

    sending 1 message
     100% (1/1) done

This had been made more informative by adding the name of the destination
folder as well:

    Sending 1 message to Drafts folder...
     100% (1/1) done

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-20 08:11:17 -07:00
Aditya Garg 2dacd35731 imap-send: display port alongwith host when git credential is invoked
When requesting for passsword, git credential helper used to display
only the host name. For example:

    Password for 'imaps://gargaditya08%40live.com@outlook.office365.com':

Now, it will display the port along with the host name:

    Password for 'imaps://gargaditya08%40live.com@outlook.office365.com:993':

This has been done to make credential helpers more specific for ports.
Also, this behaviour will also mimic git send-email, which displays
the port along with the host name when requesting for a password.

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-20 08:11:17 -07:00
Aditya Garg 067a91b03f imap-send: add ability to list the available folders
Various IMAP servers have different ways to name common folders.
For example, the folder where all deleted messages are stored is often
named "[Gmail]/Trash" on Gmail servers, and "Deleted" on Outlook.
Similarly, the Drafts folder is simply named "Drafts" on Outlook, but
on Gmail it is named "[Gmail]/Drafts".

This commit adds a `--list` command to the `imap-send` tool that lists
the available folders on the IMAP server, allowing users to see
which folders are available and how they are named. A sample output
looks like this when run against a Gmail server:

    Fetching the list of available folders...
    * LIST (\HasNoChildren) "/" "INBOX"
    * LIST (\HasChildren \Noselect) "/" "[Gmail]"
    * LIST (\All \HasNoChildren) "/" "[Gmail]/All Mail"
    * LIST (\Drafts \HasNoChildren) "/" "[Gmail]/Drafts"
    * LIST (\HasNoChildren \Important) "/" "[Gmail]/Important"
    * LIST (\HasNoChildren \Sent) "/" "[Gmail]/Sent Mail"
    * LIST (\HasNoChildren \Junk) "/" "[Gmail]/Spam"
    * LIST (\Flagged \HasNoChildren) "/" "[Gmail]/Starred"
    * LIST (\HasNoChildren \Trash) "/" "[Gmail]/Trash"

For OpenSSL, this is achived by running the 'IMAP LIST' command and
parsing the response. This command is specified in RFC6154:
https://datatracker.ietf.org/doc/html/rfc6154#section-5.1

For libcurl, the example code published in the libcurl documentation
is used to implement this functionality:
https://curl.se/libcurl/c/imap-list.html

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-20 08:11:17 -07:00
Aditya Garg 3168514e6b imap-send: enable specifying the folder using the command line
Some users may very often want to imap-send messages to a folder
other than the default set in the config. Add a command line
argument for the same.

While at it, fix minor mark-up inconsistencies in the existing
documentation text.

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-20 08:11:17 -07:00
Aditya Garg ea8681e3a4 imap-send: add PLAIN authentication method to OpenSSL
The current implementation for PLAIN in imap-send works just fine
if using curl, but if attempted to use for OpenSSL, it is treated
as an invalid mechanism. The default implementation for OpenSSL is
IMAP LOGIN command rather than AUTH PLAIN. Since AUTH PLAIN is
still used today by many email providers in form of app passwords,
lets add an implementation that can use AUTH PLAIN if specified.

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-20 08:11:17 -07:00
Aditya Garg 103d7b12b7 imap-send: add support for OAuth2.0 authentication
OAuth2.0 is a new way of authentication supported by various email providers
these days. OAUTHBEARER and XOAUTH2 are the two most common mechanisms used
for OAuth2.0. OAUTHBEARER is described in RFC5801[1] and RFC7628[2], whereas
XOAUTH2 is Google's proprietary mechanism (See [3]).

[1]: https://datatracker.ietf.org/doc/html/rfc5801
[2]: https://datatracker.ietf.org/doc/html/rfc7628
[3]: https://developers.google.com/workspace/gmail/imap/xoauth2-protocol#initial_client_response

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-20 08:11:16 -07:00
Aditya Garg b9e766604d imap-send: gracefully fail if CRAM-MD5 authentication is requested without OpenSSL
Unlike PLAIN, XOAUTH2 and OAUTHBEARER, CRAM-MD5 authentication is not
supported by libcurl and requires OpenSSL. If the user tries to use
CRAM-MD5 authentication without OpenSSL, the previous behaviour was to
attempt to authenticate and fail with a die(error). Handle this in a
better way by first checking if OpenSSL is available and then attempting
to authenticate. If OpenSSL is not available, print an error message and
exit gracefully.

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-20 08:11:16 -07:00
Aditya Garg ac4e02c503 imap-send: fix memory leak in case auth_cram_md5 fails
This patch fixes a memory leak by running free(response) in case
auth_cram_md5 fails.

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-20 08:11:16 -07:00
Aditya Garg 44ba4b0bbb imap-send: fix bug causing cfg->folder being set to NULL
6d1f198f34 (imap-send: fix leaking memory in `imap_server_conf`, 2024-06-07)
resulted a change in static int git_imap_config which resulted in cfg->folder
being incorrectly set to NULL in case imap.user, imap.pass, imap.tunnel and
imap.authmethod were defined. Because of this, since Git 2.46.0,
git-imap-send is not usable at all. The bug seems to have been unnoticed for
a long time, likely due to better options like git-send-email.

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-20 08:11:16 -07:00
Junio C Hamano cb3b40381e The second batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-18 13:53:36 -07:00
Junio C Hamano e363d5f226 Merge branch 'rj/meson-tap-parse-fixup'
An earlier test update incorrectly lost three prerequisites on
macOS, which has been corrected.

* rj/meson-tap-parse-fixup:
  test-lib: add missing prerequisites for Darwin
2025-06-18 13:53:36 -07:00
Junio C Hamano 92daf08c84 Merge branch 'ly/submodule-update-failure-leakfix'
A memory leak on an error code path has been plugged.

* ly/submodule-update-failure-leakfix:
  builtin/submodule--helper: fix leak when remote_submodule_branch() failed
2025-06-18 13:53:36 -07:00
Junio C Hamano a6cdbc8f8a Merge branch 'jm/bundle-uri-debug-output-to-fp'
Code clean-up.

* jm/bundle-uri-debug-output-to-fp:
  bundle-uri: send debug output to given FILE * stream
2025-06-18 13:53:35 -07:00
Junio C Hamano aa6ab0323f Merge branch 'bs/solaris-10-and-11'
Add settings for Solaris 10 & 11.

* bs/solaris-10-and-11:
  config.mak.uname: update settings for Solaris 10 and 11
2025-06-18 13:53:35 -07:00
Junio C Hamano 19612d0e46 Merge branch 'jw/doc-txt-to-adoc-refs'
Some leftover references to documentation source files that no
longer exist, due to recent ".txt" -> ".adoc" renaming, have been
corrected.

* jw/doc-txt-to-adoc-refs:
  doc: update references to renamed AsciiDoc files
2025-06-18 13:53:35 -07:00
Junio C Hamano 617318cbce Merge branch 'ma/doc-diff-cc-headers'
Doc mark-up update.

* ma/doc-diff-cc-headers:
  diff-generate-patch.adoc: drop spurious backticks
2025-06-18 13:53:34 -07:00
Junio C Hamano f1af195690 Merge branch 'ly/pack-bitmap-root-leakfix'
Memleak fix on an error code path.

* ly/pack-bitmap-root-leakfix:
  pack-bitmap: remove checks before bitmap_free
2025-06-18 13:53:34 -07:00
Junio C Hamano 0d0d56bca4 Merge branch 'ly/commit-buffer-reencode-leakfix'
Leakfix.

* ly/commit-buffer-reencode-leakfix:
  repo_logmsg_reencode: fix memory leak when use repo_logmsg_reencode ()
2025-06-18 13:53:34 -07:00
Junio C Hamano f1a1d79fcf Merge branch 'cf/guideline-documenting-config-vars'
CodingGuidelines update.

* cf/guideline-documenting-config-vars:
  CodingGuidelines: document formatting of similar config variables.
2025-06-18 13:53:33 -07:00
Collin Funk ff67eea529 CodingGuidelines: document formatting of similar config variables.
Document that related `git config` variables should be placed
one-per-line instead of separated by commas.

Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Collin Funk <collin.funk1@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-18 13:48:11 -07:00
Junio C Hamano d094e05ea5 diff-no-index: do not reference .d_type member of struct dirent
Some platforms like AIX lack .d_type member in "struct dirent"; use
the DTYPE(e) macro instead of a direct reference to e->d_type and
when it yields DT_UNKNOWN, find the real type with get_dtype().

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-18 13:05:29 -07:00
Junio C Hamano f9aa0eedb3 Start 2.51 cycle, the first batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-17 10:44:42 -07:00
Junio C Hamano b1dc2e796e Merge branch 'ps/meson-tap-parse'
Meson-based build/test framework now understands TAP output
generated by our tests.

* ps/meson-tap-parse:
  meson: parse TAP output generated by our tests
  meson: introduce kwargs variable for tests
  test-lib: fail on unexpectedly passing tests
  t7815: fix unexpectedly passing test on macOS
  t/test-lib: fix TAP format for BASH_XTRACEFD warning
  t/test-lib: don't print shell traces to stdout
  t983*: use prereq to check for Python-specific git-p4(1) support
  t9822: use prereq to check for ISO-8859-1 support
  t: silence output from `test_create_repo()`
  t: stop announcing prereqs
2025-06-17 10:44:42 -07:00
Junio C Hamano 2024ab3d97 Merge branch 'jk/diff-no-index-with-pathspec'
"git diff --no-index dirA dirB" can limit the comparison with
pathspec at the end of the command line, just like normal "git
diff".

* jk/diff-no-index-with-pathspec:
  diff --no-index: support limiting by pathspec
  pathspec: add flag to indicate operation without repository
  pathspec: add match_leading_pathspec variant
2025-06-17 10:44:42 -07:00
Junio C Hamano 5e22d03832 Merge branch 'ly/fetch-pack-leakfix'
A memory-leak in an error code path has been plugged.

* ly/fetch-pack-leakfix:
  builtin/fetch-pack: cleanup before return error
2025-06-17 10:44:41 -07:00
Junio C Hamano b5a135b1f7 Merge branch 'ly/commit-graph-graph-write-leakfix'
A memory-leak in an error code path has been plugged.

* ly/commit-graph-graph-write-leakfix:
  commit-graph: fix start_delayed_progress() leak
2025-06-17 10:44:41 -07:00
Junio C Hamano 1f622bb0ab Merge branch 'ly/do-not-localize-bug-messages'
Code clean-up.

* ly/do-not-localize-bug-messages:
  BUG(): remove leading underscore of the format string
2025-06-17 10:44:40 -07:00
Junio C Hamano 870a0421c4 Merge branch 'ly/sequencer-update-squash-is-fixup-only'
Code clean-up.

* ly/sequencer-update-squash-is-fixup-only:
  sequencer: replace error() with BUG() in update_squash_messages ()
2025-06-17 10:44:40 -07:00
Junio C Hamano 4fd5b1ddc7 Merge branch 'vd/cat-file-objectmode-update'
"git cat-file --batch" learns to understand %(objectmode) atom to
allow the caller to tell missing objects (due to repository
corruption) and submodules (whose commit objects are OK to be
missing) apart.

* vd/cat-file-objectmode-update:
  cat-file.c: add batch handling for submodules
  cat-file: add %(objectmode) atom
  t1006: update 'run_tests' to test generic object specifiers
2025-06-17 10:44:39 -07:00
Junio C Hamano 5b124e7c16 Merge branch 'ag/send-email-docs'
Documentation for "git send-email" has been updated with a bit more
credential helper and OAuth information.

* ag/send-email-docs:
  docs: make the purpose of using app password for Gmail more clear in send-email
  docs: remove credential helper links for emails from gitcredentials
  docs: improve formatting in git-send-email documentation
  docs: add credential helper for yahoo and link Google's sendgmail tool
2025-06-17 10:44:39 -07:00
Junio C Hamano 01148cafa4 Merge branch 'rc/userdiff-r'
Userdiff patterns for the R language.

* rc/userdiff-r:
  userdiff: add support for R programming language
2025-06-17 10:44:39 -07:00
Junio C Hamano 88134a8417 Merge branch 'ds/path-walk-2'
"git pack-objects" learns to find delta bases from blobs at the
same path, using the --path-walk API.

* ds/path-walk-2:
  pack-objects: allow --shallow and --path-walk
  path-walk: add new 'edge_aggressive' option
  pack-objects: thread the path-based compression
  pack-objects: refactor path-walk delta phase
  scalar: enable path-walk during push via config
  pack-objects: enable --path-walk via config
  repack: add --path-walk option
  t5538: add tests to confirm deltas in shallow pushes
  pack-objects: introduce GIT_TEST_PACK_PATH_WALK
  p5313: add performance tests for --path-walk
  pack-objects: update usage to match docs
  pack-objects: add --path-walk option
  pack-objects: extract should_attempt_deltas()
2025-06-17 10:44:38 -07:00
Junio C Hamano 60f9bc3e30 Merge branch 'lo/my-first-ow-doc-update'
Doc update to the more recent world order.

* lo/my-first-ow-doc-update:
  MyFirstContribution: add walken.c to meson.build
  MyFirstContribution: use struct repository in examples
2025-06-17 10:44:38 -07:00
Rodrigo Michelassi 855cfc65ae t2400: replace 'test -[efd]' with 'test_path_is_*'
'test_path_is_file', 'test_path_is_dir' and 'test_file_is_missing'
are test helpers used in Git's development, that emit useful
diagnostic information when they detect a failing condition, while
test -[efd] does not.

Replace the basic shell commands 'test -f', 'test -d' and 'test -e',
with these test helpers.

Co-authored-by: Isabella Caselli <icaselli@usp.br>
Signed-off-by: Isabella Caselli <icaselli@usp.br>
Signed-off-by: Rodrigo Michelassi <rodmichelassi@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-16 21:49:05 -07:00
Lidong Yan 2939494284 git.c: remove the_repository dependence in run_builtin()
run_builtin() takes a repo parameter, so the use of the_repository
is no longer necessary. Removed the usage of the_repository.

Signed-off-by: Lidong Yan <502024330056@smail.nju.edu.cn>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-16 08:17:12 -07:00
Junio C Hamano d82adb61ba Git 2.50.1 2025-06-15 21:57:08 -07:00
Junio C Hamano e1775c0646 Sync with 2.49.1 2025-06-15 21:54:23 -07:00
Junio C Hamano 16bd9f20a4 Git 2.50
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-15 21:17:21 -07:00
Jinyao Guo ff73f375bb mailinfo.c: fix memory leak in function handle_content_type()
The function handle_content_type allocates memory for boundary
using xmalloc(sizeof(struct strbuf)). If (++mi->content_top >=
&mi->content[MAX_BOUNDARIES]) is true, the function returns
without freeing boundary.

Signed-off-by: Jinyao Guo <guo846@purdue.edu>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-14 09:42:14 -07:00
Junio C Hamano f1ca98f609 Hopefully final bits before 2.50
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-13 13:29:15 -07:00
Junio C Hamano 7bd3e5397d Merge branch 'js/github-ci-win-coverity-fix'
Fixes for GitHub Actions Coverity job.

* js/github-ci-win-coverity-fix:
  ci(coverity): output the build log upon error
  ci(coverity): fix building on Windows
2025-06-13 13:29:15 -07:00
Junio C Hamano e1f335f3d4 Merge branch 'ss/revert-builtin-bswap-stuff'
Revert a botched bswap.h change that broke ntohll() functions on
big-endian systems with __builtin_bswap32/64().

* ss/revert-builtin-bswap-stuff:
  Revert "bswap.h: add support for built-in bswap functions"
2025-06-13 13:29:14 -07:00
Junio C Hamano f2a6a1e596 Merge branch 'jc/sed-build-fixes'
Build fix.

* jc/sed-build-fixes:
  build: sed portability fixes
2025-06-13 13:29:14 -07:00
Junio C Hamano c8b4805897 merge/pull: extend merge.stat configuration variable to cover --compact-summary
Existing `merge.stat` configuration variable is a Boolean that
defaults to `true` to control `git merge --[no-]stat` behaviour.

Extend it to be "Boolean or text", that takes false, true, or
"compact", with the last one triggering the --compact-summary option
introduced earlier.  Any other values are taken as the same as true,
instead of signaling an error---it is not a grave enough offence to
stop their merge.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-13 11:54:14 -07:00
Junio C Hamano 3a54f5bd5d merge/pull: add the "--compact-summary" option
"git merge" and "git pull" shows "git diff --stat --summary @{1}"
when they finish to indicate the extent of the changes brought into
the history by default.  While it gives a good overview, it becomes
annoying when there are very many created or deleted paths.

Introduce "--compact-summary" option to these two commands that
tells it to instead show "git diff --compact-summary @{1}", which
gives the same information in a lot more compact form in such a
situation.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-13 11:50:37 -07:00
Siddharth Asthana abf94a283f cat-file: fix mailmap application for different author and committer
The git cat-file command with --mailmap option fails to apply mailmap
transformations to the committer field when the author and committer
identities are different. This occurs due to a missing newline handling
in apply_mailmap_to_header() after processing each identity line.

When rewrite_ident_line() processes an identity, it stops at the end
of the identity data (e.g., "Author Name <email> timestamp"), but
doesn't account for the trailing newline. The current code adds the
identity length to buf_offset but fails to advance past the newline
character. This causes the next iteration to start parsing from the
newline instead of the beginning of the next header line, making it
impossible to match subsequent headers like "committer".

Additionally, rewrite_ident_line() may reallocate the buffer during
its operation. Any code using pointers into the old buffer would be
using invalid memory after such a reallocation.

This bug was introduced in e9c1b0e3 (revision: improve
commit_rewrite_person(), 2022-07-19) when the much simpler version of
commit_rewrite_person() that worked on one "person header" at a time
was rewritten to use the current apply_mailmap_to_header() function.
The original implementation processed author and committer separately,
but the rewrite introduced this loop-based approach that failed to
properly handle the transition between identity lines.

Let's fix this by addressing both issues:
1. After processing an identity line, we now check if we're at a
   newline and advance past it, ensuring the next header line is
   parsed correctly.
2. We recompute the buffer position after rewrite_ident_line() to
   handle potential buffer reallocation.

This ensures that all identity headers in commit and tag objects are
consistently processed regardless of whether the author and committer
are the same person.

Reported-by: Vasilii Iakliushin <viakliushin@gitlab.com>
Reviewed-by: Christian Couder <christian.couder@gmail.com>
Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-13 08:54:51 -07:00
Junio C Hamano aadf8ae518 Git 2.49.1
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-13 07:51:58 -07:00
Junio C Hamano b2bfd317a3 l10n-2.50.0-v2
-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE37vMEzKDqYvVxs51k24VDd1FMtUFAmhLZYwACgkQk24VDd1F
 MtUa3xAAuet6WgbUVN16q49Bd+WcK6uWooHlcpUMXANkJGqrjMquGfOCTc6bYXYi
 9JE87YUKxz5gIVP3YgEkJyLRiXuV0uUEfoGuXharQNDzMRfTNuhDmzV5drg7wWSJ
 CM0ErbD1jyHoPcuiusdhBCGAivV1k4WqofZ4OfhCUdapfpD1BnVXzNb6G6g6TemN
 WR5fiiQ2Ks0b8ZdfuXyBddqC44FOHwp4G1qgXBLoOq15matrNntb8y1ihualzTvp
 3M1LHNvh6HHwiD8lGcQiv/9Fjqbx6ypkUuxERiG90a53InKb5iYXA84MeYNbWm92
 rSpEpQOn3pq5ooweBLQWQUFOf/QFzFck6BtwHBdpH74FAkjXvjYs9aBPpH3PNUGW
 aXCTWZsvt2hEaYLMu3w54nrapnKUJMJrDRZn51+s88bk7s2fqY8yhfPduHh+fwu/
 4eVPQ9QgXiMS3sOTkU0tbV5qjw6LZFj9eb3Hg4MPQkwTQfe9x5mOOJC8IUOhwkuI
 bpb/V+PVYOcE4yv67qI51LeFkHt1ozWtxvXNJk3vEjcLSLDm3eBQTHo5t9wlpzsX
 pI3A985Fvzm7CQSr/0XPPGBLR1qnGjWXmOGe4v+N4VETnlPgqlv4nGEiLCFf+c8h
 4zwb/QaoTf7FLVKycEkBuiDohzGkuMUU1CICTTcPOJ7blwbGHjM=
 =2qMi
 -----END PGP SIGNATURE-----

Merge tag 'l10n-2.50.0-v2' of https://github.com/git-l10n/git-po

l10n-2.50.0-v2

* tag 'l10n-2.50.0-v2' of https://github.com/git-l10n/git-po:
  l10n: zh_TW: update translation for Git 2.50
2025-06-12 17:31:42 -07:00
Junio C Hamano a97f313784 Sync with 2.48.2
* maint-2.48:
  Git 2.48.2
  Git 2.47.3
  Git 2.46.4
  Git 2.45.4
  Git 2.44.4
  Git 2.43.7
  wincred: avoid buffer overflow in wcsncat()
  bundle-uri: fix arbitrary file writes via parameter injection
  config: quote values containing CR character
  git-gui: sanitize 'exec' arguments: convert new 'cygpath' calls
  git-gui: do not mistake command arguments as redirection operators
  git-gui: introduce function git_redir for git calls with redirections
  git-gui: pass redirections as separate argument to git_read
  git-gui: pass redirections as separate argument to _open_stdout_stderr
  git-gui: convert git_read*, git_write to be non-variadic
  git-gui: override exec and open only on Windows
  gitk: sanitize 'open' arguments: revisit recently updated 'open' calls
  git-gui: use git_read in githook_read
  git-gui: sanitize $PATH on all platforms
  git-gui: break out a separate function git_read_nice
  git-gui: assure PATH has only absolute elements.
  git-gui: remove option --stderr from git_read
  git-gui: cleanup git-bash menu item
  git-gui: sanitize 'exec' arguments: background
  git-gui: avoid auto_execok in do_windows_shortcut
  git-gui: sanitize 'exec' arguments: simple cases
  git-gui: avoid auto_execok for git-bash menu item
  git-gui: treat file names beginning with "|" as relative paths
  git-gui: remove unused proc is_shellscript
  git-gui: remove git config --list handling for git < 1.5.3
  git-gui: remove special treatment of Windows from open_cmd_pipe
  git-gui: remove HEAD detachment implementation for git < 1.5.3
  git-gui: use only the configured shell
  git-gui: remove Tcl 8.4 workaround on 2>@1 redirection
  git-gui: make _shellpath usable on startup
  git-gui: use [is_Windows], not bad _shellpath
  git-gui: _which, only add .exe suffix if not present
  gitk: encode arguments correctly with "open"
  gitk: sanitize 'open' arguments: command pipeline
  gitk: collect construction of blameargs into a single conditional
  gitk: sanitize 'open' arguments: simple commands, readable and writable
  gitk: sanitize 'open' arguments: simple commands with redirections
  gitk: sanitize 'open' arguments: simple commands
  gitk: sanitize 'exec' arguments: redirect to process
  gitk: sanitize 'exec' arguments: redirections and background
  gitk: sanitize 'exec' arguments: redirections
  gitk: sanitize 'exec' arguments: 'eval exec'
  gitk: sanitize 'exec' arguments: simple cases
  gitk: have callers of diffcmd supply pipe symbol when necessary
  gitk: treat file names beginning with "|" as relative paths

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-12 17:13:35 -07:00
Junio C Hamano 9edff09aec Merge branch 'kh/maintenance-missing-tasks-docfix'
Doc mark-up fix for a topic that has graduated to 'master'.

* kh/maintenance-missing-tasks-docfix:
  doc: maintenance: fix linkgit syntax
2025-06-12 14:19:10 -07:00
Junio C Hamano 5acfacc2a1 build: sed portability fixes
Recently generating the version-def.h file and the config-list.h
file have been updated, which broke versions of "sed" that do not
want to be fed a file that ends with an incomplete line, and/or that
do not understand the more recent "-E" option to use extended
regular expression.

Fix them in response to a build-failure reported on Solaris boxes.

cf. https://lore.kernel.org/git/09f954b8-d9c3-418f-ad4b-9cb9b063f4ae@comstyle.com/

Reported-by: Brad Smith <brad@comstyle.com>
Reviewed-by: Collin Funk <collin.funk1@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-12 13:44:10 -07:00
Junio C Hamano 9b662a5d21 l10n-2.50.0-rnd1
-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE37vMEzKDqYvVxs51k24VDd1FMtUFAmhK28EACgkQk24VDd1F
 MtU1GA/8CmvPedvJVqnaikUJTKRxrlyiqKkI8fAKqvqulubD36yI7QjDP4PhDKHA
 hK0uvJ16n4v4xp2aIATnD4E3AH3ocrjU5xzK1pqd26cYWdObKZeDpio/FQrEcJI2
 uPp+BHRnOVwg32gMHOEhry8rGtFlsZyCtoRSLPVPAN6Oy+NI4MfqJcN+FCtyWg5p
 oSTSwwbCXwUiuFXBjFgsCzq8Of/WRYr5cSfq/XCjz+0Gk57aLaVjnsVExxO6VwwB
 F5cdqbwuwbR7eGr3WJSGerNTfs4qKbVqbsxNDMLllI5OW/Kzm07nOdxNe4daoSbj
 9+DsNuOAe5mOdi09wx09B3QAMFiHOD8gJcTT4RbRXV+Fi3OZg782jIEzGKFmqccF
 7g7m74qsjk5GlswSXI8/l1l1mSPhBk4s6fcUkgF4aqO3F2QMIlCorEz5KE1J9H9R
 Xu+sMm46jLdCeVuz5obirE9XKOpdTlH1FQk02guskJgvCrXrmtzIBX6eYIUxewCO
 jyE4MYrVeY0PnIIMHMDJ1L+mg0hs6zyPjXiU7BQWHyYgLOQTp7q71slIYarpkj9o
 Md23cJwBhJV/lUqwuLCu6SwMBZlinYEN6QunRDbzl2oMBJjwz9VmrXbLzfqXujz4
 +ycA+efgGCN3JBU7qrvBME+jkT8dxn+4zoPFzwjfaXK2W9xXwbM=
 =O2DU
 -----END PGP SIGNATURE-----

Merge tag 'l10n-2.50.0-rnd1' of https://github.com/git-l10n/git-po

l10n-2.50.0-rnd1

* tag 'l10n-2.50.0-rnd1' of https://github.com/git-l10n/git-po:
  l10n: zh_CN: updated translation for 2.50
  l10n: Update German translation
  l10n: uk: add 2.50 translation
  l10n: po-id for 2.50
  l10n: bg.po: Updated Bulgarian translation (5819t)
  l10n: tr: Update Turkish translations for 2.50
  l10n: fr: v2.50 round 1
  l10n: Add full Irish translation (ga.po)
2025-06-12 13:35:08 -07:00
brian m. carlson bc303718cc builtin/stash: provide a way to import stashes from a ref
Now that we have a way to export stashes to a ref, let's provide a way
to import them from such a ref back to the stash.  This works much the
way the export code does, except that we strip off the first parent
chain commit and then store each resulting commit back to the stash.

We don't clear the stash first and instead add the specified stashes to
the top of the stash.  This is because users may want to export just a
few stashes, such as to share a small amount of work in progress with a
colleague, and it would be undesirable for the receiving user to lose
all of their data.  For users who do want to replace the stash, it's
easy to do to: simply run "git stash clear" first.

We specifically rely on the fact that we'll produce identical stash
commits on both sides in our tests.  This provides a cheap,
straightforward check for our tests and also makes it easy for users to
see if they already have the same data in both repositories.

Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-12 13:32:18 -07:00
brian m. carlson 27c0be9a3f builtin/stash: provide a way to export stashes to a ref
A common user problem is how to sync in-progress work to another
machine.  Users currently must use some sort of transfer of the working
tree, which poses security risks and also necessarily causes the index
to become dirty.  The experience is suboptimal and frustrating for
users.

A reasonable idea is to use the stash for this purpose, but the stash is
stored in the reflog, not in a ref, and as such it cannot be pushed or
pulled.  This also means that it cannot be saved into a bundle or
preserved elsewhere, which is a problem when using throwaway development
environments.

In addition, users often want to replicate stashes across machines, such
as when they must use multiple machines or when they use throwaway dev
environments, such as those based on the Devcontainer spec, where they
might otherwise lose various in-progress work.

Let's solve this problem by allowing the user to export the stash to a
ref (or, to just write it into the repository and print the hash, à la
git commit-tree).  Introduce git stash export, which writes a chain of
commits where the first parent is always a chain to the previous stash,
or to a single, empty commit (for the final item) and the second is the
stash commit normally written to the reflog.

Iterate over each stash from top to bottom, looking up the data for each
one, and then create the chain from the single empty commit back up in
reverse order.  Generate a predictable empty commit so our behavior is
reproducible.  Create a useful commit message, preserving the author and
committer information, to help users identify stash commits when viewing
them as normal commits.

If the user has specified specific stashes they'd like to export
instead, use those instead of iterating over all of the stashes.

As part of this, specifically request quiet behavior when looking up the
OID for a revision because we will eventually hit a revision that
doesn't exist and we don't want to die when that occurs.

When exporting stashes, be sure to verify that they look like valid
stashes and don't contain invalid data.  This will help avoid failures
on import or problems due to attempting to export invalid refs that are
not stashes.

Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-12 13:32:17 -07:00
brian m. carlson 7572e59b3d builtin/stash: factor out revision parsing into a function
We allow several special forms of stash names in this code.  In the
future, we'll want to allow these same forms without parsing a stash
commit, so let's refactor this code out into a function for reuse.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-12 13:32:17 -07:00
brian m. carlson 393bbb21c9 object-name: make get_oid quietly return an error
A reasonable person looking at the signature and usage of get_oid and
friends might conclude that in the event of an error, it always returns
-1.  However, this is not the case.  Instead, get_oid_basic dies if we
go too far back into the history of a reflog (or, when quiet, simply
exits).

This is not especially useful, since in many cases, we might want to
handle this error differently.  Let's add a flag here to make it just
return -1 like elsewhere in these code paths.

Note that we cannot make this behavior the default, since we have many
other codepaths that rely on the existing behavior, including in tests.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-12 13:32:17 -07:00
Sebastian Andrzej Siewior 1c62df0abe Revert "bswap.h: add support for built-in bswap functions"
Since 6547d1c9 (bswap.h: add support for built-in bswap
functions, 2025-04-23) tweaked the way the bswap32/64 macros are
defined, on platforms with __builtin_bswap32/64 supported, the
bswap32/64 macros are defined even on big endian platforms.

However the rest of this file assumes that bswap32/64() are defined
ONLY on little endian machines and uses that assumption to redefine
ntohl/ntohll macros. The said commit broke t4014-format-patch.sh test,
among many others on s390x.

Revert the commit.

Signed-off-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-12 13:23:39 -07:00
Yi-Jyun Pan cbf346a996
l10n: zh_TW: update translation for Git 2.50
Signed-off-by: Yi-Jyun Pan <pan93412@gmail.com>
2025-06-12 22:29:32 +08:00
Teng Long 925035958b l10n: zh_CN: updated translation for 2.50
Helped-by: 依云 <lilydjwg@gmail.com>
Helped-by: Jiang Xin <zhiyou.jx@alibaba-inc.com>
Signed-off-by: Teng Long <dyroneteng@gmail.com>
2025-06-12 21:47:46 +08:00
Jiang Xin 36cbedb7cf Merge branch '2.50-uk-update' of https://github.com/arkid15r/git-ukrainian-l10n
* '2.50-uk-update' of https://github.com/arkid15r/git-ukrainian-l10n:
  l10n: uk: add 2.50 translation
2025-06-12 09:53:04 +08:00
Jiang Xin ee33b2ef37 Merge branch 'l10n-de-2.50' of https://github.com/ralfth/git
* 'l10n-de-2.50' of https://github.com/ralfth/git:
  l10n: Update German translation
2025-06-12 09:49:37 +08:00
Junio C Hamano fdbea0870e CodingGuidelines: let BSS do its job
We have mentioned this in various reviews, but I didn't see it
mentioned in the CodingGuildelines document.  Let's add it.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-11 14:17:39 -07:00
Kristoffer Haugsbakk 1e2677f66f RelNotes/2.50.0: fix typos & other improvements
• Replace with phrases that are more standard (“all-or-nothing”
  instead of “-none”)
• Add coordinating words that make it less likely for you to trip
  over the sentence (“*that* "gc" can do”)
• Use “SMTP” instead of both SMTP and smtp
• Don’t mention `git fsck --reference` since the previous release
  was not affected by this minor bug.  Also say “errored out” since
  the git-refs(1) bug was there in v2.48.0 as well
• Use the more widespread “linked” instead of “secondary worktree”

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-11 13:32:14 -07:00
Johannes Schindelin 3cc4fc1ebd ci(coverity): output the build log upon error
It is quite helpful to know what Coverity said, exactly, in case it
fails to analyze the code.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-11 10:01:14 -07:00
Johannes Schindelin 882efe0444 ci(coverity): fix building on Windows
When I added the Coverity workflow in a56b6230d0 (ci: add a GitHub
workflow to submit Coverity scans, 2023-09-25), I merely converted an
Azure Pipeline definition that had been running successfully for ages.

In the meantime, the current Coverity documentation describes a very
different way to install the analysis tool, recommending to add the
`bin/` directory to the _end_ of `PATH` (when originally, IIRC, it was
recommended to add it to the _beginning_ of the `PATH`).

This is crucial! The reason is that the current incarnation of the
Windows variant of Coverity's analysis tools come with a _lot_ of DLL
files in their `bin/` directory, some of them interferring rather badly
with the `gcc.exe` in Git for Windows' SDK that we use to run the
Coverity build. The symptom is a cryptic error message:

  make: *** [Makefile:2960: headless-git.o] Error 1
  make: *** Waiting for unfinished jobs....
  D:\git-sdk-64-minimal\mingw64\bin\windres.exe: preprocessing failed.
  make: *** [Makefile:2679: git.res] Error 1
  make: *** [Makefile:2893: git.o] Error 1
  make: *** [Makefile:2893: builtin/add.o] Error 1
  Attempting to detect unconfigured compilers in build
  |0----------25-----------50----------75---------100|
  ****************************************************
  Warning:  Build command make.exe exited with code 2. Please verify that the build completed successfully.
  Warning:  Emitted 0 C/C++ compilation units (0%) successfully

  0 C/C++ compilation units (0%) are ready for analysis
   For more details, please look at:
      D:/a/git/git/cov-int/build-log.txt

The log (which the workflow is currently not configured to reveal) then
points out that the `windows.h` header cannot be found, which is _still_
not very helpful. The underlying root cause is that the `gcc.exe` in Git
for Windows' SDK determines the location of the header files via the
location of certain DLL files, and finding the "wrong" ones first on the
`PATH` misleads that logic.

Let's fix this problem by following Coverity's current recommendation
and append the `bin/` directory in which `cov-int` can be found to the
_end_ of `PATH`.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-11 10:01:14 -07:00
K Jayatheerth ffb36c64f2 stash: fix incorrect branch name in stash message
When creating a stash, Git uses the current branch name
of the superproject to construct the stash commit message.
However, in repositories with submodules,
the message may mistakenly display the submodule branch name instead.

This is because `refs_resolve_ref_unsafe()` returns a pointer to a static buffer.
Subsequent calls to the same function overwrite the buffer,
corrupting the originally fetched `branch_name` used for the stash message.

Use `xstrdup()` to duplicate the branch name immediately after resolving it,
so that later buffer overwrites do not affect the stash message.

Signed-off-by: K Jayatheerth <jayatheerthkulkarni2005@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-11 08:59:32 -07:00
Ralf Thielow b21f7dd9e3 l10n: Update German translation
Signed-off-by: Ralf Thielow <ralf.thielow@gmail.com>
2025-06-11 16:56:18 +02:00
Arkadii Yakovets aeac109283
l10n: uk: add 2.50 translation
Co-authored-by: Kate Golovanova <kate@kgthreads.com>
Co-authored-by: Tamara Lazerka <98753789+aramattamara@users.noreply.github.com>
Signed-off-by: Arkadii Yakovets <ark@cho.red>
Signed-off-by: Kate Golovanova <kate@kgthreads.com>
Signed-off-by: Tamara Lazerka <98753789+aramattamara@users.noreply.github.com>
2025-06-10 18:23:00 -07:00
Ayush Chandekar 1fde1c5daf preload-index: stop depending on 'the_repository'
Refactor "preload-index.c" to remove the dependency on the global
'the_repository'. Replace the occurrences of 'the_repository' with
'index->repo' and thus remove the definition '#define
USE_THE_REPOSITORY_VARIABLE'.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Ghanshyam Thakkar <shyamthakkar001@gmail.com>
Signed-off-by: Ayush Chandekar <ayu.chandekar@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-10 10:10:40 -07:00
Ayush Chandekar b1d47b464e environment: remove the global variable 'core_preload_index'
The global variable 'core_preload_index' is used in a single function
named 'preload_index()' in "preload-index.c". Move its declaration inside
that function, removing unnecessary global state.

This change is part of an ongoing effort to eliminate global variables,
improve modularity and help libify the codebase.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Ghanshyam Thakkar <shyamthakkar001@gmail.com>
Signed-off-by: Ayush Chandekar <ayu.chandekar@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-10 10:10:38 -07:00
Lidong Yan a3d278bb64 revision: fix memory leak in prepare_show_merge()
In revision.c:prepare_show_merge(), we allocated an array in prune
but forget to free it. Since parse_pathspec is not responsible to
free prune, we should add `free(prune)` in the end of prepare_show_merge().

Signed-off-by: Lidong Yan <502024330056@smail.nju.edu.cn>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-09 20:41:17 -07:00
Jiang Xin a956283999 Merge branch 'po-id' of github.com:bagasme/git-po
* 'po-id' of github.com:bagasme/git-po:
  l10n: po-id for 2.50
2025-06-10 07:43:17 +08:00
Jiang Xin f6709fbc4a Merge branch 'master' of github.com:alshopov/git-po
* 'master' of github.com:alshopov/git-po:
  l10n: bg.po: Updated Bulgarian translation (5819t)
2025-06-10 07:42:34 +08:00
Jiang Xin 104807f89e Merge branch 'l10n_fr_v2.50' of github.com:jnavila/git
* 'l10n_fr_v2.50' of github.com:jnavila/git:
  l10n: fr: v2.50 round 1
2025-06-10 07:41:22 +08:00
Jiang Xin b0f9a659b2 Merge branch 'tr-l10n' of github.com:bitigchi/git-po
* 'tr-l10n' of github.com:bitigchi/git-po:
  l10n: tr: Update Turkish translations for 2.50
2025-06-10 07:39:49 +08:00
Jiang Xin 1963f3203a Merge branch 'master' of github.com:aindriu80/git-po
* 'master' of github.com:aindriu80/git-po:
  l10n: Add full Irish translation (ga.po)
2025-06-10 07:37:22 +08:00
Kristoffer Haugsbakk 6cd0701e3c doc: maintenance: fix linkgit syntax
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-09 11:33:25 -07:00
Ramsay Jones 2f71f61045 test-lib: add missing prerequisites for Darwin
commit d3d8c601fd ("t7815: fix unexpectedly passing test on macOS",
2025-06-02) added a MACOS prerequisite by adding a 'Darwin' case
label to the 'OS-specific' case statement. However, this commit
forgot to set several prerequisites which appear in the 'default'
case label, in addition to the new MACOS prerequisite. This causes
several tests, which macOS should pass, being skipped.

In order to run all applicable tests on macOS, add the missing
prerequisites to the 'Darwin' case.

Signed-off-by: Ramsay Jones <ramsay@ramsayjones.plus.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-09 11:25:37 -07:00
Lidong Yan 81cd1eef7d pack-bitmap: remove checks before bitmap_free
In pack-bitmap.c:find_boundary_objects(), the roots_bitmap is only freed
if cascade_pseudo_merges_1() fails. However, cascade_pseudo_merges_1()
uses roots_bitmap as a mutable reference without taking ownership of it.
As a result, if cascade_pseudo_merges_1() succeeds, roots_bitmap is leaked.
And this leak currently lacks a dedicated test to detect it.

To fix this leak, remove if cascade_pseudo_merges_1() succeed check and
always calling bitmap_free(roots_bitmap);

To trigger this leak, we need roots_bitmap that contains at least one
pseudo merge. So that we can use pseudo merge bitmap when we compute roots
reachable bitmap. Here we create two commits: first A then B. Add A
to the pseudo-merge and perform a traversal over the range A..B.
In this scenario, the "haves" set will be {A}, and cascade_pseudo_merges_1
will succeed, thereby exposing the leak due to the missing roots_bitmap
cleanup.

Signed-off-by: Lidong Yan <502024330056@smail.nju.edu.cn>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-09 09:04:47 -07:00
Junio C Hamano 4c0e625c09 Git 2.50-rc2
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-09 07:18:49 -07:00
Junio C Hamano 427b538fc3 Merge branch 'mm/test-in-absolute-home'
Tests that compare $HOME and $(pwd), which should be the same
directory unless the tests chdir's around, would fail when the user
enters the test directory via symbolic links, which has been
corrected.

* mm/test-in-absolute-home:
  t: run tests from a normalized working directory
2025-06-09 07:15:51 -07:00
Lidong Yan bfc9f9cc64 builtin/submodule--helper: fix leak when remote_submodule_branch() failed
In builtin/submodule--helper.c:update_submodule(), the variable
remote_name is allocated in get_default_remote_submodule() but
may be leaked if remote_submodule_branch() fails. Although it is
unlikely that remote_submodule_branch() would fail after successfully
obtaining a remote ref name from get_default_remote_submodule(),
it is still possible. To prevent a potential memory leak, add a
call to free(remote_name) at the early exit point.

Signed-off-by: Lidong Yan <502024330056@smail.nju.edu.cn>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-08 08:49:48 -07:00
Brad Smith 47e7dee00a config.mak.uname: update settings for Solaris 10 and 11
Solaris 10 and newer has strtoumax().

Solaris 11 and newer has mkdtemp(), memmem(), and strcasestr().

Signed-off-by: Brad Smith <brad@comstyle.com>
Reviewed-by: Collin Funk <collin.funk1@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-07 21:21:10 -07:00
Junio C Hamano 8db3019401 A bit more before -rc2
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-07 10:46:51 -07:00
Junio C Hamano 8546b3566e Merge branch 'js/curl-easy-setopt-typefix'
Adjust to newer version of libcURL.

* js/curl-easy-setopt-typefix:
  curl: pass `long` values where expected
2025-06-07 10:46:50 -07:00
Junio C Hamano 7558d89423 Merge branch 'jk/curl-easy-setopt-typefix'
Adjust to newer version of libcURL.

* jk/curl-easy-setopt-typefix:
  curl: fix symbolic constant typechecks with curl_easy_setopt()
  curl: fix integer variable typechecks with curl_easy_setopt()
  curl: fix integer constant typechecks with curl_easy_setopt()
2025-06-07 10:46:50 -07:00
Junio C Hamano c20471e465 Merge branch 'bs/bsd-wo-specific-xopen-source'
Build fix for BSDs.

* bs/bsd-wo-specific-xopen-source:
  compat: fixes for header handling with OpenBSD / NetBSD
2025-06-07 10:46:50 -07:00
Junio C Hamano e2e22932cd Merge branch 'cf/var-completion-obsd-fixes'
Build fix for OpenBSD.

* cf/var-completion-obsd-fixes:
  completion: make sed command that generates config-list.h portable.
2025-06-07 10:46:49 -07:00
Phillip Wood 468817bab2 stash: allow "git stash [<options>] --patch <pathspec>" to assume push
The support for assuming "push" when "-p" is given introduced in
9e140909f6 (stash: allow pathspecs in the no verb form, 2017-02-28) is
very narrow, neither "git stash -m <message> -p <pathspec>" nor "git
stash --patch <pathspec>" imply "push" and die instead. Relax this by
passing PARSE_OPT_STOP_AT_NON_OPTION when push is being assumed and then
setting "force_assume" if "--patch" was present. This means "git stash
<pathspec> -p" still dies so that it does not assume the user meant
"push" if they mistype a subcommand name but "git stash -m <message> -p
<pathspec>" will now succeed. The test added in the last commit is
adjusted to check that push is still assumed when "--patch" comes after
other options on the command-line.

Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-07 10:37:17 -07:00
Phillip Wood e6659b77df stash: allow "git stash -p <pathspec>" to assume push again
Historically "git stash [<options>]" was assumed to mean "git stash save
[<options>]". Since 1ada5020b3 (stash: use stash_push for no verb form,
2017-02-28) it is assumed to mean "git stash push [<options>]". As the
push subcommand supports pathspecs, 9e140909f6 (stash: allow pathspecs
in the no verb form, 2017-02-28) allowed "git stash -p <pathspec>" to
mean "git stash push -p <pathspec>". This was broken in 8c3713cede
(stash: eliminate crude option parsing, 2020-02-17) which failed to
account for "push" being added to the start of argv in cmd_stash()
before it calls push_stash() and kept looking in argv[0] for "-p" after
moving the code to push_stash().

Fix this by regression by checking argv[1] instead of argv[0] and add a
couple of tests to prevent future regressions.

Helped-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-07 10:37:16 -07:00
Bagas Sanjaya 642fd4ff36 l10n: po-id for 2.50
Update following components:

  * builtin/cat-file.c
  * builtin/fast-export.c
  * builtin/fsck.c
  * builtin/merge-tree.c
  * builtin/mv.c
  * builtin/reflog.c
  * builtin/repack.c
  * builtin/rev-list.c
  * builtin/update-ref.c
  * command-list.h
  * midx-write.c
  * object-file.c
  * parse-options.c
  * promisor-remote.c
  * refs/packed-backend.c
  * scalar.c
  * t/helper/test-pack-deltas.c
  * git-send-email.perl

Translate following new components:

  * builtin/diff-pairs.c

Signed-off-by: Bagas Sanjaya <bagasdotme@gmail.com>
2025-06-07 08:27:57 +07:00
Jouke Witteveen 3717a5775a doc: update references to renamed AsciiDoc files
The .txt extensions were changed to .adoc in 1f010d6 (doc: use .adoc
extension for AsciiDoc files, 2025-01-20). References to the renamed
files were not updated yet.

Signed-off-by: Jouke Witteveen <j.witteveen@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-06 15:05:47 -07:00
Junio C Hamano 83cb7ae638 Merge branch 'master' of https://github.com/j6t/git-gui
* 'master' of https://github.com/j6t/git-gui:
  git-gui: don't delete source files when auto_mkindex fails
2025-06-06 09:41:59 -07:00
Martin Ågren 65dff89c6b diff-generate-patch.adoc: drop spurious backticks
Commit 0b080a70ab (doc: git-diff: apply format changes to
diff-generate-patch, 2024-11-18) wrapped the ".." in

  mode <mode>,<mode>..<mode>

in backticks. Note how the line before is quite similar,

  index <hash>,<hash>..<hash>

but did not get any backticks. Remove the backticks, since they confuse
Asciidoctor.

The exact failure mode changed with c87b2b3a6f (doc: fix asciidoctor
synopsis processing of triple-dots, 2025-04-12), and arguably to the
better. But Asciidoctor (2.0.18) still ends up confused by these
backticks and leaves the manpage rendering as

  index <hash>,<hash>..<hash>
  mode <mode>,<mode>`..__<mode>__
  {empty}`new file mode <mode>

Drop the backticks. This is a no-op with asciidoc (10.2.0).

Signed-off-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-06 08:47:36 -07:00
Johannes Schindelin 229d12665e curl: pass `long` values where expected
As of Homebrew's update to cURL v8.14.0, there are new compile errors to
be observed in the `osx-gcc` job of Git's CI builds:

  In file included from http.h:8,
                   from imap-send.c:36:
  In function 'setup_curl',
      inlined from 'curl_append_msgs_to_imap' at imap-send.c:1460:9,
      inlined from 'cmd_main' at imap-send.c:1581:9:
  /usr/local/Cellar/curl/8.14.0/include/curl/typecheck-gcc.h:50:15: error: call to '_curl_easy_setopt_err_long' declared with attribute warning: curl_easy_setopt expects a long argument [-Werror=attribute-warning]
     50 |               _curl_easy_setopt_err_long();                             \
        |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
  /usr/local/Cellar/curl/8.14.0/include/curl/curl.h:54:7: note: in definition of macro 'CURL_IGNORE_DEPRECATION'
     54 |       statements \
        |       ^~~~~~~~~~
  imap-send.c:1423:9: note: in expansion of macro 'curl_easy_setopt'
   1423 |         curl_easy_setopt(curl, CURLOPT_PORT, srvc->port);
        |         ^~~~~~~~~~~~~~~~
  [... many more instances of nearly identical warnings...]

See for example this CI workflow run:
https://github.com/git/git/actions/runs/15454602308/job/43504278284#step:4:307

The most likely explanation is the entry "typecheck-gcc.h: fix the
typechecks" in cURL's release notes (https://curl.se/ch/8.14.0.html).

Nearly identical compile errors afflicted recently-updated Debian
setups, which have been addressed by `jk/curl-easy-setopt-typefix`.

However, on macOS Git is built with different build options, which
uncovered more instances of `int` values that need to be cast to
constants, which were not covered by 6f11c42e8e (curl: fix integer
constant typechecks with curl_easy_setopt(), 2025-06-04). Let's
explicitly convert even those remaining `int` constants in
`curl_easy_setopt()` calls to `long` parameters.

In addition to looking at the compile errors of the `osx-gcc` job, I
verified that there are no other instances of the same issue that need
to be handled in this manner (and that might not be caught by our CI
builds because of yet other build options that might skip those code
parts), I ran the following command and inspected all 23 results
manually to ensure that the fix is now actually complete:

  git grep -n curl_easy_setopt |
  grep -ve ',.*, *[A-Za-z_"&]' \
    -e ',.*, *[-0-9]*L)' \
    -e ',.*,.* (long)'

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-06 08:12:24 -07:00
Johannes Sixt 765f1db2b5 git-gui: don't delete source files when auto_mkindex fails
Commit 2cc5b0facf (git-gui: extract script to generate "tclIndex",
2025-03-11) converted commands in a Makefile rule to a shell script.
In this process, the Makefile variable $@ had to be replaced by the
file name that it represents, 'lib/tclIndex'. However, the occurrence
in `rm -f $@` was missed. In a shell script, $@ expands to all
command line arguments, which happen to be the source files lib/*.tcl
in this case. Needless to say that we do not want to remove source
files during a build. Replace $@ by the intended 'lib/tclIndex'.

Reported-by: Randall S. Becker <rsbecker@nexbridge.com>
Signed-off-by: Johannes Sixt <j6t@kdbg.org>
2025-06-06 07:43:37 +02:00
Junio C Hamano 14de3eb344 Merge branch 'js/t5410-tee-hang-workaround'
* js/t5410-tee-hang-workaround:
  t5410: avoid hangs in CI runs in the win+Meson test jobs
2025-06-05 11:56:29 -07:00
Johannes Schindelin 52a86dd26d t5410: avoid hangs in CI runs in the win+Meson test jobs
In the GitHub workflow used in Git's CI builds, the `vs test` jobs use a
subset of a specific revision of Git for Windows' SDK to run Git's test
suite. This revision is validated by another CI workflow to ensure that
said revision _can_ run Git's test suite successfully, skipping buggy
updates in Git for Windows' SDK.

The `win+Meson test` jobs do things differently, quite differently. They
use the Bash of the Git for Windows version that is installed on the
runners to run Git's test suite.

This difference has consequences.

When 68cb0b5253 (builtin/receive-pack: add option to skip connectivity
check, 2025-05-20) introduced a test case that uses `tee <file> | git
receive-pack` as `--receive-pack` parameter (imitating an existing
pattern in the same test script), it hit just the sweet spot to trigger
a bug in the MSYS2 runtime shipped in Git for Windows v2.49.0. This
version is the one currently installed on GitHub's runners.

The problem is that the `git receive-pack` process finishes while the
`tee` process does not need to write anything anymore and therefore does
not receive an EOF. Instead, it should receive a SIGPIPE, but the bug in
the MSYS2 runtime prevents that from working as intended. As a
consequence, the `tee` process waits for more input from the `git.exe
send-pack` process but none is coming, and the test script patiently
waits until the 6h timeout hits.

Only every once in a while, the `git receive-pack` process manages to
send an EOF to the `tee` process and no hang occurs. Therefore, the
problem can be worked around by cancelling the clearly-hanging job after
twenty or so minutes and re-running it, repeating the process about half
a dozen times, until the hang was successfully avoided.

This bug in the MSYS2 runtime has been fixed in the meantime, which is
the reason why the same test case causes no problems in the `win test`
and the `vs test` jobs.

This will continue to be the case until the Git for Windows version on
the GitHub runners is upgraded to a version that distributes a newer
MSYS2 runtime version. However, as of time of writing, this _is_ the
latest Git for Windows version, and will be for another 1.5 weeks, until
Git v2.50.0 is scheduled to appear (and shortly thereafter Git for
Windows v2.50.0). Traditionally it takes a while before the runners pick
up the new version.

We could just wait it out, six hours at a time.

Here, I opt for an alternative: Detect the buggy MSYS2 runtime and
simply skip the test case. It's not like the `receive-pack` test cases
are specific to Windows, and even then, to my chagrin the CI runs in
git-for-windows/git spend around ten hours of compute time each and
every time to run the entire test suite on all the platforms, even the
tests that cover cross-platform code, and for Windows alone we do that
three times: with GCC, with MSVC, and with MSVC via Meson. Therefore, I
deem it more than acceptable to skip this test case in one of those
matrices.

For good luck, also the preceding test case is skipped in that scenario,
as it uses the same `--receive-pack=tee <file> | git receive-pack`
pattern, even though I never observed that test case to hang in
practice.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-05 09:45:42 -07:00
Junio C Hamano c80760403b Merge branch 'jk/curl-easy-setopt-typefix' into js/curl-easy-setopt-typefix
* jk/curl-easy-setopt-typefix:
  curl: fix symbolic constant typechecks with curl_easy_setopt()
  curl: fix integer variable typechecks with curl_easy_setopt()
  curl: fix integer constant typechecks with curl_easy_setopt()
2025-06-05 08:56:57 -07:00
Lidong Yan 61372dd613 repo_logmsg_reencode: fix memory leak when use repo_logmsg_reencode ()
pretty.c:repo_logmsg_reencode() allocated memory should be freed with
repo_unuse_commit_buffer(). Callers sometimes forgot free it at exit
point. Add `repo_unuse_commit_buffer()` in insert_records_from_trailers
at builtin/shortlog.c and create_commit at builtin/replay.c

Signed-off-by: Lidong Yan <502024330056@smail.nju.edu.cn>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-05 08:35:22 -07:00
Junio C Hamano 0d42fbd9a1 Merge branch 'bs/config-mak-openbsd'
Build fix for OpenBSD

* bs/config-mak-openbsd:
  config.mak.uname: update settings for OpenBSD
2025-06-04 14:30:28 -07:00
Jeff King 4558c8f84b curl: fix symbolic constant typechecks with curl_easy_setopt()
As with the previous two commits, we should be passing long integers,
not regular ones, to curl_easy_setopt(), and compiling against curl 8.14
loudly complains if we don't.

This patch catches the remaining cases, which are ones where we pass
curl's own symbolic constants. We'll cast them to long manually in each
call.

It seems kind of weird to me that curl doesn't define these constants as
longs, since the point of them is to pass to curl_easy_setopt(). But in
the curl documentation and examples, they clearly show casting them as
part of the setopt calls. It may be that there is some reason not to
push the type into the macro, like backwards compatibility. I didn't
dig, as it doesn't really matter: we have to follow what existing curl
versions ask for anyway.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-04 14:17:53 -07:00
Jeff King 30325e23ba curl: fix integer variable typechecks with curl_easy_setopt()
As discussed in the previous commit, we should be passing long integers,
not regular ones, to curl_easy_setopt(), and compiling against curl 8.14
loudly complains if we don't.

That patch fixed integer constants by adding an "L". This one deals with
actual variables.

Arguably these variables could just be declared as "long" in the first
place. But it's actually kind of awkward due to other code which uses
them:

  - port is conceptually a short, and we even call htons() on it (though
    weirdly it is defined as a regular int).

  - ssl_verify is conceptually a bool, and we assign to it from
    git_config_bool().

So I think we could probably switch these out for longs without hurting
anything, but it just feels a bit weird. Doubly so because if you don't
set USE_CURL_FOR_IMAP_SEND set, then the current types are fine!

So let's just cast these to longs in the curl calls, which makes what's
going on obvious. There aren't that many spots to modify (and as you can
see from the context, we already have some similar casts).

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-04 14:17:53 -07:00
Jeff King 6f11c42e8e curl: fix integer constant typechecks with curl_easy_setopt()
The curl documentation specifies that curl_easy_setopt() takes either:

  ...a long, a function pointer, an object pointer or a curl_off_t,
  depending on what the specific option expects.

But when we pass an integer constant like "0", it will by default be a
regular non-long int. This has always been wrong, but seemed to work in
practice (I didn't dig into curl's implementation to see whether this
might actually be triggering undefined behavior, but it seems likely and
regardless we should do what the docs say).

This is especially important since curl has a type-checking macro that
causes building against curl 8.14 to produce many warnings. The specific
commit is due to their 79b4e56b3 (typecheck-gcc.h: fix the typechecks,
2025-04-22). Curiously, it does only seem to trigger when compiled with
-O2 for me.

We can fix it by just marking the constants with a long "L".

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-04 14:17:53 -07:00
Jan Mazur efb61591ee bundle-uri: send debug output to given FILE * stream
d796cedb (bundle-uri: unit test "key=value" parsing, 2022-10-12)
introduced the print_bundle_list() function, which takes a "FILE
*fp" to write the output to.  Later with c93c3d2f (bundle-uri:
parse bundle.heuristic=creationToken, 2023-01-31) the function
started showing additional information, which is always written
to the standard output stream.

It does not look like a deliberate decision to do so, and it
does not hurt, as all callers of the function passes stdout to
it.

We could change the function not to take fp and always write to
the standard output to simplify, but let's use the FILE *fp
provided by the caller consistently to write out output.

Signed-off-by: Jan Mazur <mzr@meta.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-04 13:19:47 -07:00
Patrik Weiskircher fea50ce411 contrib/subtree: add -S/--gpg-sign
Allows optionally signing the commits that git subtree creates. This can
be necessary when working in a repository that requires gpg signed
commits.

Signed-off-by: Patrik Weiskircher <patrik@pspdfkit.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-04 09:32:17 -07:00
Patrik Weiskircher 7cd080acf6 contrib/subtree: parse using --stuck-long
Optional parameter handling only works unambiguous with git rev-parse
--parseopt when using the --stuck-long option. To prepare for future commits
which add flags with optional parameters, parse with --stuck-long.

Signed-off-by: Patrik Weiskircher <patrik@pspdfkit.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-04 09:32:17 -07:00
Aditya Garg 2cc27b3501 send-email: show the new message id assigned by outlook in the logs
Whenever an email is sent, send-email shows a log at last, which
contains all the headers of the email that were received by the
receipients.

In case outlook changes the Message-ID, a log for the same is shown to
the user, but that change is not reflected when the log containing all
the headers is displayed. Here is an example of the log that is shown
when outlook changes the Message-ID:

Outlook reassigned Message-ID to: <PN3PR01MB95973E5ACD7CCFADCB4E298CB865A@PN3PR01MB9597.INDPRD01.PROD.OUTLOOK.COM>
OK. Log says:
Server: smtp.office365.com
MAIL FROM:<gargaditya08@live.com>
RCPT TO:<negahe7142@nomrista.com>
From: Aditya Garg <gargaditya08@live.com>
To: negahe7142@nomrista.com
Subject: [PATCH] send-email: show the new message id assigned by outlook in the logs
Date: Mon, 26 May 2025 20:28:36 +0530
Message-ID: <20250526145836.4825-1-gargaditya08@live.com>
X-Mailer: git-send-email @GIT_VERSION@
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit

Result: 250

Fix this by updating the $header variable, which has the message ID we
internally assigned on the "Message-ID:" header, with the message ID the
Outlook server assigned. It should look like this after this patch:

OK. Log says:
Server: smtp.office365.com
MAIL FROM:<gargaditya08@live.com>
RCPT TO:<negahe7142@nomrista.com>
From: Aditya Garg <gargaditya08@live.com>
To: negahe7142@nomrista.com
Subject: [PATCH] send-email: show the new message id assigned by outlook in the logs
Date: Mon, 26 May 2025 20:29:22 +0530
Message-ID: <PN3PR01MB95977486061BD2542BD09B67B865A@PN3PR01MB9597.INDPRD01.PROD.OUTLOOK.COM>
X-Mailer: git-send-email @GIT_VERSION@
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit

Result: 250

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-04 09:30:13 -07:00
Aditya Garg 092bd1532c send-email: fix bug resulting in broken threads if a message is edited
Whenever we send a thread of emails using send-email, a message number
is internally assigned to each email. This number is used to track the
order of the emails in the thread. Whenever a new message is processed
in a thread, the current script logic increments the message number by
one, which is intended.

But, if a message is edited and then resent, its message number again
gets incremented. This is because the script uses the same logic to
process the edited message, which it uses to send the next message.

This minor bug is usually harmless, unless a special situations arises.
That situation is when the first message in a thread is edited and
resent, and an `--in-reply-to` argument is also passed to send-email.
In this case, if the user has chosen shallow threading, the threading
does not work as expected, and all messages become replies to the
Message-ID specified in the `--in-reply-to` argument.

The reason for this bug is hidden in the code for threading itself.

if ($thread) {
	if ($message_was_sent &&
	  ($chain_reply_to || !defined $in_reply_to || length($in_reply_to) == 0 ||
	  $message_num == 1)) {
		$in_reply_to = $message_id;
		if (length $references > 0) {
			$references .= "\n $message_id";
		} else {
			$references = "$message_id";
		}
	}
}

Here `$message_num` is the current message number, and `$in_reply_to` is
the Message-ID of the message to which the current message is a reply.
In case `--in-reply-to` is specified, the `$in_reply_to` variable
is set to the value of the `--in-reply-to` argument.

Whenever this whole set of conditions is true, the script sets the
`$in_reply_to` variable to the current message's ID. This is done to
ensure that the next message in the thread is a reply to this message.

In case we specify an `--in-reply-to` argument, and have shallow
threading, the only condition that can make this true is
`$message_num == 1`, which is true for the first message in a thread.
Thus, the `$in_reply_to` variable gets set to the first message's ID.
For subsequent messages, the `$message_num` variable is always
greater than 1, and the whole set of conditions is false. Therefore, the
`$in_reply_to` variable remains as the first message's ID. This is what
we expect in shallow threading. But if the user edits the first message
and resends it, the `$message_num` variable gets incremented by 1, and
thus the condition `$message_num == 1` becomes false. This means that
the `$in_reply_to` variable is not set to the first message's ID. As a
result the next message in the thread is not a reply to the first
message, but to the `--in-reply-to` argument, effectively breaking the
threading.

In case the user does not specify an `--in-reply-to` argument, the
`!defined $in_reply_to` condition is true, and thus the `$in_reply_to`
variable is set to the first message's ID, and the threading works
as expected, regardless of the message number.

To fix this bug, we need to ensure that the `$message_num` variable is
not incremented by 1 when a message is edited and resent. We do this by
decreasing the `$message_num` variable by 1 whenever the request to edit
a message is received. This way, the next message in the thread will
have the same message number as the edited message. Therefore the
threading will work as expected.

The same logic has also been applied in case the user drops a single
message from the thread by choosing the "[n]o" option during
confirmation. By doing this, the next message in the thread is assigned
the message number of the dropped message, and thus the threading
works as expected.

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-04 09:30:12 -07:00
Lidong Yan 7082da85cb commit-graph: fix start_delayed_progress() leak
In commit-graph.c:graph_write(), if read_one_commit() failed,
progress allocated in start_delayed_progress() will leak. Add
stop_progress() before goto cleanup.

Signed-off-by: Lidong Yan <502024330056@smail.nju.edu.cn>
Acked-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-04 08:55:30 -07:00
Lidong Yan aedebdb6b9 builtin/fetch-pack: cleanup before return error
In builtin/fetch-pack.c:cmd_fetch_pack(), if finish_connect() failed,
it returns error code without cleanup which cause memory leak. Add
cleanup label before frees in the end of cmd_fetch_pack(), and add
`goto cleanup` if finish_connect() failed.

Signed-off-by: Lidong Yan <502024330056@smail.nju.edu.cn>
Acked-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-04 08:52:25 -07:00
Victoria Dye b0b910e052 cat-file.c: add batch handling for submodules
When an object specification is passed to 'cat-file --batch[-check]'
referring to a submodule (e.g. 'HEAD:path/to/my/submodule'), the current
behavior of the command is to print the "missing" error message. However, it
is often valuable for callers to distinguish between paths that are actually
missing and "the submodule tree entry exists, but the object does not exist
in the repository".

To disambiguate without needing to invoke a separate Git process (e.g.
'ls-tree'), print the message "<oid> submodule" for such objects instead of
"<object> missing". In addition to the change from "missing" to "submodule",
the new message differs from the old in that it always prints the resolved
tree entry's OID, rather than the input object specification.

Note that this implementation maintains a distinction between submodules
where the commit OID is not present in the repo, and submodules where the
commit OID *is* present; the former will now print "<object> submodule", but
the latter will still print the full object content.

Signed-off-by: Victoria Dye <vdye@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-03 12:08:58 -07:00
Victoria Dye aba1438435 cat-file: add %(objectmode) atom
Add a formatting atom, used with the --batch-check/--batch-command options,
that prints the octal representation of the object mode if a given revision
includes that information, e.g. one that follows the format
<tree-ish>:<path>. If the mode information does not exist, an empty string
is printed instead.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Victoria Dye <vdye@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-03 12:08:58 -07:00
Victoria Dye 9fd38038b9 t1006: update 'run_tests' to test generic object specifiers
Update the 'run_tests' test wrapper so that the first argument may refer to
any specifier that uniquely identifies an object (e.g. a ref name,
'<OID>:<path>', '<OID>^{<type>}', etc.), rather than only a full object ID.

Also add tests that use non-OID identifiers, ensuring appropriate parsing in
'cat-file'. The identifiers used in some of the added tests include a space,
which is incompatible with the '%(rest)' atom. To accommodate that without
removing the test case, use 'test_expect_failure' when 'object_name'
includes a space.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Victoria Dye <vdye@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-03 12:08:58 -07:00
Lidong Yan 5dceb8bd05 BUG(): remove leading underscore of the format string
BUG() is not end-user facing but programmer facing, and we do not
use _("...") in them. Replace all `BUG(_("..."))` with `BUG("...")`

Signed-off-by: Lidong Yan <502024330056@smail.nju.edu.cn>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-03 08:36:11 -07:00
Lidong Yan 8b34b6a220 sequencer: replace error() with BUG() in update_squash_messages ()
In sequencer.c, caller only pass TODO_SQUASH or TODO_FIXUP to
update_squash_messages(), any other command passed in should be
considered as BUG. Replace `return error('unknown command')`
with `BUG('not a FIXUP or SQUASH')`.

Signed-off-by: Lidong Yan <502024330056@smail.nju.edu.cn>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-03 08:33:01 -07:00
Patrick Steinhardt 1b5074e614 builtin/maintenance: fix locking race when handling "gc" task
The "gc" task has a similar locking race as the one that we have fixed
for the "pack-refs" and "reflog-expire" tasks in preceding commits. Fix
this by splitting up the logic of the "gc" task:

  - We execute `gc_before_repack()` in the foreground, which contains
    the logic that git-gc(1) itself would execute in the foreground, as
    well.

  - We spawn git-gc(1) after detaching, but with a new hidden flag that
    suppresses calling `gc_before_repack()`.

Like this we have roughly the same logic as git-gc(1) itself and know to
repack refs and reflogs before detaching, thus fixing the race.

Note that `gc_before_repack()` is renamed to `gc_foreground_tasks()` to
better reflect what this function does.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-03 08:30:52 -07:00
Patrick Steinhardt d2b084c660 builtin/gc: avoid global state in `gc_before_repack()`
The `gc_before_repack()` should only ever run once in git-gc(1), but we
may end up calling it twice when the "--detach" flag is passed. The
duplicated call is avoided though via a static flag in this function.

This pattern is somewhat unintuitive though. Refactor it to drop the
static flag and instead guard the second call of `gc_before_repack()`
via `opts.detach`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-03 08:30:52 -07:00
Patrick Steinhardt 697202b0b1 usage: allow dying without writing an error message
Sometimes code wants to die in a situation where it already has written
an error message. To use the same error code as `die()` we have to use
`exit(128)`, which is easy to get wrong and leaves magic numbers all
over our codebase.

Teach `die_message_builtin()` to not print any error when passed a
`NULL` pointer as error string. Like this, such users can now call
`die(NULL)` to achieve the same result without any hardcoded error
codes.

Adapt a couple of builtins to use this new pattern to demonstrate that
there is a need for such a helper.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-03 08:30:51 -07:00
Patrick Steinhardt c367852d9e builtin/maintenance: fix locking race with refs and reflogs tasks
As explained in the preceding commit, git-gc(1) knows to detach only
after it has already packed references and expired reflogs. This is done
to avoid racing around their respective lockfiles.

Adapt git-maintenance(1) accordingly and run the "pack-refs" and
"reflog-expire" tasks in the foreground. Note that the "gc" task has the
same issue, but the fix is a bit more involved there and will thus be
done in a subsequent commit.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-03 08:30:51 -07:00
Patrick Steinhardt 5bb4298acf builtin/maintenance: split into foreground and background tasks
Both git-gc(1) and git-maintenance(1) have logic to daemonize so that
the maintenance tasks are performed in the background. git-gc(1) has
some special logic though to not perform _all_ housekeeping tasks in the
background: both references and reflogs are still handled synchronously
in the foreground.

This split exists because otherwise it may easily happen that git-gc(1)
keeps the "packed-refs" file locked for an extended amount of time,
where the next Git command that wants to modify any reference could now
fail. This was especially important in the past, where git-gc(1) was
still executed directly as part of our automatic maintenance: git-gc(1)
was invoked via `git gc --auto --detach`, so we knew to handle most of
the maintenance tasks in the background while doing those parts that may
cause locking issues in the foreground.

We have since moved to git-maintenance(1), which is a more flexible
replacement for git-gc(1). By default this command runs git-gc(1), only,
but it can be configured to run different tasks, as well. This command
does not know about the split between maintenance tasks that should run
before and after detach though, and this has led to several bug reports
about spurious locking errors for the "packed-refs" file.

Prepare for a fix by introducing this split for maintenance tasks. Note
that this commit does not yet change any of the tasks, so there should
not (yet) be a change in behaviour.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-03 08:30:51 -07:00
Patrick Steinhardt 3236e03c66 builtin/maintenance: fix typedef for function pointers
The typedefs for `maintenance_task_fn` and `maintenance_auto_fn` are
somewhat confusingly not true function pointers. As such, any user of
those typedefs needs to manually add the pointer to make use of them.

Fix this by making these true function pointers.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-03 08:30:50 -07:00
Patrick Steinhardt 2aa9ee7eec builtin/maintenance: extract function to run tasks
Extract the function to run maintenance tasks. This function will be
reused in a subsequent commit where we introduce a split between
maintenance tasks that run before and after daemonizing the process.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-03 08:30:50 -07:00
Patrick Steinhardt 38a8fa5a9a builtin/maintenance: stop modifying global array of tasks
When configuring maintenance tasks run by git-maintenance(1) we do so by
modifying the global array of tasks directly. This is already quite bad
on its own, as global state makes for logic that is hard to follow.

Even more importantly though we use multiple different fields to track
whether or not a task should be run:

  - "enabled" tracks the "maintenance.*.enabled" config key. This field
    disables execution of a task, unless the user has explicitly asked
    for the task.

  - "selected_order" tracks the order in which jobs have been asked for
    by the user via the "--task=" command line option. It overrides
    everything else, but only has an effect if at least one job has been
    selected.

  - "schedule" tracks the schedule priority for a job, that is how often
    it should run. This field only plays a role when the user has passed
    the "--schedule=" command line option.

All of this makes it non-trivial to figure out which job really should
be running right now. The logic to configure these fields and the logic
that interprets them is distributed across multiple functions, making it
even harder to follow it.

Refactor the logic so that we stop modifying global state. Instead, we
now compute which jobs should be run in `initialize_task_config()`,
represented as an array of jobs to run that is stored in the options
structure. Like this, all logic becomes self-contained and any users of
this array only need to iterate through the tasks and execute them one
by one.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-03 08:30:49 -07:00
Patrick Steinhardt a7c86d328f builtin/maintenance: mark "--task=" and "--schedule=" as incompatible
The "--task=" option explicitly allows the user to say which maintenance
tasks should be run, whereas "--schedule=" only respects the maintenance
strategy configured for a specific repository. As such, it is not
sensible to accept both options at the same time.

Mark them as incompatible with one another. While at it, also convert
the existing logic that marks "--auto" and "--schedule=" as incompatible
to use `die_for_incompatible_opt2()`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-03 08:30:49 -07:00
Patrick Steinhardt 1bb6bdb646 builtin/maintenance: centralize configuration of explicit tasks
Users of git-maintenance(1) can explicitly ask it to run specific tasks
by passing the `--task=` command line option. This option can be passed
multiple times, which causes us to execute tasks in the same order as
the tasks have been provided by the user.

The order in which tasks are run is computed in `task_option_parse()`:
every time we parse such a command line argument, we modify the global
array of tasks by seting the selected index for that specific task.
This has two downsides:

  - We modify global state, which makes it hard to follow the logic.

  - The configuration of tasks is split across multiple different
    functions, so it is not easy to figure out the different factors
    that play a role in selecting tasks.

Refactor the logic so that `task_option_parse()` does not modify global
state anymore. Instead, this function now only collects the list of
configured tasks. The logic to configure ordering of the respective
tasks is then deferred to `initialize_task_config()`.

This refactoring solves the second problem, that the configuration of
tasks is spread across multiple different locations. The first problem,
that we modify global state, will be fixed in a subsequent commit.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-03 08:30:49 -07:00
Patrick Steinhardt bd19b94a66 builtin/gc: drop redundant local variable
We have two different variables that track the quietness for git-gc(1):

  - The local variable `quiet`, which we wire up.

  - The `quiet` field of `struct maintenance_run_opts`.

This leads to confusion which of these variables should be used and what
the respective effect is.

Simplify this logic by dropping the local variable in favor of the
options field.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-03 08:30:48 -07:00
Patrick Steinhardt 95b5039f5b builtin/gc: use designated field initializers for maintenance tasks
Convert the array of maintenance tasks to use designated field
initializers. This makes it easier to add more fields to the struct
without having to modify all tasks.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-03 08:30:48 -07:00
Brad Smith 35ec1e2245 compat: fixes for header handling with OpenBSD / NetBSD
Handle OpenBSD and NetBSD as FreeBSD / DragonFly are. OpenBSD would
need _XOPEN_SOURCE to be set to 700. Its simpler to just not set
_XOPEN_SOURCE.

    CC strbuf.o
strbuf.c:645:6: warning: call to undeclared function 'getdelim'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
        r = getdelim(&sb->buf, &sb->alloc, term, fp);
            ^
1 warning generated.

Signed-off-by: Brad Smith <brad@comstyle.com>
Reviewed-by: Collin Funk <collin.funk1@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-03 07:36:17 -07:00
Lucas Seiki Oshiro b257adb571 MyFirstContribution: add walken.c to meson.build
Instruct in the documentation to also add an entry in meson.build for
builtin/walken.c, as currently both Meson and Make are supported.

Helped-by: Karthik Nayak <karthik.188@gmail.com>
Helped-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-02 17:28:52 -07:00
Lucas Seiki Oshiro 08c3aaf5ba MyFirstContribution: use struct repository in examples
Add the parameter `struct repository *repo` to the cmd_walken function.

Since commit 9b1cb5070f (builtin: add a repository parameter for
builtin functions, 2024-09-13), all the cmd_* have the `repo` parameter
and new commands must follow this convention, so the documentation
should also be changed.

Change the `git_config` calls to `repo_config`, also passing the `repo`
parameter, as since 036876a106 (config: hide functions using
`the_repository` by default, 2024-08-13) the non-repo config functions
are no longer recommended as they use the global `repository` variable.

Helped-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-02 17:28:52 -07:00
Collin Funk db170e1826 completion: make sed command that generates config-list.h portable.
The OpenBSD 'sed' command does not support '\n' to represent newlines in
sed expressions. This leads to the follow compiler error:

    In file included from builtin/help.c:15:
    ./config-list.h:282:18: error: use of undeclared identifier 'n'
            "gitcvs.dbUser",n       "gitcvs.dbPass",
                            ^
    1 error generated.
    gmake: *** [Makefile:2821: builtin/help.o] Error 1

We can fix this by documenting related configuration variables
one-per-line instead of listing them separated by commas. This allows us
to remove the unportable part of the sed expression in
generate-configlist.sh.

Signed-off-by: Collin Funk <collin.funk1@gmail.com>
Reviewed-by: Jacob Keller <jacob.keller@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-02 17:21:49 -07:00
Patrick Steinhardt c1bc974923 meson: parse TAP output generated by our tests
By default, Meson only knows to pay respect to the exit code of tests to
judge whether or not it ran successfully. This can be changed though by
specifying the "protocol" parameter. Next to the default "exitcode"
protocol, Meson also supports the "tap" output that our tests already
know to generate.

Unfortunately, the "tap" protocol was incompatible with `meson test
--interactive` and caused a hang. We have upstreamed a fix [1] though,
so with the recent release of Meson 1.8 that fix is finally out and we
can start using the "tap" protocol when running with a recent-enough
version of this build tool.

With this change in place, Meson now properly detects how many subtests
ran and whether test suites have been skipped:

    ```
    $ meson test t002*
    ninja: Entering directory `/home/pks/Development/git/build'
     1/10 t0024-crlf-archive                  OK              0.17s   2 subtests passed
     2/10 t0022-crlf-rename                   OK              0.18s   2 subtests passed
     3/10 t0029-core-unsetenvvars             SKIP            0.15s
     4/10 t0023-crlf-am                       OK              0.18s   2 subtests passed
     5/10 t0025-crlf-renormalize              OK              0.21s   3 subtests passed
     6/10 t0026-eol-config                    OK              0.25s   5 subtests passed
     7/10 t0020-crlf                          OK              0.81s   36 subtests passed
     8/10 t0028-working-tree-encoding         OK              0.85s   22 subtests passed
     9/10 t0021-conversion                    OK              3.45s   38 subtests passed
    10/10 t0027-auto-crlf                     OK             26.35s   2600 subtests passed

    Ok:                9
    Fail:              0
    Skipped:           1
    ```

Note that when running `meson test --interactive` the test results will
now be marked as "ignored". This is because in interactive mode the file
descriptors will remain connected to the user's terminal, and it is
expected that the user interacts with the tests (e.g., spawn a debugger
or use `test_pause`). As such, the TAP output cannot be parsed reliably
by Meson in that case, so the tests are marked as ignored accordingly.

[1]: https://github.com/mesonbuild/meson/pull/13980

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-02 07:51:43 -07:00
Patrick Steinhardt b44e63f405 meson: introduce kwargs variable for tests
Meson has the ability to create a kwargs dictionary that can then be
passed to any function call with the `kwargs:` positional argument. This
allows one to deduplicate common parameters that one wishes to pass to
several different function invocations.

Our tests already have one common parameter that we use everywhere,
"timeout", and we're about to add a second common parameter in the next
commit. Let's prepare for this by introducing `test_kwargs` so that we
can deduplicate these common arguments.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-02 07:51:43 -07:00
Patrick Steinhardt 5e0752b071 test-lib: fail on unexpectedly passing tests
When tests are executed via `test_expect_failure` we rather obviously
expect the test itself to fail. If it unexpectedly does not fail then we
count the test as a "fixed" test and announce that a known breakage has
vanished:

    ok 1 - setup
    ok 2 - create refs/heads/main # TODO known breakage vanished
    ok 3 - create refs/heads/main with oldvalue verification
    ...
    ok 299 - update-ref should also create reflog for HEAD
    # 1 known breakage(s) vanished; please update test(s)
    # passed all remaining 298 test(s)
    1..299

While we announce that tests should be updated, the overall test suite
still passes. This makes it quite hard to detect when a test that has
previously failed succeeds now as the developer needs to pay close
attention to the exact output. Even more importantly, tests that only
succeed on _some_ systems are even easier to miss now, as one would have
to explicitly take a look at respective CI jobs to notice that those do
pass now.

Furthermore, we are about to introduce support for parsing TAP output in
Meson. In contrast to prove(1), which treats unexpected passes as a
successful test run, Meson treats those as failure. Neither of these
tools is wrong in doing so. Quoting the TAP specification [1]:

    Should a todo test point begin succeeding, the harness may report it
    in some way that indicates that whatever was supposed to be done has
    been, and it should be promoted to a normal Test Point.

So it is essentially implementation-defined how exactly the unexpected
pass is reported, and whether it should cause the overall test suite to
fail or not. It is unarguably a bad thing for us though if these tools
interpret these differently, as it would mean that test results now
depend on whether the developer uses prove(1) or Meson.

Unify the behaviour by causing a test suite to fail when there are any
unexpected passes. As prove(1) does not consider an unexpected pass to
be an error this leads to somewhat funky output:

    t1400-update-ref.sh ................................ Dubious, test returned 1 (wstat 256, 0x100)
    All 299 subtests passed
            (1 TODO test unexpectedly succeeded)

    ...

    Test Summary Report
    -------------------
    t1400-update-ref.sh                              (Wstat: 256 (exited 1) Tests: 299 Failed: 0)
      TODO passed:   2
      Non-zero exit status: 1

But as we directly announce that the root cause is an unexpected TODO
that has succeeded it's not all that bad.

[1]: https://testanything.org/tap-version-14-specification.html

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-02 07:51:43 -07:00
Patrick Steinhardt d3d8c601fd t7815: fix unexpectedly passing test on macOS
In t7815, we have the following test:

    test_expect_failure !CYGWIN 'git grep .fi a' '
        git grep .fi a
    '

The test passes if '.' matches a NUL byte, which we expect to only
happen on Cygwin. The upcoming changes to support parsing TAP output in
Meson surface that this test, surprisingly, passes on macOS as well.

It is unclear how long the test has been passing on macOS already.
064eed36c7 (config.mak.uname: only set NO_REGEX on cygwin for v1.7,
2025-04-17) mentions that the test started to pass for Cygwin. This was
attributed to a new implementation of regcomp(3p) and friends, which was
inherited from FreeBSD. Given the BSD lineage of macOS it is feasible
that it also inherited similar code eventually that made the test pass
now.

It is somewhat dubious what the test actually brings to the table given
that it is quite platform specific. Ideally, we would fix this mess by
having a configure-time check whether regcomp(3p) works as expected,
including NUL bytes, and use our bundled version of the regex library in
case it doesn't. Like this, we could ensure that all platforms work the
same in this edge case and mark the new behaviour as expected.

This change is outside of the scope of this patch series, which only
introduces support for TAP. So instead of fixing the bigger issue,
ignore the test on Darwin like we already do for Cygwin.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-02 07:51:42 -07:00
Patrick Steinhardt d4ea24b8a9 t/test-lib: fix TAP format for BASH_XTRACEFD warning
When the Bash version is too old to support BASH_XTRACEFD we print a
warning to stderr. This warning is not prefixed with "#", which causes
TAP parsers to (wrongly) interpret the warning as part of the protocol.

Fix this issue by prefixing the warning with a "#" so that it is treated
as comment.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-02 07:51:42 -07:00
Patrick Steinhardt d411d3d837 t/test-lib: don't print shell traces to stdout
We have several flags like "--verbose", "--verbose-only" or "-x" that
cause us to generate shell traces. The generated tracing output is split
up in these cases so that the test's stdout is printed to file
descriptor 3 whereas its stderr is printed to file descriptor 4.
Depending on which options have been given, we then end up either:

  - Redirecting both file descriptors to a file.

  - Redirecting them to stdout and stderr, respectively.

  - Closing them in case we're running in none-verbose mode.

The second case causes problems though when passing output to a TAP
parser. We print the test's stdout to the console's stdout, and that
results in broken TAP output.

Fix the issue by instead redirecting the test's stdout to the shell's
stderr. This makes it impossible to discern stdout from stderr, but
going by my own experience I never came across a usecase where I would
have needed this distinction.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-02 07:51:42 -07:00
Patrick Steinhardt a1199a2389 t983*: use prereq to check for Python-specific git-p4(1) support
The tests in t9835 and t9836 verify that git-p4(1) works with both
Python 2 and 3, respectively. To determine whether we have those Python
versions in the first place we create a wrapper script that directly
executes the git-p4(1) script with `python2` or `python3` binaries. We
then condition the execution of tests on whether that wrapper script can
be executed successfully.

The logic that does all of this is not contained in a prerequisite block
though, so the output it generates causes us to break the TAP format.
Refactor the logic to use `test_lazy_prereq()` to fix this.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-02 07:51:42 -07:00
Patrick Steinhardt 844537091d t9822: use prereq to check for ISO-8859-1 support
Tests in t9822 depend on filesystem support for ISO-8859-1 encoding. We
thus have a block of code that acts as a prerequisite -- if we fail to
write a file with an ISO-8859-1-encoded file name to disk then we skip
all tests.

When the prerequisite fails though we end up printing an error message
to stderr, which breaks the TAP format. Fix this by converting the code
to a proper prerequisite, which handles output redirection for us.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-02 07:51:42 -07:00
Patrick Steinhardt ddfcb9d466 t: silence output from `test_create_repo()`
There are a couple users of `test_create_repo()` that use this function
outside of any test case. This function is nowadays only a thin wrapper
around `git init`, which by default prints a message to stdout that the
repository has been initialized. The resulting output may thus confuse
TAP parsers.

Refactor these users to instead create the repository in a "setup" test
case so that we don't explicitly have to silence them. There's one
exception in t1007: we use `push_repo()` and its `pop_repo()` equivalent
multiple times, so to reduce the noise introduced by this patch we
instead silence this invocation.

While at it, convert callsites to use git-init(1) directly as the
`test_create_repo()` function has been deprecated in f0d4d398e2
(test-lib: split up and deprecate test_create_repo(), 2021-05-10).

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-02 07:51:42 -07:00
Patrick Steinhardt faac9d46e0 t: stop announcing prereqs
We have a couple of cases where our tests end up announcing that a
certain prerequisite is or isn't fulfilled. While this is supposed to
help the developer it has the downside that it breaks the TAP format.

We could convert these cases to just have a "#" prefix, but it feels
rather unlikely that these are generally useful in the first place. We
already do announce why a specific test is being skipped, so we should
try to use this mechanism to the best extent possible.

Stop announcing these prereqs to fix the TAP format. Where possible,
convert the tests to rely on the prerequisites themselves to announce
why a test ran or didn't ran.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-02 07:51:41 -07:00
Brad Smith d584219107 config.mak.uname: update settings for OpenBSD
OpenBSD requires DIR_HAS_BSD_GROUP_SEMANTICS.

OpenBSD has never had the BSD sysctl KERN_PROC_PATHNAME nor
does it support or use the /proc filesystem.

OpenBSD has had strcasestr() since 3.8. OpenBSD has had memmem()
since 5.4.

Signed-off-by: Brad Smith <brad@comstyle.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-06-01 21:57:38 -07:00
Mark Mentovai 2d207ed1ec t: run tests from a normalized working directory
Some tests make git perform actions that produce observable pathnames,
and have expectations on those paths. Tests run with $HOME set to a
$TRASH_DIRECTORY, and with their working directory the same
$TRASH_DIRECTORY, although these paths are logically identical, they do
not observe the same pathname canonicalization rules and thus might not
be represented by strings that compare equal. In particular, no pathname
normalization is applied to $TRASH_DIRECTORY or $HOME, while tests
change their working directory with `cd -P`, which normalizes the
working directory's path by fully resolving symbolic links.

t7900's macOS maintenance tests (which are not limited to running on
macOS) have an expectation on a path that `git maintenance` forms by
using abspath.c strbuf_realpath() to resolve a canonical absolute path
based on $HOME. When t7900 runs from a working directory that contains
symbolic links in its pathname, $HOME will also contain symbolic links,
which `git maintenance` resolves but the test's expectation does not,
causing a test failure.

Align $TRASH_DIRECTORY and $HOME with the normalized path as used for
the working directory by resetting them to match the working directory
after it's established by `cd -P`. With all paths in agreement and
symbolic links resolved, pathname expectations can be set and met based
on string comparison without regard to external environmental factors
such as the presence of symbolic links in a path.

Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Mark Mentovai <mark@chromium.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-30 14:55:03 -07:00
Aditya Garg 9e68aaba45 docs: make the purpose of using app password for Gmail more clear in send-email
The current example for Gmail suggests using app passwords for
send-email if user has multi-factor authentication set up for their
account. However, it does not clarify that the user cannot use their
normal password in case they do not have multi-factor authentication
enabled. Most likely the example was written in the days when Google
allowed using normal passwords without multi-factor authentication.

Clarify that regular passwords do not work for Gmail and app-passwords
are the only way for basic authentication. Also encourage users to use
OAuth2.0 as a more secure alternative.

While at it, also prefer using the word "mechanism" over "method" for
`OAUTHBEARER` and `XOAUTH2` since that is what official docs use.

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-30 10:23:38 -07:00
Aditya Garg 6cae42c189 docs: remove credential helper links for emails from gitcredentials
In a recent attempt to add links of email helpers to git-scm.com [1], I
came to a conclusion that the links in the gitcredentials page are meant
for people needing credential helpers for cloning, fetching and pushing
repositories to remote hosts, and not sending emails. gitcredentials
docs don't even talk about send emails, thus confirming this view.

So, lets remove these links from the gitcredentials page. The links are
still available in the git-send-email documentation, which is the right
place for them.

[1]: https://github.com/git/git-scm.com/pull/2005

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-30 10:23:37 -07:00
Aditya Garg 394c190495 docs: improve formatting in git-send-email documentation
The current documentation for git-send-email had an inconsistent use of
"", ``, and '' for quoting. This commit improves the formatting by
using the same style throughout the documentation. Missing full stops
have also been added at some places.

Finally, the cpan links of necessary perl modules have been added to
make their installation easier.

While at it, the unecessary use of $ with <num> and <int> placeholders
has also been removed.

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-30 10:23:37 -07:00
Aditya Garg 200d74711f docs: add credential helper for yahoo and link Google's sendgmail tool
This commit links `git-credential-yahoo` as a credential helper for
Yahoo accounts. Also, Google's `sendgmail` tool has been linked as an
alternative method for sending emails through Gmail.

Signed-off-by: Aditya Garg <gargaditya08@live.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-30 10:23:36 -07:00
Rodrigo Carvalho 1d9526df8d userdiff: add support for R programming language
Add userdiff patterns to support R programming language.

Also, add three userdiff tests for R programming language
files. These files define simple function and nested function,
with and without indentation.

Signed-off-by: Rodrigo Carvalho <rodrigorsdc@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-29 15:29:37 -07:00
Alexander Shopov 1c3c7b19a2 l10n: bg.po: Updated Bulgarian translation (5819t)
Signed-off-by: Alexander Shopov <ash@kambanaria.org>
2025-05-29 22:12:48 +02:00
Emir SARI 2140ff4591
l10n: tr: Update Turkish translations for 2.50
Signed-off-by: Emir SARI <emir_sari@icloud.com>
2025-05-29 14:27:15 +03:00
Jean-Noël Avila 49c4d5c3b5 l10n: fr: v2.50 round 1
Signed-off-by: Jean-Noël Avila <jn.avila@free.fr>
2025-05-29 12:58:38 +02:00
Aindriú Mac Giolla Eoin bf5ce434db l10n: Add full Irish translation (ga.po)
- Added complete Irish translation (ga.po).
- Added entry for Irish in po/TEAMS.
- Corrected email format and removed trailing whitespace.
- Translated new strings from Git 2.50.0-rc0

Signed-off-by: Aindriú Mac Giolla Eoin <aindriu80@gmail.com>
2025-05-29 10:15:04 +01:00
Taylor Blau fbae1f06cb Git 2.48.2
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-28 15:18:19 -04:00
Taylor Blau 856b515a46 Sync with 2.47.3
* maint-2.47:
  Git 2.47.3
  Git 2.46.4
  Git 2.45.4
  Git 2.44.4
  Git 2.43.7
  wincred: avoid buffer overflow in wcsncat()
  bundle-uri: fix arbitrary file writes via parameter injection
  config: quote values containing CR character
  git-gui: sanitize 'exec' arguments: convert new 'cygpath' calls
  git-gui: do not mistake command arguments as redirection operators
  git-gui: introduce function git_redir for git calls with redirections
  git-gui: pass redirections as separate argument to git_read
  git-gui: pass redirections as separate argument to _open_stdout_stderr
  git-gui: convert git_read*, git_write to be non-variadic
  git-gui: override exec and open only on Windows
  gitk: sanitize 'open' arguments: revisit recently updated 'open' calls
  git-gui: use git_read in githook_read
  git-gui: sanitize $PATH on all platforms
  git-gui: break out a separate function git_read_nice
  git-gui: assure PATH has only absolute elements.
  git-gui: remove option --stderr from git_read
  git-gui: cleanup git-bash menu item
  git-gui: sanitize 'exec' arguments: background
  git-gui: avoid auto_execok in do_windows_shortcut
  git-gui: sanitize 'exec' arguments: simple cases
  git-gui: avoid auto_execok for git-bash menu item
  git-gui: treat file names beginning with "|" as relative paths
  git-gui: remove unused proc is_shellscript
  git-gui: remove git config --list handling for git < 1.5.3
  git-gui: remove special treatment of Windows from open_cmd_pipe
  git-gui: remove HEAD detachment implementation for git < 1.5.3
  git-gui: use only the configured shell
  git-gui: remove Tcl 8.4 workaround on 2>@1 redirection
  git-gui: make _shellpath usable on startup
  git-gui: use [is_Windows], not bad _shellpath
  git-gui: _which, only add .exe suffix if not present
  gitk: encode arguments correctly with "open"
  gitk: sanitize 'open' arguments: command pipeline
  gitk: collect construction of blameargs into a single conditional
  gitk: sanitize 'open' arguments: simple commands, readable and writable
  gitk: sanitize 'open' arguments: simple commands with redirections
  gitk: sanitize 'open' arguments: simple commands
  gitk: sanitize 'exec' arguments: redirect to process
  gitk: sanitize 'exec' arguments: redirections and background
  gitk: sanitize 'exec' arguments: redirections
  gitk: sanitize 'exec' arguments: 'eval exec'
  gitk: sanitize 'exec' arguments: simple cases
  gitk: have callers of diffcmd supply pipe symbol when necessary
  gitk: treat file names beginning with "|" as relative paths
2025-05-28 15:17:05 -04:00
Taylor Blau a52a24e03c Git 2.47.3
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-28 15:16:03 -04:00
Taylor Blau 0991bd0023 Sync with 2.46.4
* maint-2.46:
  Git 2.46.4
  Git 2.45.4
  Git 2.44.4
  Git 2.43.7
  wincred: avoid buffer overflow in wcsncat()
  bundle-uri: fix arbitrary file writes via parameter injection
  config: quote values containing CR character
  git-gui: sanitize 'exec' arguments: convert new 'cygpath' calls
  git-gui: do not mistake command arguments as redirection operators
  git-gui: introduce function git_redir for git calls with redirections
  git-gui: pass redirections as separate argument to git_read
  git-gui: pass redirections as separate argument to _open_stdout_stderr
  git-gui: convert git_read*, git_write to be non-variadic
  git-gui: override exec and open only on Windows
  gitk: sanitize 'open' arguments: revisit recently updated 'open' calls
  git-gui: use git_read in githook_read
  git-gui: sanitize $PATH on all platforms
  git-gui: break out a separate function git_read_nice
  git-gui: assure PATH has only absolute elements.
  git-gui: remove option --stderr from git_read
  git-gui: cleanup git-bash menu item
  git-gui: sanitize 'exec' arguments: background
  git-gui: avoid auto_execok in do_windows_shortcut
  git-gui: sanitize 'exec' arguments: simple cases
  git-gui: avoid auto_execok for git-bash menu item
  git-gui: treat file names beginning with "|" as relative paths
  git-gui: remove unused proc is_shellscript
  git-gui: remove git config --list handling for git < 1.5.3
  git-gui: remove special treatment of Windows from open_cmd_pipe
  git-gui: remove HEAD detachment implementation for git < 1.5.3
  git-gui: use only the configured shell
  git-gui: remove Tcl 8.4 workaround on 2>@1 redirection
  git-gui: make _shellpath usable on startup
  git-gui: use [is_Windows], not bad _shellpath
  git-gui: _which, only add .exe suffix if not present
  gitk: encode arguments correctly with "open"
  gitk: sanitize 'open' arguments: command pipeline
  gitk: collect construction of blameargs into a single conditional
  gitk: sanitize 'open' arguments: simple commands, readable and writable
  gitk: sanitize 'open' arguments: simple commands with redirections
  gitk: sanitize 'open' arguments: simple commands
  gitk: sanitize 'exec' arguments: redirect to process
  gitk: sanitize 'exec' arguments: redirections and background
  gitk: sanitize 'exec' arguments: redirections
  gitk: sanitize 'exec' arguments: 'eval exec'
  gitk: sanitize 'exec' arguments: simple cases
  gitk: have callers of diffcmd supply pipe symbol when necessary
  gitk: treat file names beginning with "|" as relative paths

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-28 14:59:31 -04:00
Taylor Blau 47d3b506d4 Git 2.46.4
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-28 14:58:48 -04:00
Taylor Blau 199837cd4d Sync with 2.45.4
* maint-2.45:
  Git 2.45.4
  Git 2.44.4
  Git 2.43.7
  wincred: avoid buffer overflow in wcsncat()
  bundle-uri: fix arbitrary file writes via parameter injection
  config: quote values containing CR character
  git-gui: sanitize 'exec' arguments: convert new 'cygpath' calls
  git-gui: do not mistake command arguments as redirection operators
  git-gui: introduce function git_redir for git calls with redirections
  git-gui: pass redirections as separate argument to git_read
  git-gui: pass redirections as separate argument to _open_stdout_stderr
  git-gui: convert git_read*, git_write to be non-variadic
  git-gui: override exec and open only on Windows
  gitk: sanitize 'open' arguments: revisit recently updated 'open' calls
  git-gui: use git_read in githook_read
  git-gui: sanitize $PATH on all platforms
  git-gui: break out a separate function git_read_nice
  git-gui: assure PATH has only absolute elements.
  git-gui: remove option --stderr from git_read
  git-gui: cleanup git-bash menu item
  git-gui: sanitize 'exec' arguments: background
  git-gui: avoid auto_execok in do_windows_shortcut
  git-gui: sanitize 'exec' arguments: simple cases
  git-gui: avoid auto_execok for git-bash menu item
  git-gui: treat file names beginning with "|" as relative paths
  git-gui: remove unused proc is_shellscript
  git-gui: remove git config --list handling for git < 1.5.3
  git-gui: remove special treatment of Windows from open_cmd_pipe
  git-gui: remove HEAD detachment implementation for git < 1.5.3
  git-gui: use only the configured shell
  git-gui: remove Tcl 8.4 workaround on 2>@1 redirection
  git-gui: make _shellpath usable on startup
  git-gui: use [is_Windows], not bad _shellpath
  git-gui: _which, only add .exe suffix if not present
  gitk: encode arguments correctly with "open"
  gitk: sanitize 'open' arguments: command pipeline
  gitk: collect construction of blameargs into a single conditional
  gitk: sanitize 'open' arguments: simple commands, readable and writable
  gitk: sanitize 'open' arguments: simple commands with redirections
  gitk: sanitize 'open' arguments: simple commands
  gitk: sanitize 'exec' arguments: redirect to process
  gitk: sanitize 'exec' arguments: redirections and background
  gitk: sanitize 'exec' arguments: redirections
  gitk: sanitize 'exec' arguments: 'eval exec'
  gitk: sanitize 'exec' arguments: simple cases
  gitk: have callers of diffcmd supply pipe symbol when necessary
  gitk: treat file names beginning with "|" as relative paths

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-28 14:57:08 -04:00
Taylor Blau f94b90ad6e Git 2.45.4
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-28 14:54:04 -04:00
Taylor Blau 3e10fb5eb4 Sync with 2.44.4
* maint-2.44:
  Git 2.44.4
  Git 2.43.7
  wincred: avoid buffer overflow in wcsncat()
  bundle-uri: fix arbitrary file writes via parameter injection
  config: quote values containing CR character
  git-gui: sanitize 'exec' arguments: convert new 'cygpath' calls
  git-gui: do not mistake command arguments as redirection operators
  git-gui: introduce function git_redir for git calls with redirections
  git-gui: pass redirections as separate argument to git_read
  git-gui: pass redirections as separate argument to _open_stdout_stderr
  git-gui: convert git_read*, git_write to be non-variadic
  git-gui: override exec and open only on Windows
  gitk: sanitize 'open' arguments: revisit recently updated 'open' calls
  git-gui: use git_read in githook_read
  git-gui: sanitize $PATH on all platforms
  git-gui: break out a separate function git_read_nice
  git-gui: assure PATH has only absolute elements.
  git-gui: remove option --stderr from git_read
  git-gui: cleanup git-bash menu item
  git-gui: sanitize 'exec' arguments: background
  git-gui: avoid auto_execok in do_windows_shortcut
  git-gui: sanitize 'exec' arguments: simple cases
  git-gui: avoid auto_execok for git-bash menu item
  git-gui: treat file names beginning with "|" as relative paths
  git-gui: remove unused proc is_shellscript
  git-gui: remove git config --list handling for git < 1.5.3
  git-gui: remove special treatment of Windows from open_cmd_pipe
  git-gui: remove HEAD detachment implementation for git < 1.5.3
  git-gui: use only the configured shell
  git-gui: remove Tcl 8.4 workaround on 2>@1 redirection
  git-gui: make _shellpath usable on startup
  git-gui: use [is_Windows], not bad _shellpath
  git-gui: _which, only add .exe suffix if not present
  gitk: encode arguments correctly with "open"
  gitk: sanitize 'open' arguments: command pipeline
  gitk: collect construction of blameargs into a single conditional
  gitk: sanitize 'open' arguments: simple commands, readable and writable
  gitk: sanitize 'open' arguments: simple commands with redirections
  gitk: sanitize 'open' arguments: simple commands
  gitk: sanitize 'exec' arguments: redirect to process
  gitk: sanitize 'exec' arguments: redirections and background
  gitk: sanitize 'exec' arguments: redirections
  gitk: sanitize 'exec' arguments: 'eval exec'
  gitk: sanitize 'exec' arguments: simple cases
  gitk: have callers of diffcmd supply pipe symbol when necessary
  gitk: treat file names beginning with "|" as relative paths

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-28 14:51:38 -04:00
Taylor Blau 080b728d4b Git 2.44.4
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-28 14:51:12 -04:00
Taylor Blau a162459bf6 Sync with 2.43.7
* maint-2.43:
  Git 2.43.7
  wincred: avoid buffer overflow in wcsncat()
  bundle-uri: fix arbitrary file writes via parameter injection
  config: quote values containing CR character
  git-gui: sanitize 'exec' arguments: convert new 'cygpath' calls
  git-gui: do not mistake command arguments as redirection operators
  git-gui: introduce function git_redir for git calls with redirections
  git-gui: pass redirections as separate argument to git_read
  git-gui: pass redirections as separate argument to _open_stdout_stderr
  git-gui: convert git_read*, git_write to be non-variadic
  git-gui: override exec and open only on Windows
  gitk: sanitize 'open' arguments: revisit recently updated 'open' calls
  git-gui: use git_read in githook_read
  git-gui: sanitize $PATH on all platforms
  git-gui: break out a separate function git_read_nice
  git-gui: assure PATH has only absolute elements.
  git-gui: remove option --stderr from git_read
  git-gui: cleanup git-bash menu item
  git-gui: sanitize 'exec' arguments: background
  git-gui: avoid auto_execok in do_windows_shortcut
  git-gui: sanitize 'exec' arguments: simple cases
  git-gui: avoid auto_execok for git-bash menu item
  git-gui: treat file names beginning with "|" as relative paths
  git-gui: remove unused proc is_shellscript
  git-gui: remove git config --list handling for git < 1.5.3
  git-gui: remove special treatment of Windows from open_cmd_pipe
  git-gui: remove HEAD detachment implementation for git < 1.5.3
  git-gui: use only the configured shell
  git-gui: remove Tcl 8.4 workaround on 2>@1 redirection
  git-gui: make _shellpath usable on startup
  git-gui: use [is_Windows], not bad _shellpath
  git-gui: _which, only add .exe suffix if not present
  gitk: encode arguments correctly with "open"
  gitk: sanitize 'open' arguments: command pipeline
  gitk: collect construction of blameargs into a single conditional
  gitk: sanitize 'open' arguments: simple commands, readable and writable
  gitk: sanitize 'open' arguments: simple commands with redirections
  gitk: sanitize 'open' arguments: simple commands
  gitk: sanitize 'exec' arguments: redirect to process
  gitk: sanitize 'exec' arguments: redirections and background
  gitk: sanitize 'exec' arguments: redirections
  gitk: sanitize 'exec' arguments: 'eval exec'
  gitk: sanitize 'exec' arguments: simple cases
  gitk: have callers of diffcmd supply pipe symbol when necessary
  gitk: treat file names beginning with "|" as relative paths

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-28 14:47:12 -04:00
Taylor Blau 7a1903ad46 Git 2.43.7
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-28 14:42:12 -04:00
Taylor Blau 32c93d5935 Merge branch 'tb/wincred-buffer-overflow' into maint-2.43
This merges in the fix for CVE-2025-48386.

* tb/wincred-buffer-overflow:
  wincred: avoid buffer overflow in wcsncat()

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-28 14:33:35 -04:00
Taylor Blau 9de345cb27 wincred: avoid buffer overflow in wcsncat()
The wincred credential helper uses a static buffer ("target") as a
unique key for storing and comparing against internal storage. It does
this by building up a string is supposed to look like:

    git:$PROTOCOL://$USERNAME@$HOST/@PATH

However, the static "target" buffer is declared as a wide string with no
more than 1,024 wide characters. The first call to wcsncat() is almost
correct (it copies no more than ARRAY_SIZE(target) wchar_t's), but does
not account for the trailing NUL, introducing an off-by-one error.

But subsequent calls to wcsncat() have an additional problem on top of
the off-by-one. They do not account for the length of the existing
wide string being built up in 'target'. So the following:

    $ perl -e '
        my $x = "x" x 1_000;
        print "protocol=$x\nhost=$x\nusername=$x\npath=$x\n"
      ' |
      C\:/Program\ Files/Git/mingw64/libexec/git-core/git-credential-wincred.exe get

will result in a segmentation fault from over-filling buffer.

This bug is as old as the wincred helper itself, dating back to
a6253da0f3 (contrib: add win32 credential-helper, 2012-07-27). Commit
8b2d219a3d (wincred: improve compatibility with windows versions,
2013-01-10) replaced the use of strncat() with wcsncat(), but retained
the buggy behavior.

Fix this by using a "target_append()" helper which accounts for both the
length of the existing string within the buffer, as well as the trailing
NUL character.

Reported-by: David Leadbeater <dgl@dgl.cx>
Helped-by: David Leadbeater <dgl@dgl.cx>
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-28 12:57:36 -04:00
Taylor Blau 2d22f0cd07 Merge branch 'jt/config-quote-cr' into maint-2.43
This merges in the fix for CVE-2025-48384.

* jt/config-quote-cr:
  config: quote values containing CR character

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-28 12:55:15 -04:00
Taylor Blau d2bc61fcab Merge branch 'ps/bundle-uri-arbitrary-writes' into maint-2.43
This merges in the fix for CVE-2025-48385.

* ps/bundle-uri-arbitrary-writes:
  bundle-uri: fix arbitrary file writes via parameter injection

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-28 12:54:03 -04:00
Taylor Blau d61cfed2c2 Merge branch 'js/gitk-git-gui-harden-exec-open' into maint-2.43
This merges in fixes for CVE-2025-27614, CVE-2025-27613, CVE-2025-46334,
and CVE-2025-46835 targeting Gitk and Git GUI.

* js/gitk-git-gui-harden-exec-open: (41 commits)
  git-gui: sanitize 'exec' arguments: convert new 'cygpath' calls
  git-gui: do not mistake command arguments as redirection operators
  git-gui: introduce function git_redir for git calls with redirections
  git-gui: pass redirections as separate argument to git_read
  git-gui: pass redirections as separate argument to _open_stdout_stderr
  git-gui: convert git_read*, git_write to be non-variadic
  git-gui: override exec and open only on Windows
  gitk: sanitize 'open' arguments: revisit recently updated 'open' calls
  git-gui: use git_read in githook_read
  git-gui: sanitize $PATH on all platforms
  git-gui: break out a separate function git_read_nice
  git-gui: assure PATH has only absolute elements.
  git-gui: remove option --stderr from git_read
  git-gui: cleanup git-bash menu item
  git-gui: sanitize 'exec' arguments: background
  git-gui: avoid auto_execok in do_windows_shortcut
  git-gui: sanitize 'exec' arguments: simple cases
  git-gui: avoid auto_execok for git-bash menu item
  git-gui: treat file names beginning with "|" as relative paths
  git-gui: remove unused proc is_shellscript
  git-gui: remove git config --list handling for git < 1.5.3
  git-gui: remove special treatment of Windows from open_cmd_pipe
  git-gui: remove HEAD detachment implementation for git < 1.5.3
  git-gui: use only the configured shell
  git-gui: remove Tcl 8.4 workaround on 2>@1 redirection
  git-gui: make _shellpath usable on startup
  git-gui: use [is_Windows], not bad _shellpath
  git-gui: _which, only add .exe suffix if not present
  gitk: encode arguments correctly with "open"
  gitk: sanitize 'open' arguments: command pipeline
  gitk: collect construction of blameargs into a single conditional
  gitk: sanitize 'open' arguments: simple commands, readable and writable
  gitk: sanitize 'open' arguments: simple commands with redirections
  gitk: sanitize 'open' arguments: simple commands
  gitk: sanitize 'exec' arguments: redirect to process
  gitk: sanitize 'exec' arguments: redirections and background
  gitk: sanitize 'exec' arguments: redirections
  gitk: sanitize 'exec' arguments: 'eval exec'
  gitk: sanitize 'exec' arguments: simple cases
  gitk: have callers of diffcmd supply pipe symbol when necessary
  gitk: treat file names beginning with "|" as relative paths
  ...

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-28 12:48:38 -04:00
Patrick Steinhardt' via Git Security 35cb1bb0b9 bundle-uri: fix arbitrary file writes via parameter injection
We fetch bundle URIs via `download_https_uri_to_file()`. The logic to
fetch those bundles is not handled in-process, but we instead use a
separate git-remote-https(1) process that performs the fetch for us. The
information about which file should be downloaded and where that file
should be put gets communicated via stdin of that process via a "get"
request. This "get" request has the form "get $uri $file\n\n". As may be
obvious to the reader, this will cause git-remote-https(1) to download
the URI "$uri" and put it into "$file".

The fact that we are using plain spaces and newlines as separators for
the request arguments means that we have to be extra careful with the
respective vaules of these arguments:

  - If "$uri" contained a space we would interpret this as both URI and
    target location.

  - If either "$uri" or "$file" contained a newline we would interpret
    this as a new command.

But we neither quote the arguments such that any characters with special
meaning would be escaped, nor do we verify that none of these special
characters are contained.

If either the URI or file contains a newline character, we are open to
protocol injection attacks. Likewise, if the URI itself contains a
space, then an attacker-controlled URI can lead to partially-controlled
file writes.

Note that the attacker-controlled URIs do not permit completely
arbitrary file writes, but instead allows an attacker to control the
path in which we will write a temporary (e.g., "tmp_uri_XXXXXX")
file.

The result is twofold:

  - By adding a space in "$uri" we can control where exactly a file will
    be written to, including out-of-repository writes. The final
    location is not completely arbitrary, as the injected string will be
    concatenated with the original "$file" path. Furthermore, the name
    of the bundle will be "tmp_uri_XXXXXX", further restricting what an
    adversary would be able to write.

    Also note that is not possible for the URI to contain a newline
    because we end up in `credential_from_url_1()` before we try to
    issue any requests using that URI. As such, it is not possible to
    inject arbitrary commands via the URI.

  - By adding a newline to "$file" we can inject arbitrary commands.
    This gives us full control over where a specific file will be
    written to. Potential attack vectors would be to overwrite hooks,
    but if an adversary were to guess where the user's home directory is
    located they might also easily write e.g. a "~/.profile" file and
    thus cause arbitrary code execution.

    This injection can only become possible when the adversary has full
    control over the target path where a bundle will be downloaded to.
    While this feels unlikely, it is possible to control this path when
    users perform a recursive clone with a ".gitmodules" file that is
    controlled by the adversary.

Luckily though, the use of bundle URIs is not enabled by default in Git
clients (yet): they have to be enabled by setting the `bundle.heuristic`
config key explicitly. As such, the blast radius of this parameter
injection should overall be quite contained.

Fix the issue by rejecting spaces in the URI and newlines in both the
URI and the file. As explained, it shouldn't be required to also
restrict the use of newlines in the URI, as we would eventually die
anyway in `credential_from_url_1()`. But given that we're only one small
step away from arbitrary code execution, let's rather be safe and
restrict newlines in URIs, as well.

Eventually we should probably refactor the way that Git talks with the
git-remote-https(1) subprocess so that it is less fragile. Until then,
these two restrictions should plug the issue.

Reported-by: David Leadbeater <dgl@dgl.cx>
Based-on-patch-by: David Leadbeater <dgl@dgl.cx>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:09:48 -04:00
Justin Tobler 05e9cd64ee config: quote values containing CR character
When reading the config, values that contain a trailing CRLF are
stripped. If the value itself has a trailing CR, the normal LF that
follows results in the CR being unintentionally stripped. This may lead
to unintended behavior due to the config value written being different
when it gets read.

One such issue involves a repository with a submodule path containing a
trailing CR. When the submodule gets initialized, the submodule is
cloned without being checked out and has "core.worktree" set to the
submodule path. The git-checkout(1) that gets spawned later reads the
"core.worktree" config value, but without the trailing CR, and
consequently attempts to checkout to a different path than intended.

If the repository contains a matching path that is a symlink, it is
possible for the submodule repository to be checked out in arbitrary
locations. This is extra bad when the symlink points to the submodule
hooks directory and the submodule repository contains an executable
"post-checkout" hook. Once the submodule repository checkout completes,
the "post-checkout" hook immediately executes.

To prevent mismatched config state due to misinterpreting a trailing CR,
wrap config values containing CR in double quotes when writing the
entry. This ensures a trailing CR is always separated for an LF and thus
prevented from getting stripped.

Note that this problem cannot be addressed by just quoting each CR with
"\r". The reading side of the config interprets only a few backslash
escapes, and "\r" is not among them. This fix is sufficient though
because it only affects the CR at the end of a line and any literal CR
in the interior is already preserved.

Co-authored-by: David Leadbeater <dgl@dgl.cx>
Signed-off-by: Justin Tobler <jltobler@gmail.com>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:07:55 -04:00
Johannes Sixt 311d9ada3a Merge branch 'js/fix-open-exec'
This addresses CVE-2025-46835, Git GUI can create and overwrite a
user's files:

When a user clones an untrusted repository and is tricked into editing
a file located in a maliciously named directory in the repository, then
Git GUI can create and overwrite files for which the user has write
permission.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
2025-05-23 17:04:31 -04:00
Johannes Sixt a7d1716fa6 Merge branch 'ml/replace-auto-execok'
This addresses CVE-2025-46334, Git GUI malicious command injection on
Windows.

A malicious repository can ship versions of sh.exe or typical textconv
filter programs such as astextplain.  Due to the unfortunate design of
Tcl on Windows, the search path when looking for an executable always
includes the current directory.  The mentioned programs are invoked when
the user selects "Git Bash" or "Browse Files" from the menu.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
2025-05-23 17:04:30 -04:00
Johannes Sixt a437f5bc93 git-gui: sanitize 'exec' arguments: convert new 'cygpath' calls
The side branch merged in the previous commit introduces new 'exec'
calls. Convert these in the same way we did earlier for existing
'exec' calls.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:30 -04:00
Johannes Sixt 27fbab4898 Merge branch 'js/fix-open-exec'
This addresses CVE-2025-27613, Gitk can create and truncate a user's
files:

When a user clones an untrusted repository and runs gitk without
additional command arguments, files for which the user has write
permission can be created and truncated. The option "Support per-file
encoding" must have been enabled before in Gitk's Preferences.  This
option is disabled by default.

The same happens when "Show origin of this line" is used in the main
window (regardless of whether "Support per-file encoding" is enabled or
not).

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
2025-05-23 17:04:30 -04:00
Johannes Sixt 4e7e3b792e Merge branch 'ah/fix-open-with-stdin'
This addresses CVE-2025-27614, Arbitrary command execution with Gitk:

A Git repository can be crafted in such a way that with some social
engineering a user who has cloned the repository can be tricked into
running any script (e.g., Bourne shell, Perl, Python, ...) supplied by
the attacker by invoking `gitk filename`, where `filename` has a
particular structure. The script is run with the privileges of the user.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
2025-05-23 17:04:30 -04:00
Taylor Blau afca9a4fb4 Merge branch 'ml/replace-auto-execok' into js/fix-open-exec
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:27 -04:00
Johannes Sixt 44e3935d53 git-gui: do not mistake command arguments as redirection operators
Tcl 'open' assigns special meaning to its argument when they begin with
redirection, pipe or background operator. There are many calls of the
'open' variant that runs a process which construct arguments that are
taken from the Git repository or are user input. However, when file
names or ref names are taken from the repository, it is possible to
find names that have these special forms. They must not be interpreted
by 'open' lest it redirects input or output, or attempts to build a
pipeline using a command name controlled by the repository.

Use the helper function make_arglist_safe, which identifies such
arguments and prepends "./" to force such a name to be regarded as a
relative file name.

After this change the following 'open' calls that start a process do not
apply the argument processing:

git-gui.sh:4095:         || [catch {set spell_fd [open $spell_cmd r+]} spell_err]} {
lib/spellcheck.tcl:47:                                          set pipe_fd [open [list | $s_prog -v] r]
lib/spellcheck.tcl:133:         _connect $this [open $spell_cmd r+]
lib/spellcheck.tcl:405:         set fd [open [list | aspell dump dicts] r]

In all cases, the command arguments are constant strings (or begin with
a constant string) that are of a form that would not be affected by the
processing anyway.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:24 -04:00
Johannes Sixt 99f7bc1af6 git-gui: introduce function git_redir for git calls with redirections
Proc git invokes git and collects all output, which is it returns.
We are going to treat command arguments and redirections differently to
avoid passing arguments that look like redirections to the command
accidentally. A few invocations also pass redirection operators as
command arguments deliberately. Rewrite these cases to use a new
function git_redir that takes two lists, one for the regular command
arguments and one for the redirection operations.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:24 -04:00
Johannes Sixt 60b0ba0a04 git-gui: pass redirections as separate argument to git_read
We are going to treat command arguments and redirections differently to
avoid passing arguments that look like redirections to the command
accidentally. To do so, it will be necessary to know which arguments
are intentional redirections. Rewrite direct call sites of git_read
to pass intentional redirections as a second (optional) argument.

git_read defers to safe_open_command, but we cannot make it safe, yet,
because one of the callers of git_read is proc git, which does not yet
know which of its arguments are redirections. This is the topic of the
next commit.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:24 -04:00
Johannes Sixt 1e0a93c3d3 git-gui: pass redirections as separate argument to _open_stdout_stderr
We are going to treat command arguments and redirections differently to
avoid passing arguments that look like redirections to the command
accidentally. To do so, it will be necessary to know which arguments
are intentional redirections. Rewrite direct callers of
_open_stdout_stderr to pass intentional redirections as a second
(optional) argument.

Passing arbitrary arguments is not safe right now, but we rename it
to safe_open_command anyway to avoid having to touch the call sites
again later when we make it actually safe.

We cannot make the function safe right away because one caller is
git_read, which does not yet know which of its arguments are
redirections. This is the topic of the next commit.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:24 -04:00
Johannes Sixt dc9ecb1aab git-gui: convert git_read*, git_write to be non-variadic
We are going to treat command arguments and redirections differently to
avoid passing arguments that look like redirections to the command
accidentally. To do so, it will be necessary to know which arguments
are intentional redirections. As a preparation, convert git_read,
git_read_nice, and git_write to take just a single argument that is
the command in a list. Adjust all call sites accordingly.

In the future, this argument will be the regular command arguments and
a second argument will be the redirection operations.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:24 -04:00
Mark Levedahl a1ccd25120 git-gui: override exec and open only on Windows
Since aae9560a35 (Work around Tcl's default `PATH` lookup,
2022-11-23), git-gui overrides exec and open on all platforms. But,
this was done in response to Tcl adding elements to $PATH on Windows,
while exec, open, and auto_execok honor $PATH as given on all other
platforms.

Let's do the override only on Windows, restoring others to using their
native exec and open. These honor the sanitized $PATH as that is written
out to env(PATH) in a previous commit. auto_execok is also safe on these
platforms, so can be used for _which.

Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Johannes Sixt 67a128b91e gitk: sanitize 'open' arguments: revisit recently updated 'open' calls
The previous commits bb5cb23daf (gitk: prevent overly long command
lines, 2023-01-24) rewrote a set of the 'open' calls substantially.
These were then later updated by 7dd272eca1 (gitk: escape file paths
before piping to git log, 2023-01-24) and d5d1b91e5327 (gitk: encode
arguments correctly with "open", 2025-03-07). In the preceding merge,
the conversions to a safe_open variant were undone to ensure that the
principal operation of the new 'open' calls is not modified by accident.

Since the 'open' calls now pass a redirection from a Tcl string as
stdin, convert the calls to 'safe_open_command_redirect'.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Johannes Sixt 074c2b9d7c git-gui: use git_read in githook_read
0730a5a3a5 ("git-gui - use git-hook, honor core.hooksPath", 2023-09-17)
rewrote githook_read to use `git hook` to run a hook script. The code
that was replaced discovered the hook script file manually and invoked
it using function _open_stdout_stderr. After the rewrite, this function
is still invoked, but it calls into `git` instead of the hook scripts.

Notice though, that we have function git_read that invokes git and
prepares a pipe for the caller to read from. Replace the implementation
of githook_read to be just a wrapper around git_read. This unifies the
way in which the git executable is invoked. git_read ultimately also
calls into _open_stdout_stderr, but it modifies the path to the git
executable before doing so.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Mark Levedahl 384b1409e8 git-gui: sanitize $PATH on all platforms
Since 8f23432b38 (windows: ignore empty `PATH` elements, 2022-11-23),
git-gui removes empty elements from $PATH, and a prior commit made this
remove all non-absolute elements from $PATH. But, this happens only on
Windows. Unsafe $PATH elements in $PATH are possible on all platforms.
Let's sanitize $PATH on all platforms to have consistent behavior. If a
user really wants the current repository on $PATH, they can add its
absolute name to $PATH.

Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Johannes Sixt aa42e87ef4 git-gui: break out a separate function git_read_nice
There are two callers of git_read that request special treatment using
option --nice. Rewrite them to call a new function git_read_nice that
does the special treatment. Now we can remove all option treatment from
git_read.

git_write has the same capability, but there are no callers that
request --nice. Remove the feature without substitution.

This is a preparation for a later change where we want to make git_read
and friends non-variadic. Then it cannot have optional arguments.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Mark Levedahl 8fe7861c51 git-gui: assure PATH has only absolute elements.
Since 8f23432b38 (windows: ignore empty `PATH` elements, 2022-11-23),
git-gui excises all empty paths from $PATH, but still allows '.' or
other relative paths, which can also allow executing code from the
repository. Let's remove anything except absolute elements. While here,
let's remove duplicated elements, which are very common on Windows:
only the first such item can do anything except waste time repeating a
search.

Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Johannes Sixt 23ba43256b git-gui: remove option --stderr from git_read
Some callers of git_read want to redirect stderr of the invoked command
to stdout.  The function offers option --stderr for this purpose.
However, the option only appends 2>@1 to the commands.  The callers can
do that themselves. In lib/console.tcl we even have a caller that
already knew implictly what --stderr does behind the scenes.

This is a preparation for a later change where we want to make git_read
non-variadic. Then it cannot have optional leading arguments.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Mark Levedahl 676c49583f git-gui: cleanup git-bash menu item
git-gui on Git for Windows creates a menu item to start a git-bash
session for the current repository. This menu-item works as desired when
git-gui is installed in the Git for Windows (g4w) distribution, but
not when run from a different location such as normally done in
development. The reason is that git-bash's location is known to be
'/git-bash' in the Unix pathname space known to MSYS, but this is not
known in the Windows pathname space. Instead, git-gui derives a pathname
for git-bash assuming it is at a known relative location.

If git-gui is run from a different directory than assumed in g4w, the
relative location changes, and git-gui resorts to running a generic bash
login session in a Windows console.

But, the MSYS system underlying Git for Windows includes the 'cygpath'
utility to convert between Unix and Windows pathnames. Let's use this so
git-bash's Windows pathname is determined directly from /git-bash.

Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Johannes Sixt e883ceb122 git-gui: sanitize 'exec' arguments: background
As in the previous commits, introduce a function that sanitizes
arguments intended for the process, but runs the process in the
background. Convert 'exec' calls to use this new function.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Mark Levedahl 00c7aa86e9 git-gui: avoid auto_execok in do_windows_shortcut
git-gui on Windows uses auto_execok to locate git-gui.exe,
which performs the same flawed search as does the builtin exec.
Use _which instead, performing a safe PATH lookup.

Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Johannes Sixt 4f3e0a4bce git-gui: sanitize 'exec' arguments: simple cases
Tcl 'exec' assigns special meaning to its argument when they begin with
redirection, pipe or background operator. There are a number of
invocations of 'exec' which construct arguments that are taken from the
Git repository or a user input. However, when file names or ref names
are taken from the repository, it is possible to find names that have
these special forms. They must not be interpreted by 'exec' lest it
redirects input or output, or attempts to build a pipeline using a
command name controlled by the repository.

Introduce a helper function that identifies such arguments and prepends
"./" to force such a name to be regarded as a relative file name.

Convert those 'exec' calls where the arguments can simply be packed
into a list.

Note that most commands containing the word 'exec' route through
console::exec or console::chain, which we will treat in another commit.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Mark Levedahl 411cd493cb git-gui: avoid auto_execok for git-bash menu item
On Windows, git-gui offers to open a git-bash session for the current
repository from the menu, but uses [auto_execok start] to get the
command to actually run that shell.

The code for auto_execok, in /usr/share/tcl8.6/tcl.init, has 'start' in
the 'shellBuiltins' list for cmd.exe on Windows: as a result,
auto_execok does not actually search for start, meaning this usage is
technically ok with auto_execok now.  However, leaving this use of
auto_execok in place will just induce confusion about why a known unsafe
function is being used on Windows. Instead, let's switch to using our
known safe _which function that looks only in $PATH, excluding the
current working directory.

Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Johannes Sixt c2e8904258 git-gui: treat file names beginning with "|" as relative paths
The Tcl 'open' function has a very wide interface. It can open files as
well as pipes to external processes. The difference is made only by the
first character of the file name: if it is "|", a process is spawned.

We have a number of calls of Tcl 'open' that take a file name from the
environment in which Git GUI is running. Be prepared that insane values
are injected. In particular, when we intend to open a file, do not take
a file name that happens to begin with "|" as a request to run a process.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Mark Levedahl 2c66188b12 git-gui: remove unused proc is_shellscript
Commit 7d076d5675 (git-gui: handle shell script text filters when
loading for blame, 2011-12-09) added is_shellscript to test if a file
is executable by the shell, used only when searching for textconv
filters. The previous commit rearranged the tests for finding such
filters, and removed the only user of is_shellscript. Remove this
function.

Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Johannes Sixt 8255167b26 git-gui: remove git config --list handling for git < 1.5.3
git-gui uses `git config --null --list` to parse configuration. Git
versions prior to 1.5.3 do not have --null and need different treatment.
Nobody should be using such an old version anymore. (Moreover, since
0730a5a3a, git-gui requires git v2.36 or later). Keep only the code for
modern Git.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Johannes Sixt 4eb9b1157b git-gui: remove special treatment of Windows from open_cmd_pipe
Commit 7d076d5675 (git-gui: handle shell script text filters when
loading for blame, 2011-12-09) added open_cmd_pipe to run text
conversion in support of blame, with special handling for shell
scripts on Windows. To determine whether the command is a shell
script, 'lindex' is used to pick off the first token from the command.
However, cmd is actually a command string taken from .gitconfig
literally and is not necessarily a syntactically correct Tcl list.
Hence, it cannot be processed by 'lindex' and 'lrange' reliably.
Pass the command string to the shell just like on non-Windows
platforms to avoid the potentially incorrect treatment.

A use of 'auto_execok' is removed by this change. This function is
dangerous on Windows, because it searches programs in the current
directory. Delegating the path lookup to the shell is safe, because
/bin/sh and /bin/bash follow POSIX on all platforms, including the
Git for Windows port.

A possible regression is that the old code, given filter command of
'foo', could find 'foo.bat' as a script, and not just bare 'foo', or
'foo.exe'.  This rewrite requires explicitly giving the suffix if it is
not .exe.

This part of Git GUI can be exercised using

    git gui blame -- some.file

while some.file has a textconv filter configured and has unstaged
modifications.

Helped-by: Mark Levedahl <mlevedahl@gmail.com>
Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Mark Levedahl f9a2e8a38f git-gui: remove HEAD detachment implementation for git < 1.5.3
git-gui provides an implementation to detach HEAD on Git versions prior
to 1.5.3.  Nobody should be using such an old version anymore.
(Moreover, since 0730a5a3a, git-gui requires git v2.36 or later).
Keep only the code for modern Git.

Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
[j6t: message tweaked]
Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Mark Levedahl 02dd866ba9 git-gui: use only the configured shell
git-gui has a few places where a bare "sh" is passed to exec, meaning
that the first instance of "sh" on $PATH will be used rather than the
shell configured. This violates expectations that the configured shell
is being used. Let's use [shellpath] everywhere.

Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Mark Levedahl 4774c704d2 git-gui: remove Tcl 8.4 workaround on 2>@1 redirection
Since b792230 ("git-gui: Show a progress meter for checking out files",
2007-07-08), git-gui includes a workaround for Tcl that does not support
using 2>@1 to redirect stderr to stdout. Tcl added such support in
8.4.7, released in 2004, and this is fully supported in all 8.5
releases.

As git-gui has a hard-coded requirement for Tcl >= 8.5, the workaround
is no longer needed. Delete it.

Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Mark Levedahl 10637fc327 git-gui: make _shellpath usable on startup
Since commit d5257fb3c1 (git-gui: handle textconv filter on
Windows and in development, 2010-08-07), git-gui will search for a
usable shell if _shellpath is not configured, and on Windows may
resort to using auto_execok to find 'sh'. While this was intended for
development use, checks are insufficient to assure a proper
configuration when deployed where _shellpath is always set, but might
not give a usable shell.

Let's make this more robust by only searching if _shellpath was not
defined, and then using only our restricted search functions.
Furthermore, we should convert to a Windows path on Windows.  Always
check for a valid shell on startup, meaning an absolute path to an
executable, aborting if these conditions are not met.

Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Johannes Sixt dcda716dbc Merge branch 'ml/git-gui-exec-path-fix'
* ml/git-gui-exec-path-fix:
  git-gui - use git-hook, honor core.hooksPath
  git-gui - re-enable use of hook scripts
2025-05-23 17:04:23 -04:00
Mark Levedahl c5c32781c9 git-gui: use [is_Windows], not bad _shellpath
Commit 7d076d5675 (git-gui: handle shell script text filters when
loading for blame, 2011-12-09) added open_cmd_pipe, with special
handling for Windows detected by seeing that _shellpath does not
point to an executable shell. That is bad practice, and is broken by
the next commit that assures _shellpath is valid on all platforms.

Fix this by using [is_Windows] as done for all Windows specific code.

Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Mark Levedahl 37b9230226 git-gui: _which, only add .exe suffix if not present
The _which function finds executables on $PATH, and adds .exe on Windows
unless -script was given. However, win32.tcl executes "wscript.exe"
and "cscript.exe", both of which fail as _which adds .exe to both. This
is already fixed in git-gui released by Git for Windows. Do so here.

Signed-off-by: Mark Levedahl <mlevedahl@gmail.com>
Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:23 -04:00
Taylor Blau d7bc50cece Merge branch 'js/fix-open-exec-2.40.0' into js/fix-open-exec
Branch js/fix-open-exec-2.40.0 converts `open` and `exec` calls to call
wrappers that sanitze the command arguments. This side branch updates
three `open` calls that are in conflict with the fix in the preceding
commit.  To keep the intended operation of the 'open' calls, this merge
does not try to merge and resolve the conflicts, but ignores the
conversions that are brought in by the side branch, taking "ours" side
of the code in these three cases.

New fixes are the topic of the next commit.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:04:21 -04:00
Avi Halachmi (:avih) 8e3070aa5e gitk: encode arguments correctly with "open"
While "exec" uses a normal arguments list which is applied as
command + arguments (and redirections, etc), "open" uses a single
argument which is this command+arguments, where the command and
arguments are a list inside this one argument to "open".

Commit bb5cb23 (gitk: prevent overly long command lines 2023-05-08)
changed several values from individual arguments in that list (hashes
and file names), to a single value which is fed to git via redirection
to its stdin using "open" [1].

However, it didn't ensure correctly that this aggregate value in this
string is interpreted as a single element in this command+args list.

It did just enough so that newlines (which is how these elements are
concatenated) don't split this single list element.

A followup commit at the same patchset: 7dd272e (gitk: escape file
paths before piping to git log 2023-05-08) added a bit more, by
escaping backslahes and spaces at the file names, so that at least
it doesn't break when such file names get used there.

But these are not enough. At the very least tab is missing, and more,
and trying to manually escape every possible thing which can affect
how this string is interpreted in a list is a sub-par approach.

The solution is simply to tell tcl "this is a single list element".
which we can do by aggregating this value completely normally (hashes
and files separated by newlines), and then do [list $value].

So this is what this commit does, for all 3 places where bb5cb23
changed individual elements into an aggregate value.

[1]
That was not a fully accurate description. The accurate version
is that this string originally included two lists: hashes and files.
When used with "open" these lists correctly become the individual
elements of these lists, even if they contain spaces etc, so the
arguments which were used at this "git" commands were correct.

Commit bb5cb23 couldn't use these two lists as-is, because it needed
to process the individual elements in them (one element per line of
the aggregate value), and the issue is that ensuring this aggregate
is indeed interpreted as a single list element was sub-par.

Note: all the (double) quotes before/after the modification are not
required and with zero effect, even for \n. But this commit preserves
the original quoting form intentionally. It can be cleaned up later.

Signed-off-by: Avi Halachmi (:avih) <avihpit@yahoo.com>
Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:03:30 -04:00
Johannes Sixt 026c397d91 gitk: sanitize 'open' arguments: command pipeline
As in the earlier commits, introduce a function that constructs a
pipeline of commands after sanitizing the arguments.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:03:30 -04:00
Johannes Sixt 79a3ef5314 gitk: collect construction of blameargs into a single conditional
The command line to invoke 'git blame' for a single line is constructed
using several if-conditionals, each with the same condition
{$from_index new {}}. Merge all of them into a single conditional.
This requires to duplicate significant parts of the command, but it
helps the next change, where we will have to deal with a nested list
structure.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:03:30 -04:00
Johannes Sixt 2aeb4484a0 gitk: sanitize 'open' arguments: simple commands, readable and writable
As in the previous commits, introduce a function that sanitizes
arguments and also keeps the returned file handle writable to pass
data to stdin.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:03:30 -04:00
Johannes Sixt 42a64b41a7 gitk: sanitize 'open' arguments: simple commands with redirections
As in the previous commits, introduce a function that sanitizes
arguments intended for the process and in addition allows to pass
redirections, which are passed to Tcl's 'open' verbatim.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:03:30 -04:00
Johannes Sixt fe32bf31b8 gitk: sanitize 'open' arguments: simple commands
Tcl 'open' treats the second argument as a command when it begins
with |. The remainder of the argument is a list comprising the command
and its arguments. It assigns special meaning to these arguments when
they begin with a redirection, pipe or background operator. There are a
number of invocations of 'open' which construct arguments that are
taken from the Git repository or a user input. However, when file names
or ref names are taken from the repository, it is possible to find
names which have these special forms. They must not be interpreted by
'open' lest it redirects input or output, or attempts to build a
pipeline using a command name controlled by the repository.

Introduce a helper function that identifies such arguments and prepends
"./" to force such a name to be regarded as a relative file name.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:03:30 -04:00
Johannes Sixt 30846b4306 gitk: sanitize 'exec' arguments: redirect to process
Convert one 'exec' call that sends output to a process (pipeline).
Fortunately, the command does not contain any variables. For this
reason, just treat it as a "redirection".

Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:03:30 -04:00
Johannes Sixt 7a0493edda gitk: sanitize 'exec' arguments: redirections and background
Convert 'exec' calls that both redirect output to a file and run the
process in the background. 'safe_exec_redirect' can take both these
"redirections" in the second argument simultaneously.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:03:30 -04:00
Johannes Sixt 6b631ee8ed gitk: sanitize 'exec' arguments: redirections
As in the previous commits, introduce a function that sanitizes
arguments intended for the process and in addition allows to pass
redirections verbatim, which are interpreted by Tcl's 'exec'.
Redirections can include the background operator '&'.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:03:30 -04:00
Johannes Sixt 88139a617f gitk: sanitize 'exec' arguments: 'eval exec'
Convert calls of 'exec' where the arguments are already available in
a list and 'eval' is used to unpack the list. Use 'concat' to unite
the arguments into a single list before passing them to 'safe_exec'.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:03:30 -04:00
Johannes Sixt 9f0d1c2f7d gitk: sanitize 'exec' arguments: simple cases
Tcl 'exec' assigns special meaning to its argument when they begin with
redirection, pipe or background operator. There are a number of
invocations of 'exec' which construct arguments that are taken from the
Git repository or a user input. However, when file names or ref names
are taken from the repository, it is possible to find names with have
these special forms. They must not be interpreted by 'exec' lest it
redirects input or output, or attempts to build a pipeline using a
command name controlled by the repository.

Introduce a helper function that identifies such arguments and prepends
"./" to force such a name to be regarded as a relative file name.

Convert those 'exec' calls where the arguments can simply be packed
into a list.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:03:30 -04:00
Johannes Sixt 6eb797f5d1 gitk: have callers of diffcmd supply pipe symbol when necessary
Function 'diffcmd' derives which of git diff-files, git diff-index, or
git diff-tree must be invoked depending on the ids provided. It puts
the pipe symbol as the first element of the returned command list.

Note though that of the four callers only two use the command with
Tcl 'open' and need the pipe symbol. The other two callers pass the
command to Tcl 'exec' and must remove the pipe symbol.

Do not include the pipe symbol in the constructed command list, but let
the call sites decide whether to add it or not. Note that Tcl 'open'
inspects only the first character of the command list, which is also
the first character of the first element in the list. For this reason,
it is valid to just tack on the pipe symbol with |$cmd and it is not
necessary to use [concat | $cmd].

Signed-off-by: Johannes Sixt <j6t@kdbg.org>

Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:03:30 -04:00
Johannes Sixt b966b738e1 gitk: treat file names beginning with "|" as relative paths
The Tcl 'open' function has a vary wide interface. It can open files as
well as pipes to external processes. The difference is made only by the
first character of the file name: if it is "|", an process is spawned.

We have a number of calls of Tcl 'open' that take a file name from the
environment in which Gitk is running. Be prepared that insane values are
injected. In particular, when we intend to open a file, do not mistake
a file name that happens to begin with "|" as a request to run a process.

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
2025-05-23 17:03:30 -04:00
Jacob Keller 09fb155f11 diff --no-index: support limiting by pathspec
The --no-index option of git-diff enables using the diff machinery from
git while operating outside of a repository. This mode of git diff is
able to compare directories and produce a diff of their contents.

When operating git diff in a repository, git has the notion of
"pathspecs" which can specify which files to compare. In particular,
when using git to diff two trees, you might invoke:

  $ git diff-tree -r <treeish1> <treeish2>.

where the treeish could point to a subdirectory of the repository.

When invoked this way, users can limit the selected paths of the tree by
using a pathspec. Either by providing some list of paths to accept, or
by removing paths via a negative refspec.

The git diff --no-index mode does not support pathspecs, and cannot
limit the diff output in this way. Other diff programs such as GNU
difftools have options for excluding paths based on a pattern match.
However, using git diff as a diff replacement has several advantages
over many popular diff tools, including coloring moved lines, rename
detections, and similar.

Teach git diff --no-index how to handle pathspecs to limit the
comparisons. This will only be supported if both provided paths are
directories.

For comparisons where one path isn't a directory, the --no-index mode
already has some DWIM shortcuts implemented in the fixup_paths()
function.

Modify the fixup_paths function to return 1 if both paths are
directories. If this is the case, interpret any extra arguments to git
diff as pathspecs via parse_pathspec.

Use parse_pathspec to load the remaining arguments (if any) to git diff
--no-index as pathspec items. Disable PATHSPEC_ATTR support since we do
not have a repository to do attribute lookup. Disable PATHSPEC_FROMTOP
since we do not have a repository root. All pathspecs are treated as
rooted at the provided comparison paths.

After loading the pathspec data, calculate skip offsets for skipping
past the root portion of the paths. This is required to ensure that
pathspecs start matching from the provided path, rather than matching
from the absolute path. We could instead pass the paths as prefix values
to parse_pathspec. This is slightly problematic because the paths come
from the command line and don't necessarily have the proper trailing
slash. Additionally, that would require parsing pathspecs multiple
times.

Pass the pathspec object and the skip offsets into queue_diff, which
in-turn must pass them along to read_directory_contents.

Modify read_directory_contents to check against the pathspecs when
scanning the directory. Use the skip offset to skip past the initial
root of the path, and only match against portions that are below the
intended directory structure being compared.

The search algorithm for finding paths is recursive with read_dir. To
make pathspec matching work properly, we must set both
DO_MATCH_DIRECTORY and DO_MATCH_LEADING_PATHSPEC.

Without DO_MATCH_DIRECTORY, paths like "a/b/c/d" will not match against
pathspecs like "a/b/c". This is usually achieved by setting the is_dir
parameter of match_pathspec.

Without DO_MATCH_LEADING_PATHSPEC, paths like "a/b/c" would not match
against pathspecs like "a/b/c/d". This is crucial because we recursively
iterate down the directories. We could simply avoid checking pathspecs
at subdirectories, but this would force recursion down directories
which would simply be skipped.

If we always passed DO_MATCH_LEADING_PATHSPEC, then we will
incorrectly match in certain cases such as matching 'a/c' against
':(glob)**/d'. The match logic will see that a matches the leading part
of the **/ and accept this even tho c doesn't match.

To avoid this, use the match_leading_pathspec() variant recently
introduced. This sets both flags when is_dir is set, but leaves them
both cleared when is_dir is 0.

Add test cases and documentation covering the new functionality. Note
for the documentation I opted not to move the placement of '--' which is
sometimes used to disambiguate arguments. The diff --no-index mode
requires exactly 2 arguments determining what to compare. Any additional
arguments are interpreted as pathspecs and must come afterwards. Use of
'--' would not actually disambiguate anything, since there will never be
ambiguity over which arguments represent paths or pathspecs.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-22 14:20:11 -07:00
Jacob Keller 00466c1620 pathspec: add flag to indicate operation without repository
A following change will add support for pathspecs to the git diff
--no-index command. This mode of git diff does not load any repository.

Add a new PATHSPEC_NO_REPOSITORY flag indicating that we're parsing
pathspecs without a repository.

Both PATHSPEC_ATTR and PATHSPEC_FROMTOP require a repository to
function. Thus, verify that both of these are set in magic_mask to
ensure they won't be accepted when PATHSPEC_NO_REPOSITORY is set.

Check PATHSPEC_NO_REPOSITORY when warning about paths outside the
directory tree. When the flag is set, do not look for a git repository
when generating the warning message.

Finally, add a BUG in match_pathspec_item if the istate is NULL but the
pathspec has PATHSPEC_ATTR set. Callers which support PATHSPEC_ATTR
should always pass a valid istate, and callers which don't pass a valid
istate should have set PATHSPEC_ATTR in the magic_mask field to disable
support for attribute-based pathspecs.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-22 14:20:11 -07:00
Jacob Keller 6e4fb00156 pathspec: add match_leading_pathspec variant
The do_match_pathspec() function has the DO_MATCH_LEADING_PATHSPEC
option to allow pathspecs to match when matching "src" against a
pathspec like "src/path/...". This support is not exposed by
match_pathspec, and the internal flags to do_match_pathspec are not
exposed outside of dir.c

The upcoming support for pathspecs in git diff --no-index need the
LEADING matching behavior when iterating down through a directory with
readdir.

We could try to expose the match_pathspec_with_flags to the public API.
However, DO_MATCH_EXCLUDES really shouldn't be public, and its a bit
weird to only have a few of the flags become public.

Instead, add match_leading_pathspec() as a function which sets both
DO_MATCH_DIRECTORY and DO_MATCH_LEADING_PATHSPEC when is_dir is true.

This will be used in a following change to support pathspec matching in
git diff --no-index.

Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-22 14:20:11 -07:00
Karthik Nayak 9d2962a7c4 receive-pack: use batched reference updates
The reference updates performed as a part of 'git-receive-pack(1)', take
place one at a time. For each reference update, a new transaction is
created and committed. This is necessary to ensure we can allow
individual updates to fail without failing the entire command. The
command also supports an 'atomic' mode, which uses a single transaction
to update all of the references. But this mode has an all-or-nothing
approach, where if a single update fails, all updates would fail.

In 23fc8e4f61 (refs: implement batch reference update support,
2025-04-08), we introduced a new mechanism to batch reference updates.
Under the hood, this uses a single transaction to perform a batch of
reference updates, while allowing only individual updates to fail.
Utilize this newly introduced batch update mechanism in
'git-receive-pack(1)'. This provides a significant bump in performance,
especially when dealing with repositories with large number of
references.

With the reftable backend there is a 18x performance improvement, when
performing receive-pack with 10000 refs:

  Benchmark 1: receive: many refs (refformat = reftable, refcount = 10000, revision = master)
    Time (mean ± σ):      4.276 s ±  0.078 s    [User: 0.796 s, System: 3.318 s]
    Range (min … max):    4.185 s …  4.430 s    10 runs

  Benchmark 2: receive: many refs (refformat = reftable, refcount = 10000, revision = HEAD)
    Time (mean ± σ):     235.4 ms ±   6.9 ms    [User: 75.4 ms, System: 157.3 ms]
    Range (min … max):   228.5 ms … 254.2 ms    11 runs

  Summary
    receive: many refs (refformat = reftable, refcount = 10000, revision = HEAD) ran
     18.16 ± 0.63 times faster than receive: many refs (refformat = reftable, refcount = 10000, revision = master)

In similar conditions, the files backend sees a 1.21x performance
improvement:

  Benchmark 1: receive: many refs (refformat = files, refcount = 10000, revision = master)
    Time (mean ± σ):      1.121 s ±  0.021 s    [User: 0.128 s, System: 0.975 s]
    Range (min … max):    1.097 s …  1.156 s    10 runs

  Benchmark 2: receive: many refs (refformat = files, refcount = 10000, revision = HEAD)
    Time (mean ± σ):     927.9 ms ±  22.6 ms    [User: 99.0 ms, System: 815.2 ms]
    Range (min … max):   903.1 ms … 978.0 ms    10 runs

  Summary
    receive: many refs (refformat = files, refcount = 10000, revision = HEAD) ran
      1.21 ± 0.04 times faster than receive: many refs (refformat = files, refcount = 10000, revision = master)

As using batched updates requires the error handling to be moved to the
end of the flow, create and use a 'struct strset' to track the failed
refs and attribute the correct errors to them.

This change also uncovers an issue when a client provides multiple
updates to the same reference. For example:

  $ git send-pack remote.git A:foo B:foo
  Enumerating objects: 3, done.
  Counting objects: 100% (3/3), done.
  Delta compression using up to 20 threads
  Compressing objects: 100% (2/2), done.
  Writing objects: 100% (3/3), 226 bytes | 226.00 KiB/s, done.
  Total 3 (delta 1), reused 0 (delta 0), pack-reused 0 (from 0)
  remote: error: cannot lock ref 'refs/heads/foo': reference already exists
  To remote.git
   ! [remote rejected] A -> foo (failed to update ref)
   ! [remote failure]  B -> foo (remote failed to report status)

As you can see, the remote runs into an error because it cannot lock the
target reference for the second update. Furthermore, the remote complains
that the first update has been rejected whereas the second update didn't
receive any status update because we failed to lock it. Reading this status
message alone a user would probably expect that `foo` has not been updated
at all. But that's not the case: while we claim that the ref wasn't updated,
it surprisingly points to `A` now.

One could argue that this is merely an error in how we report the result of
this push. But ultimately, the user's request itself is already broken and
doesn't make any sense in the first place and cannot ever lead to a sensible
outcome that honors the full request.

The conversion to batched transactions fixes the issue because we now try to
queue both updates in the same transaction. As such, the transaction itself
will notice this conflict and refuse the update altogether before we commit
any of the values.

Note that this requires changes to a couple of tests in t5408 that happened
to exercise this behaviour. Given that the generated output is misleading
and given that the user request cannot ever be fully honored this really
feels more like a bug than properly designed behaviour. As such, changing
the behaviour feels like the right thing to do.

Since now reference updates are batched, the 'reference-transaction'
hook will be invoked with all updates together. Currently git will 'die'
when the hook returns with a non-zero exit status in the 'prepared'
stage. For 'git-receive-pack(1)', this allowed users to reject an
individual reference update, git would have applied previous updates but
immediately abort further execution. This is definitely an incorrect
usage of this hook, since the right place to do this would be the
'update' hook. This patch retains the latter behavior, but
'reference-transaction' hook now changes to a all-or-nothing behavior
when a non-zero exit status is returned in the 'prepared' stage, since
batch updates use a transaction under the hood. This explains the change
in 't1416'.

Helped-by: Jeff King <peff@peff.net>
Helped-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-19 11:06:32 -07:00
Karthik Nayak 77188b5bba send-pack: fix memory leak around duplicate refs
The 'git-send-pack(1)' allows users to push objects to a remote
repository and explicitly list the references to be pushed. The status
of each reference pushed is captured into a list mapped by refname.

If a reference fails to be updated, its error message is captured in the
`ref->remote_status` field. While the command allows duplicate ref
inputs, the list doesn't accommodate this behavior as a particular
refname is linked to a single `struct ref*` element. So if the user
inputs a reference twice like:

  git send-pack remote.git A:foo B:foo

where the user is trying to update the same reference 'foo' twice and
the reference fails to be updated, we first fill `ref->remote_status`
with error message for the input 'A:foo' then we override the same field
with the error message for 'B:foo'. This override happens without first
free'ing the previous value. Fix this leak.

The current tests already incorporate the above example, but in the test
'A:foo' succeeds while 'B:foo' fails, meaning that the memory leak isn't
triggered. Add a new test with multiple duplicates.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-19 11:06:31 -07:00
Karthik Nayak 0e358de64a fetch: use batched reference updates
The reference updates performed as a part of 'git-fetch(1)', take place
one at a time. For each reference update, a new transaction is created
and committed. This is necessary to ensure we can allow individual
updates to fail without failing the entire command. The command also
supports an '--atomic' mode, which uses a single transaction to update
all of the references. But this mode has an all-or-nothing approach,
where if a single update fails, all updates would fail.

In 23fc8e4f61 (refs: implement batch reference update support,
2025-04-08), we introduced a new mechanism to batch reference updates.
Under the hood, this uses a single transaction to perform a batch of
reference updates, while allowing only individual updates to fail.
Utilize this newly introduced batch update mechanism in 'git-fetch(1)'.
This provides a significant bump in performance, especially when dealing
with repositories with large number of references.

Adding support for batched updates is simply modifying the flow to also
create a batch update transaction in the non-atomic flow.

With the reftable backend there is a 22x performance improvement, when
performing 'git-fetch(1)' with 10000 refs:

  Benchmark 1: fetch: many refs (refformat = reftable, refcount = 10000, revision = master)
    Time (mean ± σ):      3.403 s ±  0.775 s    [User: 1.875 s, System: 1.417 s]
    Range (min … max):    2.454 s …  4.529 s    10 runs

  Benchmark 2: fetch: many refs (refformat = reftable, refcount = 10000, revision = HEAD)
    Time (mean ± σ):     154.3 ms ±  17.6 ms    [User: 102.5 ms, System: 56.1 ms]
    Range (min … max):   145.2 ms … 220.5 ms    18 runs

  Summary
    fetch: many refs (refformat = reftable, refcount = 10000, revision = HEAD) ran
     22.06 ± 5.62 times faster than fetch: many refs (refformat = reftable, refcount = 10000, revision = master)

In similar conditions, the files backend sees a 1.25x performance
improvement:

  Benchmark 1: fetch: many refs (refformat = files, refcount = 10000, revision = master)
    Time (mean ± σ):     605.5 ms ±   9.4 ms    [User: 117.8 ms, System: 483.3 ms]
    Range (min … max):   595.6 ms … 621.5 ms    10 runs

  Benchmark 2: fetch: many refs (refformat = files, refcount = 10000, revision = HEAD)
    Time (mean ± σ):     485.8 ms ±   4.3 ms    [User: 91.1 ms, System: 396.7 ms]
    Range (min … max):   477.6 ms … 494.3 ms    10 runs

  Summary
    fetch: many refs (refformat = files, refcount = 10000, revision = HEAD) ran
      1.25 ± 0.02 times faster than fetch: many refs (refformat = files, refcount = 10000, revision = master)

With this we'll either be using a regular transaction or a batch update
transaction. This helps cleanup some code which is no longer needed as
we'll now always have some type of 'ref_transaction' object being
propagated.

One big change is that earlier, each individual update would propagate a
failure. Whereas now, the `ref_transaction_for_each_rejected_update`
function is called at the end of the flow to capture the exit status for
'git-fetch(1)' and also to print F/D conflict errors. This does change
the order of the errors being printed, but the behavior stays the same.

Since transaction errors are now explicitly defined as part of
76e760b999 (refs: introduce enum-based transaction error types,
2025-04-08), utilize them and get rid of custom errors defined within
'builtin/fetch.c'.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-19 11:06:31 -07:00
Karthik Nayak b3de3832ce refs: add function to translate errors to strings
The commit 76e760b999 (refs: introduce enum-based transaction error
types, 2025-04-08) introduced enum-based transaction error types. The
refs transaction logic was also modified to propagate these errors. For
clients of the ref transaction system, it would be beneficial to provide
human readable messages for these errors.

There is already an existing mapping in 'builtin/update-ref.c', move it
to 'refs.c' as `ref_transaction_error_msg()` and use the same within the
'builtin/update-ref.c'.

Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-19 11:06:31 -07:00
Derrick Stolee c178b02e29 pack-objects: allow --shallow and --path-walk
There does not appear to be anything particularly incompatible about the
--shallow and --path-walk options of 'git pack-objects'. If shallow
commits are to be handled differently, then it is by the revision walk
that defines the commit set and which are interesting or uninteresting.

However, before the previous change, a trivial removal of the warning
would cause a failure in t5500-fetch-pack.sh when
GIT_TEST_PACK_PATH_WALK is enabled. The shallow fetch would provide more
objects than we desired, due to some incorrect behavior of the path-walk
API, especially around walking uninteresting objects.

The recently-added tests in t5538-push-shallow.sh help to confirm this
behavior is working with the --path-walk option if
GIT_TEST_PACK_PATH_WALK is enabled. These tests passed previously due to
the --path-walk feature being disabled in the presence of a shallow
clone.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-16 12:15:41 -07:00
Derrick Stolee 4705889c3d path-walk: add new 'edge_aggressive' option
In preparation for allowing both the --shallow and --path-walk options
in the 'git pack-objects' builtin, create a new 'edge_aggressive' option
in the path-walk API. This option will help walk the boundary more
thoroughly and help avoid sending extra objects during fetches and
pushes.

The only use of the 'edge_hint_aggressive' option in the revision API is
within mark_edges_uninteresting(), which is usually called before
between prepare_revision_walk() and before visiting commits with
get_revision(). In prepare_revision_walk(), the UNINTERESTING commits
are walked until a boundary is found.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-16 12:15:40 -07:00
Derrick Stolee e5394794a5 pack-objects: thread the path-based compression
Adapting the implementation of ll_find_deltas(), create a threaded
version of the --path-walk compression step in 'git pack-objects'.

This involves adding a 'regions' member to the thread_params struct,
allowing each thread to own a section of paths. We can simplify the way
jobs are split because there is no value in extending the batch based on
name-hash the way sections of the object entry array are attempted to be
grouped. We re-use the 'list_size' and 'remaining' items for the purpose
of borrowing work in progress from other "victim" threads when a thread
has finished its batch of work more quickly.

Using the Git repository as a test repo, the p5313 performance test
shows that the resulting size of the repo is the same, but the threaded
implementation gives gains of varying degrees depending on the number of
objects being packed. (This was tested on a 16-core machine.)

Test                        HEAD~1      HEAD
---------------------------------------------------
5313.20: big pack             2.38      1.99 -16.4%
5313.21: big pack size       16.1M     16.0M  -0.2%
5313.24: repack             107.32     45.41 -57.7%
5313.25: repack size        213.3M    213.2M  -0.0%

(Test output is formatted to better fit in message.)

This ~60% reduction in 'git repack --path-walk' time is typical across
all repos I used for testing. What is interesting is to compare when the
overall time improves enough to outperform the --name-hash-version=1
case. These time improvements correlate with repositories with data
shapes that significantly improve their data size as well. The
--path-walk feature frequently takes longer than --name-hash-version=2,
trading some extra computation for some additional compression. The
natural place where this additional computation comes from is the two
compression passes that --path-walk takes, though the first pass is
naturally faster due to the path boundaries avoiding a number of delta
compression attempts.

For example, the microsoft/fluentui repo has significant size reduction
from --name-hash-version=1 to --name-hash-version=2 followed by further
improvements with --path-walk. The threaded computation makes
--path-walk more competitive in time compared to --name-hash-version=2,
though still ~31% more expensive in that metric.

Repack Method       Pack Size       Time
------------------------------------------
Hash v1                439.4M      87.24s
Hash v2                161.7M      21.51s
Path Walk (Before)     142.5M      81.29s
Path Walk (After)      142.5M      28.16s

Similar results hold for the Git repository:

Repack Method       Pack Size       Time
------------------------------------------
Hash v1                248.8M      30.44s
Hash v2                249.0M      30.15s
Path Walk (Before)     213.2M     142.50s
Path Walk (After)      213.3M      45.41s

...as well as the nodejs/node repository:

Repack Method       Pack Size       Time
------------------------------------------
Hash v1                739.9M      71.18s
Hash v2                764.6M      67.82s
Path Walk (Before)     698.1M     208.10s
Path Walk (After)      698.0M      75.10s

Finally, the Linux kernel repository is a good test for this repacking
time change, even though the space savings is more subtle:

Repack Method       Pack Size       Time
------------------------------------------
Hash v1                  2.5G     554.41s
Hash v2                  2.5G     549.62s
Path Walk (before)       2.2G    1562.36s
Path Walk (before)       2.2G     559.00s

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-16 12:15:40 -07:00
Derrick Stolee 206a1bb203 pack-objects: refactor path-walk delta phase
Previously, the --path-walk option to 'git pack-objects' would compute
deltas inline with the path-walk logic. This would make the progress
indicator look like it is taking a long time to enumerate objects, and
then very quickly computed deltas.

Instead of computing deltas on each region of objects organized by tree,
store a list of regions corresponding to these groups. These can later
be pulled from the list for delta compression before doing the "global"
delta search.

This presents a new progress indicator that can be used in tests to
verify that this stage is happening.

The current implementation is not integrated with threads, but we are
setting it up to arrive in the next change.

Since we do not attempt to sort objects by size until after exploring
all trees, we can remove the previous change to t5530 due to a different
error message appearing first.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-16 12:15:40 -07:00
Derrick Stolee 4933152cbb scalar: enable path-walk during push via config
Repositories registered with Scalar are expected to be client-only
repositories that are rather large. This means that they are more likely to
be good candidates for using the --path-walk option when running 'git
pack-objects', especially under the hood of 'git push'. Enable this config
in Scalar repositories.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-16 12:15:40 -07:00
Derrick Stolee 4f7f571204 pack-objects: enable --path-walk via config
Users may want to enable the --path-walk option for 'git pack-objects' by
default, especially underneath commands like 'git push' or 'git repack'.

This should be limited to client repositories, since the --path-walk option
disables bitmap walks, so would be bad to include in Git servers when
serving fetches and clones. There is potential that it may be helpful to
consider when repacking the repository, to take advantage of improved deltas
across historical versions of the same files.

Much like how "pack.useSparse" was introduced and included in
"feature.experimental" before being enabled by default, use the repository
settings infrastructure to make the new "pack.usePathWalk" config enabled by
"feature.experimental" and "feature.manyFiles".

In order to test that this config works, add a new trace2 region around
the path walk code that can be checked by a 'git push' command.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-16 12:15:39 -07:00
Derrick Stolee 5f711504d9 repack: add --path-walk option
Since 'git pack-objects' supports a --path-walk option, allow passing it
through in 'git repack'. This presents interesting testing opportunities for
comparing the different repacking strategies against each other.

Add the --path-walk option to the performance tests in p5313.

For the microsoft/fluentui repo [1] checked out at a specific commit [2],
the --path-walk tests in p5313 look like this:

Test                                                     this tree
-------------------------------------------------------------------------
5313.18: thin pack with --path-walk                      0.08(0.06+0.02)
5313.19: thin pack size with --path-walk                           18.4K
5313.20: big pack with --path-walk                       2.10(7.80+0.26)
5313.21: big pack size with --path-walk                            19.8M
5313.22: shallow fetch pack with --path-walk             1.62(3.38+0.17)
5313.23: shallow pack size with --path-walk                        33.6M
5313.24: repack with --path-walk                         81.29(96.08+0.71)
5313.25: repack size with --path-walk                             142.5M

[1] https://github.com/microsoft/fluentui
[2] e70848ebac1cd720875bccaa3026f4a9ed700e08

Along with the earlier tests in p5313, I'll instead reformat the
comparison as follows:

Repack Method    Pack Size       Time
---------------------------------------
Hash v1             439.4M      87.24s
Hash v2             161.7M      21.51s
Path Walk           142.5M      81.29s

There are a few things to notice here:

 1. The benefits of --name-hash-version=2 over --name-hash-version=1 are
    significant, but --path-walk still compresses better than that
    option.

 2. The --path-walk command is still using --name-hash-version=1 for the
    second pass of delta computation, using the increased name hash
    collisions as a potential method for opportunistic compression on
    top of the path-focused compression.

 3. The --path-walk algorithm is currently sequential and does not use
    multiple threads for delta compression. Threading will be
    implemented in a future change so the computation time will improve
    to better compete in this metric.

There are small benefits in size for my copy of the Git repository:

Repack Method    Pack Size       Time
---------------------------------------
Hash v1             248.8M      30.44s
Hash v2             249.0M      30.15s
Path Walk           213.2M     142.50s

As well as in the nodejs/node repository [3]:

Repack Method    Pack Size       Time
---------------------------------------
Hash v1             739.9M      71.18s
Hash v2             764.6M      67.82s
Path Walk           698.1M     208.10s

[3] https://github.com/nodejs/node

This benefit also repeats in my copy of the Linux kernel repository:

Repack Method    Pack Size       Time
---------------------------------------
Hash v1               2.5G     554.41s
Hash v2               2.5G     549.62s
Path Walk             2.2G    1562.36s

It is important to see that even when the repository shape does not have
many name-hash collisions, there is a slight space boost to be found
using this method.

As this repacking strategy was released in Git for Windows 2.47.0, some
users have reported cases where the --path-walk compression is slightly
worse than the --name-hash-version=2 option. In those cases, it may be
beneficial to combine the two options. However, there has not been a
released version of Git that has both options and I don't have access to
these repos for testing.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-16 12:15:39 -07:00
Derrick Stolee 6e95bf80b5 t5538: add tests to confirm deltas in shallow pushes
It can be notoriously difficult to detect if delta bases are being
computed properly during 'git push'. Construct an example where it will
make a kilobyte worth of difference when a delta base is not found. We
can then use the progress indicators to distinguish between bytes and
KiB depending on whether the delta base is found and used.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-16 12:15:39 -07:00
Derrick Stolee 861d4bc292 pack-objects: introduce GIT_TEST_PACK_PATH_WALK
There are many tests that validate whether 'git pack-objects' works as
expected. Instead of duplicating these tests, add a new test environment
variable, GIT_TEST_PACK_PATH_WALK, that implies --path-walk by default
when specified.

This was useful in testing the implementation of the --path-walk
implementation, helping to find tests that are overly specific to the
default object walk. These include:

 - t0411-clone-from-partial.sh : One test fetches from a repo that does
   not have the boundary objects. This causes the path-based walk to
   fail. Disable the variable for this test.

 - t5306-pack-nobase.sh : Similar to t0411, one test fetches from a repo
   without a boundary object.

 - t5310-pack-bitmaps.sh : One test compares the case when packing with
   bitmaps to the case when packing without them. Since we disable the
   test variable when writing bitmaps, this causes a difference in the
   object list (the --path-walk option adds an extra object). Specify
   --no-path-walk in both processes for the comparison. Another test
   checks for a specific delta base, but when computing dynamically
   without using bitmaps, the base object it too small to be considered
   in the delta calculations so no base is used.

 - t5316-pack-delta-depth.sh : This script cares about certain delta
   choices and their chain lengths. The --path-walk option changes how
   these chains are selected, and thus changes the results of this test.

 - t5322-pack-objects-sparse.sh : This demonstrates the effectiveness of
   the --sparse option and how it combines with --path-walk.

 - t5332-multi-pack-reuse.sh : This test verifies that the preferred
   pack is used for delta reuse when possible. The --path-walk option is
   not currently aware of the preferred pack at all, so finds a
   different delta base.

 - t7406-submodule-update.sh : When using the variable, the --depth
   option collides with the --path-walk feature, resulting in a warning
   message. Disable the variable so this warning does not appear.

I want to call out one specific test change that is only temporary:

 - t5530-upload-pack-error.sh : One test cares specifically about an
   "unable to read" error message. Since the current implementation
   performs delta calculations within the path-walk API callback, a
   different "unable to get size" error message appears. When this
   is changed in a future refactoring, this test change can be reverted.

Similar to GIT_TEST_NAME_HASH_VERSION, we do not add this option to the
linux-TEST-vars CI build as that's already an overloaded build.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-16 12:15:39 -07:00
Derrick Stolee 3ce9e5f293 p5313: add performance tests for --path-walk
The previous change added a --path-walk option to 'git pack-objects'.
Create a performance test that demonstrates the time and space benefits
of the feature.

In order to get an appropriate comparison, we need to avoid reusing
deltas and recompute them from scratch.

Compare the creation of a thin pack representing a small push and the
creation of a relatively large non-thin pack.

Running on my copy of the Git repository results in this data (removing
the repack tests for --name-hash-version):

Test                                                     this tree
------------------------------------------------------------------------
5313.2: thin pack with --name-hash-version=1             0.02(0.01+0.01)
5313.3: thin pack size with --name-hash-version=1                   1.6K
5313.4: big pack with --name-hash-version=1              2.55(4.20+0.26)
5313.5: big pack size with --name-hash-version=1                   16.4M
5313.6: shallow fetch pack with --name-hash-version=1    1.24(2.03+0.08)
5313.7: shallow pack size with --name-hash-version=1               12.2M
5313.10: thin pack with --name-hash-version=2            0.03(0.01+0.01)
5313.11: thin pack size with --name-hash-version=2                  1.6K
5313.12: big pack with --name-hash-version=2             1.91(3.23+0.20)
5313.13: big pack size with --name-hash-version=2                  16.4M
5313.14: shallow fetch pack with --name-hash-version=2   1.06(1.57+0.10)
5313.15: shallow pack size with --name-hash-version=2              12.5M
5313.18: thin pack with --path-walk                      0.03(0.01+0.01)
5313.19: thin pack size with --path-walk                            1.6K
5313.20: big pack with --path-walk                       2.05(3.24+0.27)
5313.21: big pack size with --path-walk                            16.3M
5313.22: shallow fetch pack with --path-walk             1.08(1.66+0.07)
5313.23: shallow pack size with --path-walk                        12.4M

This can be reformatted as follows:

Pack Type            Hash v1   Hash v2     Path Walk
---------------------------------------------------
thin pack    (time)    0.02s      0.03s      0.03s
             (size)    1.6K       1.6K       1.6K
big pack     (time)    2.55s      1.91s      2.05s
             (size)   16.4M      16.4M      16.3M
shallow pack (time)    1.24s      1.06s      1.08s
             (size)   12.2M      12.5M      12.4M

Note that the timing is slower because there is no threading in the
--path-walk case (yet). Also, the shallow pack cases are really not
using the --path-walk logic right now because it is disabled until some
additions are made to the path walk API.

The cases where the --path-walk option really shines is when the default
name-hash is overwhelmed with unhelpful collisions. An open source
example can be found in the microsoft/fluentui repo [1] at a certain
commit [2].

[1] https://github.com/microsoft/fluentui
[2] e70848ebac1cd720875bccaa3026f4a9ed700e08

Running the tests on this repo results in the following comparison table:

Pack Type            Hash v1    Hash v2    Path Walk
---------------------------------------------------
thin pack    (time)    0.36s      0.12s      0.08s
             (size)    1.2M      22.0K      18.4K
big pack     (time)    2.00s      2.90s      2.21s
             (size)   20.4M      25.9M      19.5M
shallow pack (time)    1.41s      1.80s      1.65s
             (size)   34.4M      33.7M      33.6M

Notice in particular that in the small thin pack, the time performance
has improved from 0.36s for --name-hash-version=1 to 0.08s and this is
likely due to the improved size of the resulting pack: 18.4K instead of
1.2M.  The relatively new --name-hash-version=2 is competitive with
--path-walk (0.12s and 22.0K) but not quite as successful.

Finally, running this on a copy of the Linux kernel repository results
in these data points:

Pack Type            Hash v1    Hash v2    Path Walk
---------------------------------------------------
thin pack    (time)    0.03s      0.13s      0.03s
             (size)    4.6K       4.6K       4.6K
big pack     (time)   15.29s     12.32s     13.92s
             (size)  201.1M     159.1M     158.5M
shallow pack (time)   10.88s     22.93s     22.74s
             (size)  269.2M     273.8M     267.7M

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-16 12:15:38 -07:00
Derrick Stolee 9fcfe12ac4 pack-objects: update usage to match docs
The t0450 test script verifies that builtin usage matches the synopsis
in the documentation. Adjust the builtin to match and then remove 'git
pack-objects' from the exception list.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-16 12:15:38 -07:00
Derrick Stolee 70664d2865 pack-objects: add --path-walk option
In order to more easily compute delta bases among objects that appear at
the exact same path, add a --path-walk option to 'git pack-objects'.

This option will use the path-walk API instead of the object walk given
by the revision machinery. Since objects will be provided in batches
representing a common path, those objects can be tested for delta bases
immediately instead of waiting for a sort of the full object list by
name-hash. This has multiple benefits, including avoiding collisions by
name-hash.

The objects marked as UNINTERESTING are included in these batches, so we
are guaranteeing some locality to find good delta bases.

After the individual passes are done on a per-path basis, the default
name-hash is used to find other opportunistic delta bases that did not
match exactly by the full path name.

The current implementation performs delta calculations while walking
objects, which is not ideal for a few reasons. First, this will cause
the "Enumerating objects" phase to be much longer than usual. Second, it
does not take advantage of threading during the path-scoped delta
calculations. Even with this lack of threading, the path-walk option is
sometimes faster than the usual approach. Future changes will refactor
this code to allow for threading, but that complexity is deferred until
later to keep this patch as simple as possible.

This new walk is incompatible with some features and is ignored by
others:

 * Object filters are not currently integrated with the path-walk API,
   such as sparse-checkout or tree depth. A blobless packfile could be
   integrated easily, but that is deferred for later.

 * Server-focused features such as delta islands, shallow packs, and
   using a bitmap index are incompatible with the path-walk API.

 * The path walk API is only compatible with the --revs option, not
   taking object lists or pack lists over stdin. These alternative ways
   to specify the objects currently ignores the --path-walk option
   without even a warning.

Future changes will create performance tests that demonstrate the power
of this approach.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-16 12:15:38 -07:00
Derrick Stolee 4bc0ba0829 pack-objects: extract should_attempt_deltas()
This will be helpful in a future change, which will reuse this logic.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-16 12:15:37 -07:00
Junio C Hamano e836757e14 whatschanged: list it in BreakingChanges document
This can be squashed into the previous step.  That is how our "git
pack-redundant" conversion did.

Theoretically, however, those who want to gauge the need to keep the
command by exposing their users to patches before this one may want
to wait until their experiment finishes before they formally say
"this will go away".

This change is made into a separate patch from the previous step
precisely to help those folks.

While at it, update the documentation page to use the new [synopsis]
facility to mark-up the SYNOPSIS part.

Helped-by: Elijah Newren <newren@gmail.com>
[en: typofix]
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-12 15:30:12 -07:00
Junio C Hamano 07572f220a whatchanged: remove when built with WITH_BREAKING_CHANGES
As we made "git whatchanged" require "--i-still-use-this" and asked
the users to report if they still want to use it, the logical next
step is to allow us build Git without "whatchanged" to prepare for
its eventual removal.

If we were to follow the pattern established in 8ccc75c2 (remote:
announce removal of "branches/" and "remotes/", 2025-01-22), we can
do this together with the documentation update to officially list
that the command will be removed in the BreakingChanges document,
but let's just keep the changes separate just in case we want to
proceed a bit slower.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-12 15:30:12 -07:00
Junio C Hamano 731a2c7dda whatchanged: require --i-still-use-this
The documentation of "git whatchanged" is pretty explicit that the
command was retained for historical reasons to help those whose fingers
cannot be retrained.  Let's see if they still are finding it hard to
type "git log --raw" instead of "git whatchanged" by marking the
command as "nominated for removal", and require "--i-still-use-this"
on the command line.  Adjust the tests so that the option is passed
when we invoke the command.  In addition, we test that the command
fails when "--i-still-use-this" is not given.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-12 15:29:37 -07:00
Junio C Hamano ab4d1880e1 tests: prepare for a world without whatchanged
Some tests on fast-import run "git whatchanged" without even
checking the output from the command.  It is tempting to remove the
calls altogether since they are not doing anything useful, but they
presumably were added there while the tests were developed to manually
sanity check which paths were touched.

Replace these calls with "git log --raw", which is a rough
equivalent in the more modern Git.

This does not remove "git whatchanged", but we no longer have to
worry about adjusting these places when we eventually do.

Helped-by: Elijah Newren <newren@gmail.com>
[en: log message]
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-12 15:29:18 -07:00
Junio C Hamano ba69a6c66d doc: prepare for a world without whatchanged
Some documentation examples reference "whatchanged", either as a
placeholder command or an example of source structure.

To reduce the need for future edits when `whatchanged` is removed,
replace these references with alternatives:

 - In `MyFirstObjectWalk.adoc`, use `version` as the nearby anchor
   point for `walken`, instead of `whatchanged`.

 - In `user-manual.adoc`, cite `show` instead of `whatchanged` as
   a command whose source lives in the same file as `log`.

Helped-by: Elijah Newren <newren@gmail.com>
[en: log message]
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-12 13:11:43 -07:00
Junio C Hamano 4511d56e1a you-still-use-that??: help deprecating commands for removal
Commands slated for removal like "git pack-redundant" now require
an explicit "--i-still-use-this" option to run.  This is to
discourage casual use and surface their pending deprecation to
users.

The warning message is long, so factor it into a helper function
you_still_use_that() to simplify reuse by other commands.

Also add a missing test to ensure this enforcement works for
"pack-redundant".

Helped-by: Elijah Newren <newren@gmail.com>
[en: log message]
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-12 13:11:43 -07:00
Patrick Steinhardt af2a4b3eb7 contrib: remove some scripts in "stats" directory
The "stats" directory contains a couple of scripts to do some statistics
on a repository:

  - "git-common-hash" shows the longest common hash prefixes and can be
    used to determine the minimum prefix length to use for object names
    to be unique. The script has last been touched in 53474eb92f
    (contrib: update stats/mailmap script, 2012-12-12) and searching for
    it on the internet doesn't really surface any potential use cases or
    even mentions of it.

    Modern Git also shouldn't really need this tool as it knows to
    automatically scale printed prefixes via some heuristics.

  - "mailmap.pl" performs some statistics on the number of mailmapped
    commits in a repository. It has last been modified in 53474eb92f
    (contrib: update stats/mailmap script, 2012-12-12) and has since
    been bitrotting. It doesn't even compile nowadays anymore:

        $ perl contrib/stats/mailmap.pl
        Experimental keys on scalar is now forbidden at contrib/stats/mailmap.pl line 57.
        Type of arg 1 to keys must be hash or array (not hash element) at contrib/stats/mailmap.pl line 57, near "}) "
        Experimental keys on scalar is now forbidden at contrib/stats/mailmap.pl line 57.
        Type of arg 1 to keys must be hash or array (not private variable) at contrib/stats/mailmap.pl line 57, near "$h)"
        Experimental keys on scalar is now forbidden at contrib/stats/mailmap.pl line 64.
        Type of arg 1 to keys must be hash or array (not private variable) at contrib/stats/mailmap.pl line 64, near "$h)"
        Execution of contrib/stats/mailmap.pl aborted due to compilation errors.

    This should be good-enough signal to indicate that nobody is using
    this script at all anymore.

  - "packinfo.pl" takes the output from git-verify-pack(1) and performs
    some pretty printing thereof. On the one hand it reformats the
    output to be easier to read and provide some summaries. On the other
    hand it may also print filenames of blobs.

    We don't have any replacement for this tool. Ideally, we should move
    its functionality into git-verify-pack(1) itself.

Remove the first two scripts, but retain "packinfo.pl".

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-12 10:55:47 -07:00
Patrick Steinhardt 15405cd325 contrib: remove "git-new-workdir"
The "git-new-workdir" command has been introduced to make it possible to
have a separate working directory in a different place. The command thus
predates git-worktree(1), which is what people use nowadays to create
any such working directory. As such, the script doesn't really have much
of a reason to exist nowadays anymore.

It also doesn't seem like the script is still in use: the last time it
has received an update was in e32afab7b0 (git-new-workdir: don't fail
if the target directory is empty, 2014-11-26), more than a decade ago.
Remove it as well as the tests that depend on it.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-12 10:55:47 -07:00
Patrick Steinhardt 95bc447419 contrib: remove "emacs" directory
While the "emacs/" directory still exists, all of its code has been
replaced with stubs in 6d5ed4836d (git{,-blame}.el: remove old
bitrotting Emacs code, 2018-04-11). Instead, the recommendation is to
use Emacs' own vc-annotate mode.

Remove the code altogether.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-12 10:55:46 -07:00
Patrick Steinhardt bb9a9297d7 contrib: remove "git-resurrect.sh"
The "git-resurrect.sh" script can be used to find traces of a branch tip
in the reflog and resurrect that branch. Despite a couple of global
cleanups, the script hasn't seen any activity since it was introduced in
e1ff064e1b (contrib git-resurrect: find traces of a branch name and
resurrect it, 2009-02-04).

Furthermore, the tool does not work with the "reftable" backend at all
as it directly reads ".git/logs/HEAD". As reflogs are stored as part of
the individual tables though that file wouldn't exist in a "reftable"-
enabled repository.

Last but not least, the tool doesn't even work unless it is explicitly
invoked via `git resurrect` as it sources "git-sh-setup". As none of our
build systems know to install this script, users thus have to go out of
their way to really make it work, which is highly unlikely.

Another source that indicates that this tool can be removed is a
question for how to restore deleted branches on StackOverflow [1]. The
top-voted answer uses git-reflog(1) directly and has received more than
3000 votes to date. While "git-resurrect.sh" is also mentioned, it only
got 16 upvotes, and comments mention the above caveat that users have to
do some manual setup to make it work.

It's thus rather clear that the tool doesn't have a lot or even any
users. Remove it.

[1]: https://stackoverflow.com/questions/3640764/can-i-recover-a-branch-after-its-deletion-in-git

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-12 10:55:46 -07:00
Patrick Steinhardt 1248fb08d7 contrib: remove "persistent-https" remote helper
The "persistent-https" remote helper supposedly speeds up SSL operations
by running a daemon that keeps a connection open to a remote server. It
is effectively unmaintained nowadays: the last time it received an
update was in accb613afd (contrib/persistent-https: use Git version for
build label, 2016-07-20) and its parent commits to make it compile with
Go 1.7+.

This Go toolchain is somewhat dated by now though and unsupported. The
oldest still-supported toolchain is Go 1.23, which was released in
August 2024. It is not possible to compile the remote helper with that
Go version anymore:

    $ go version
    go version go1.23.8 linux/amd64
    $ make
    case $(go version) in \
    "go version go"1.[0-5].*) EQ=" " ;; *) EQ="=" ;; esac && \
    go build -o git-remote-persistent-https \
            -ldflags "-X main._BUILD_EMBED_LABEL${EQ}GIT_VERSION=2.49.0.943.g965a70ebf62"
    go: cannot find main module, but found .git/config in /home/pks/Development/git
            to create a module there, run:
            cd ../.. && go mod init
    make: *** [Makefile:31: git-remote-persistent-https] Error 1

The problem is that modern Go toolchains require a "go.mod" file, but we
don't have any such files. This requirement exists since quite a while
already, so it's clear that nobody has tried to use this remote helper
anytime recent.

Remove the remote helper.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-12 10:55:46 -07:00
Patrick Steinhardt 21b4f9009d contrib: remove "mw-to-git"
The "mw-to-git" directory contains tools for accessing MediaWiki via
Git. The scripts are essentially unmaintained in Git: despite a couple
of global cleanups, the last changes were a couple of security-related
issues part of 9a8606465e (remote-mediawiki: use "sh" to eliminate
unquoted commands, 2020-09-21) and its parents. We don't ever run any of
the tests so it is more likely than not that many of the tests have been
bitrotting, like e.g. documented in f8ab018daf (remote-mediawiki tests:
annotate failing tests, 2020-09-21).

According to Matthieu Moy [1], one of the original developers of this
tool, it didn't receive any attention recently and there is no
motivation to keep maintaining it anymore in the community. The project
has been spun out of Git [2] and thus has a new official home, but did
not receive much attention over there, either.

As such, it seems like the MediaWiki transport helper is slowly fading
away. But given that there is a new home, it doesn't make sense to have
it as part of Git anymore only to let it rot. Remove the directory.

[1]: <108f297a-b415-4742-80e4-51ea02af18e9@matthieu-moy.fr>
[2]: https://github.com/Git-Mediawiki/Git-Mediawiki

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-12 10:55:45 -07:00
Patrick Steinhardt 9a19b79e75 contrib: remove "hooks" directory
The "hooks" directory contains a handful of example hooks. Most of these
hooks are highly specific and haven't really received any updates over
the last couple of years, except for some global cleanups. The multimail
hook has also been removed in f74d11471f (multimail: stop shipping a
copy, 2021-06-10) in favor of its upstream project [1].

Remove those hooks. If we want to provide examples for how to use Git
hooks we should do that as part of our documentation, for example in
githooks(5).

[1]: https://github.com/git-multimail/git-multimail

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-12 10:55:45 -07:00
Patrick Steinhardt 5e16d46ba4 contrib: remove "thunderbird-patch-inline"
The "thunderbird-patch-inline" directory in "contrib/" contains a script
to send patch files via Thunderbird. This script depends on the
ExternalEditor extension [1], which seems to be effectively unmaintained
with the last update being in 2008. While the extension has eventually
been maintained in [2], that fork hasn't received any updates since
2020, either.

As such, the ExternalEditor extension does not work with modern versions
of Thunderbird anymore, and as the "thunderbird-patch-inline" script
depends on the ExternalEditor extension it likely doesn't work anymore,
either. The fact that this script hasn't been touched for the last 10
years outside of some global cleanup supports the idea that it is not
useful anymore.

Remove it.

[1]: https://globs.org/articles.php?lng=en&pg=2
[2]: https://github.com/exteditor/exteditor/releases

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-12 10:55:44 -07:00
Patrick Steinhardt 9a5e587d47 contrib: remove remote-helper stubs
The "remote-helpers" directory contains two remote helper scripts for
Mercurial and Bazaar. These scripts have since been converted into stubs
in b2c851a8e6 (Revert "Merge branch 'jc/graduate-remote-hg-bzr' (early
part)", 2014-05-20) as the helpers have been moved into their own
upstream projects [1][2].

Given that these stubs have been created more than a decade ago it is
very unlikely that anybody still tries to use them. Remove them.

[1]: https://github.com/felipec/git-remote-bzr
[1]: https://github.com/felipec/git-remote-hg

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-12 10:55:44 -07:00
Patrick Steinhardt 6672b90ece contrib: remove "examples" directory
The "examples" directory used to contain scripted versions of some of
our builtins. These have all been removed in 49eb8d39c7 (Remove
contrib/examples/*, 2018-03-25), but we left a note in the directory to
make it discoverable that there used to be examples.

It is unlikely that anybody still looks at these examples more than 7
years after they have been removed. Remove the note and its directory.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-12 10:55:43 -07:00
Patrick Steinhardt a8f959cbf6 contrib: remove "remotes2config.sh"
Remotes can be configured either via a repository's config or by using
the ".git/branches/" or ".git/remotes/" directories. Back when the new
config-based mechanism has been introduced we also introduced a helper
script that migrates from the old-style remote configuration to the new
config-based mechanism.

With the recent removal announcement for the two directories we also
started to instruct users to migrate repositories that still use these
mechanism to use config-based remotes. Notably though, the migration
path doesn't even use the migration script. Instead, git-remote(1)
itself knows how to migrate any such remote via `git remote rename`.

In fact, a full migration _cannot_ use the script as it only knows to
migrate remotes from ".git/remotes/", but not ".git/branches/". As such,
the migration path via `git remote rename` is the only feasible way to
fully migrate repositories over to the new format.

Last but not least, the script doesn't even work as-is as it sources
"git-sh-setup". For this to work it would need to be invoked either via
Git so that this script is in our PATH, users would have to manually
call it with an adjusted PATH, or distributions need to install the
script into "$prefix/libexec/git-core" with a "git-" prefix. All of
these steps are unlikely enough to underpin the claim that this script
is not used at all.

So given that:

  - The script cannot perform a full migration of all deprecated remote
    types.

  - We don't advertise it anywhere.

  - It has been basically untouched since 2007.

  - It doesn't even work unless users do manual steps.

It should be safe enough to just remove it. Do so.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-05-12 10:55:43 -07:00
447 changed files with 41573 additions and 14895 deletions

View File

@ -5,11 +5,13 @@ freebsd_task:
env: env:
GIT_PROVE_OPTS: "--timer --jobs 10" GIT_PROVE_OPTS: "--timer --jobs 10"
GIT_TEST_OPTS: "--no-chain-lint --no-bin-wrappers" GIT_TEST_OPTS: "--no-chain-lint --no-bin-wrappers"
MAKEFLAGS: "-j4" GIT_SKIP_TESTS: t7815.12
MAKEFLAGS: -j4
DEFAULT_TEST_TARGET: prove DEFAULT_TEST_TARGET: prove
DEFAULT_UNIT_TEST_TARGET: unit-tests-prove
DEVELOPER: 1 DEVELOPER: 1
freebsd_instance: freebsd_instance:
image_family: freebsd-13-4 image_family: freebsd-14-3
memory: 2G memory: 2G
install_script: install_script:
pkg install -y gettext gmake perl5 pkg install -y gettext gmake perl5
@ -19,4 +21,4 @@ freebsd_task:
build_script: build_script:
- su git -c gmake - su git -c gmake
test_script: test_script:
- su git -c 'gmake DEFAULT_UNIT_TEST_TARGET=unit-tests-prove test unit-tests' - su git -c 'gmake test unit-tests'

View File

@ -12,7 +12,15 @@ UseTab: Always
TabWidth: 8 TabWidth: 8
IndentWidth: 8 IndentWidth: 8
ContinuationIndentWidth: 8 ContinuationIndentWidth: 8
ColumnLimit: 80
# While we do want to enforce a character limit of 80 characters, we often
# allow lines to overflow that limit to prioritize readability. Setting a
# character limit here with penalties has been finicky and creates too many
# false positives.
#
# NEEDSWORK: It would be nice if we can find optimal settings to ensure we
# can re-enable the limit here.
ColumnLimit: 0


# C Language specifics # C Language specifics
Language: Cpp Language: Cpp
@ -210,16 +218,11 @@ MaxEmptyLinesToKeep: 1
# No empty line at the start of a block. # No empty line at the start of a block.
KeepEmptyLinesAtTheStartOfBlocks: false KeepEmptyLinesAtTheStartOfBlocks: false


# Penalties
# This decides what order things should be done if a line is too long
PenaltyBreakAssignment: 5
PenaltyBreakBeforeFirstCallParameter: 5
PenaltyBreakComment: 5
PenaltyBreakFirstLessLess: 0
PenaltyBreakOpenParenthesis: 300
PenaltyBreakString: 5
PenaltyExcessCharacter: 10
PenaltyReturnTypeOnItsOwnLine: 300

# Don't sort #include's # Don't sort #include's
SortIncludes: false SortIncludes: false

# Remove optional braces of control statements (if, else, for, and while)
# according to the LLVM coding style. This avoids braces on simple
# single-statement bodies of statements but keeps braces if one side of
# if/else if/.../else cascade has multi-statement body.
RemoveBracesLLVM: true

View File

@ -147,9 +147,13 @@ jobs:
key: cov-build-${{ env.COVERITY_LANGUAGE }}-${{ env.COVERITY_PLATFORM }}-${{ steps.lookup.outputs.hash }} key: cov-build-${{ env.COVERITY_LANGUAGE }}-${{ env.COVERITY_PLATFORM }}-${{ steps.lookup.outputs.hash }}
- name: build with cov-build - name: build with cov-build
run: | run: |
export PATH="$RUNNER_TEMP/cov-analysis/bin:$PATH" && export PATH="$PATH:$RUNNER_TEMP/cov-analysis/bin" &&
cov-configure --gcc && cov-configure --gcc &&
cov-build --dir cov-int make if ! cov-build --dir cov-int make
then
cat cov-int/build-log.txt
exit 1
fi
- name: package the build - name: package the build
run: tar -czvf cov-int.tgz cov-int run: tar -czvf cov-int.tgz cov-int
- name: submit the build to Coverity Scan - name: submit the build to Coverity Scan

View File

@ -298,7 +298,7 @@ jobs:
path: build path: build
- name: Test - name: Test
shell: pwsh shell: pwsh
run: meson test -C build --list | Select-Object -Skip 1 | Select-String .* | Group-Object -Property { $_.LineNumber % 10 } | Where-Object Name -EQ ${{ matrix.nr }} | ForEach-Object { meson test -C build --no-rebuild --print-errorlogs $_.Group } run: meson test -C build --no-rebuild --print-errorlogs --slice "$(1+${{ matrix.nr }})/10"


regular: regular:
name: ${{matrix.vector.jobname}} (${{matrix.vector.pool}}) name: ${{matrix.vector.jobname}} (${{matrix.vector.pool}})

View File

@ -178,7 +178,7 @@ test:msvc-meson:
- job: "build:msvc-meson" - job: "build:msvc-meson"
artifacts: true artifacts: true
script: script:
- meson test -C build --list | Select-Object -Skip 1 | Select-String .* | Group-Object -Property { $_.LineNumber % $Env:CI_NODE_TOTAL + 1 } | Where-Object Name -EQ $Env:CI_NODE_INDEX | ForEach-Object { meson test -C build --no-rebuild --print-errorlogs $_.Group; if (!$?) { exit $LASTEXITCODE } } - meson test -C build --no-rebuild --print-errorlogs --slice $Env:CI_NODE_INDEX/$Env:CI_NODE_TOTAL
parallel: 10 parallel: 10


test:fuzz-smoke-tests: test:fuzz-smoke-tests:

View File

@ -118,6 +118,53 @@ Cf. <2f5de416-04ba-c23d-1e0b-83bb655829a7@zombino.com>,
<20170223155046.e7nxivfwqqoprsqj@LykOS.localdomain>, <20170223155046.e7nxivfwqqoprsqj@LykOS.localdomain>,
<CA+EOSBncr=4a4d8n9xS4FNehyebpmX8JiUwCsXD47EQDE+DiUQ@mail.gmail.com>. <CA+EOSBncr=4a4d8n9xS4FNehyebpmX8JiUwCsXD47EQDE+DiUQ@mail.gmail.com>.


* The default storage format for references in newly created repositories will
be changed from "files" to "reftable". The "reftable" format provides
multiple advantages over the "files" format:
+
** It is impossible to store two references that only differ in casing on
case-insensitive filesystems with the "files" format. This issue is common
on Windows and macOS platforms. As the "reftable" backend does not use
filesystem paths to encode reference names this problem goes away.
** Similarly, macOS normalizes path names that contain unicode characters,
which has the consequence that you cannot store two names with unicode
characters that are encoded differently with the "files" backend. Again,
this is not an issue with the "reftable" backend.
** Deleting references with the "files" backend requires Git to rewrite the
complete "packed-refs" file. In large repositories with many references
this file can easily be dozens of megabytes in size, in extreme cases it
may be gigabytes. The "reftable" backend uses tombstone markers for
deleted references and thus does not have to rewrite all of its data.
** Repository housekeeping with the "files" backend typically performs
all-into-one repacks of references. This can be quite expensive, and
consequently housekeeping is a tradeoff between the number of loose
references that accumulate and slow down operations that read references,
and compressing those loose references into the "packed-refs" file. The
"reftable" backend uses geometric compaction after every write, which
amortizes costs and ensures that the backend is always in a
well-maintained state.
** Operations that write multiple references at once are not atomic with the
"files" backend. Consequently, Git may see in-between states when it reads
references while a reference transaction is in the process of being
committed to disk.
** Writing many references at once is slow with the "files" backend because
every reference is created as a separate file. The "reftable" backend
significantly outperforms the "files" backend by multiple orders of
magnitude.
** The reftable backend uses a binary format with prefix compression for
reference names. As a result, the format uses less space compared to the
"packed-refs" file.
+
Users that get immediate benefit from the "reftable" backend could continue to
opt-in to the "reftable" format manually by setting the "init.defaultRefFormat"
config. But defaults matter, and we think that overall users will have a better
experience with less platform-specific quirks when they use the new backend by
default.
+
A prerequisite for this change is that the ecosystem is ready to support the
"reftable" format. Most importantly, alternative implementations of Git like
JGit, libgit2 and Gitoxide need to support it.

=== Removals === Removals


* Support for grafting commits has long been superseded by git-replace(1). * Support for grafting commits has long been superseded by git-replace(1).
@ -183,6 +230,14 @@ These features will be removed.
timeframe, in preference to its synonym "--annotate-stdin". Git 3.0 timeframe, in preference to its synonym "--annotate-stdin". Git 3.0
removes the support for "--stdin" altogether. removes the support for "--stdin" altogether.


* The git-whatchanged(1) command has outlived its usefulness more than
10 years ago, and takes more keystrokes to type than its rough
equivalent `git log --raw`. We have nominated the command for
removal, have changed the command to refuse to work unless the
`--i-still-use-this` option is given, and asked the users to report
when they do so. So far there hasn't been a single complaint.
+
The command will be removed.


== Superseded features that will not be deprecated == Superseded features that will not be deprecated



View File

@ -315,6 +315,9 @@ For C programs:
encouraged to have a blank line between the end of the declarations encouraged to have a blank line between the end of the declarations
and the first statement in the block. and the first statement in the block.


- Do not explicitly initialize global variables to 0 or NULL;
instead, let BSS take care of the zero initialization.

- NULL pointers shall be written as NULL, not as 0. - NULL pointers shall be written as NULL, not as 0.


- When declaring pointers, the star sides with the variable - When declaring pointers, the star sides with the variable
@ -877,6 +880,17 @@ Characters are also surrounded by underscores:
As a side effect, backquoted placeholders are correctly typeset, but As a side effect, backquoted placeholders are correctly typeset, but
this style is not recommended. this style is not recommended.


When documenting multiple related `git config` variables, place them on
a separate line instead of separating them by commas. For example, do
not write this:
`core.var1`, `core.var2`::
Description common to `core.var1` and `core.var2`.

Instead write this:
`core.var1`::
`core.var2`::
Description common to `core.var1` and `core.var2`.

Synopsis Syntax Synopsis Syntax


The synopsis (a paragraph with [synopsis] attribute) is automatically The synopsis (a paragraph with [synopsis] attribute) is automatically

View File

@ -510,7 +510,12 @@ lint-docs-meson:
awk "/^manpages = {$$/ {flag=1 ; next } /^}$$/ { flag=0 } flag { gsub(/^ \047/, \"\"); gsub(/\047 : [157],\$$/, \"\"); print }" meson.build | \ awk "/^manpages = {$$/ {flag=1 ; next } /^}$$/ { flag=0 } flag { gsub(/^ \047/, \"\"); gsub(/\047 : [157],\$$/, \"\"); print }" meson.build | \
grep -v -e '#' -e '^$$' | \ grep -v -e '#' -e '^$$' | \
sort >tmp-meson-diff/meson.adoc && \ sort >tmp-meson-diff/meson.adoc && \
ls git*.adoc scalar.adoc | grep -v -e git-bisect-lk2009.adoc -e git-pack-redundant.adoc -e git-tools.adoc >tmp-meson-diff/actual.adoc && \ ls git*.adoc scalar.adoc | \
grep -v -e git-bisect-lk2009.adoc \
-e git-pack-redundant.adoc \
-e git-tools.adoc \
-e git-whatchanged.adoc \
>tmp-meson-diff/actual.adoc && \
if ! cmp tmp-meson-diff/meson.adoc tmp-meson-diff/actual.adoc; then \ if ! cmp tmp-meson-diff/meson.adoc tmp-meson-diff/actual.adoc; then \
echo "Meson man pages differ from actual man pages:"; \ echo "Meson man pages differ from actual man pages:"; \
diff -u tmp-meson-diff/meson.adoc tmp-meson-diff/actual.adoc; \ diff -u tmp-meson-diff/meson.adoc tmp-meson-diff/actual.adoc; \

View File

@ -43,7 +43,7 @@ Open up a new file `builtin/walken.c` and set up the command handler:
#include "builtin.h" #include "builtin.h"
#include "trace.h" #include "trace.h"


int cmd_walken(int argc, const char **argv, const char *prefix) int cmd_walken(int argc, const char **argv, const char *prefix, struct repository *repo)
{ {
trace_printf(_("cmd_walken incoming...\n")); trace_printf(_("cmd_walken incoming...\n"));
return 0; return 0;
@ -83,23 +83,36 @@ int cmd_walken(int argc, const char **argv, const char *prefix)
} }
---- ----


Also add the relevant line in `builtin.h` near `cmd_whatchanged()`: Also add the relevant line in `builtin.h` near `cmd_version()`:


---- ----
int cmd_walken(int argc, const char **argv, const char *prefix); int cmd_walken(int argc, const char **argv, const char *prefix, struct repository *repo);
---- ----


Include the command in `git.c` in `commands[]` near the entry for `whatchanged`, Include the command in `git.c` in `commands[]` near the entry for `version`,
maintaining alphabetical ordering: maintaining alphabetical ordering:


---- ----
{ "walken", cmd_walken, RUN_SETUP }, { "walken", cmd_walken, RUN_SETUP },
---- ----


Add it to the `Makefile` near the line for `builtin/worktree.o`: Add an entry for the new command in the both the Make and Meson build system,
before the entry for `worktree`:


- In the `Makefile`:
---- ----
...
BUILTIN_OBJS += builtin/walken.o BUILTIN_OBJS += builtin/walken.o
...
----

- In the `meson.build` file:
----
builtin_sources = [
...
'builtin/walken.c',
...
]
---- ----


Build and test out your command, without forgetting to ensure the `DEVELOPER` Build and test out your command, without forgetting to ensure the `DEVELOPER`
@ -193,7 +206,7 @@ initialization functions.


Next, we should have a look at any relevant configuration settings (i.e., Next, we should have a look at any relevant configuration settings (i.e.,
settings readable and settable from `git config`). This is done by providing a settings readable and settable from `git config`). This is done by providing a
callback to `git_config()`; within that callback, you can also invoke methods callback to `repo_config()`; within that callback, you can also invoke methods
from other components you may need that need to intercept these options. Your from other components you may need that need to intercept these options. Your
callback will be invoked once per each configuration value which Git knows about callback will be invoked once per each configuration value which Git knows about
(global, local, worktree, etc.). (global, local, worktree, etc.).
@ -221,14 +234,14 @@ static int git_walken_config(const char *var, const char *value,
} }
---- ----


Make sure to invoke `git_config()` with it in your `cmd_walken()`: Make sure to invoke `repo_config()` with it in your `cmd_walken()`:


---- ----
int cmd_walken(int argc, const char **argv, const char *prefix) int cmd_walken(int argc, const char **argv, const char *prefix, struct repository *repo)
{ {
... ...


git_config(git_walken_config, NULL); repo_config(repo, git_walken_config, NULL);


... ...
} }
@ -250,14 +263,14 @@ We'll also need to include the `revision.h` header:


... ...


int cmd_walken(int argc, const char **argv, const char *prefix) int cmd_walken(int argc, const char **argv, const char *prefix, struct repository *repo)
{ {
/* This can go wherever you like in your declarations.*/ /* This can go wherever you like in your declarations.*/
struct rev_info rev; struct rev_info rev;
... ...


/* This should go after the git_config() call. */ /* This should go after the repo_config() call. */
repo_init_revisions(the_repository, &rev, prefix); repo_init_revisions(repo, &rev, prefix);


... ...
} }
@ -305,7 +318,7 @@ Then let's invoke `final_rev_info_setup()` after the call to
`repo_init_revisions()`: `repo_init_revisions()`:


---- ----
int cmd_walken(int argc, const char **argv, const char *prefix) int cmd_walken(int argc, const char **argv, const char *prefix, struct repository *repo)
{ {
... ...



View File

@ -0,0 +1,73 @@
Git v2.43.7 Release Notes
=========================

This release includes fixes for CVE-2025-27613, CVE-2025-27614,
CVE-2025-46334, CVE-2025-46835, CVE-2025-48384, CVE-2025-48385, and
CVE-2025-48386.

Fixes since v2.43.6
-------------------

* CVE-2025-27613, Gitk:

When a user clones an untrusted repository and runs Gitk without
additional command arguments, any writable file can be created and
truncated. The option "Support per-file encoding" must have been
enabled. The operation "Show origin of this line" is affected as
well, regardless of the option being enabled or not.

* CVE-2025-27614, Gitk:

A Git repository can be crafted in such a way that a user who has
cloned the repository can be tricked into running any script
supplied by the attacker by invoking `gitk filename`, where
`filename` has a particular structure.

* CVE-2025-46334, Git GUI (Windows only):

A malicious repository can ship versions of sh.exe or typical
textconv filter programs such as astextplain. On Windows, path
lookup can find such executables in the worktree. These programs
are invoked when the user selects "Git Bash" or "Browse Files" from
the menu.

* CVE-2025-46835, Git GUI:

When a user clones an untrusted repository and is tricked into
editing a file located in a maliciously named directory in the
repository, then Git GUI can create and overwrite any writable
file.

* CVE-2025-48384, Git:

When reading a config value, Git strips any trailing carriage
return and line feed (CRLF). When writing a config entry, values
with a trailing CR are not quoted, causing the CR to be lost when
the config is later read. When initializing a submodule, if the
submodule path contains a trailing CR, the altered path is read
resulting in the submodule being checked out to an incorrect
location. If a symlink exists that points the altered path to the
submodule hooks directory, and the submodule contains an executable
post-checkout hook, the script may be unintentionally executed
after checkout.

* CVE-2025-48385, Git:

When cloning a repository Git knows to optionally fetch a bundle
advertised by the remote server, which allows the server-side to
offload parts of the clone to a CDN. The Git client does not
perform sufficient validation of the advertised bundles, which
allows the remote side to perform protocol injection.

This protocol injection can cause the client to write the fetched
bundle to a location controlled by the adversary. The fetched
content is fully controlled by the server, which can in the worst
case lead to arbitrary code execution.

* CVE-2025-48386, Git:

The wincred credential helper uses a static buffer (`target`) as a
unique key for storing and comparing against internal storage. This
credential helper does not properly bounds check the available
space remaining in the buffer before appending to it with
`wcsncat()`, leading to potential buffer overflows.

View File

@ -0,0 +1,7 @@
Git v2.44.4 Release Notes
=========================

This release merges up the fixes that appears in v2.43.7 to address
the following CVEs: CVE-2025-27613, CVE-2025-27614, CVE-2025-46334,
CVE-2025-46835, CVE-2025-48384, CVE-2025-48385, and CVE-2025-48386.
See the release notes for v2.43.7 for details.

View File

@ -0,0 +1,7 @@
Git v2.45.4 Release Notes
=========================

This release merges up the fixes that appears in v2.43.7, and v2.44.4
to address the following CVEs: CVE-2025-27613, CVE-2025-27614,
CVE-2025-46334, CVE-2025-46835, CVE-2025-48384, CVE-2025-48385, and
CVE-2025-48386. See the release notes for v2.43.7 for details.

View File

@ -0,0 +1,7 @@
Git v2.46.4 Release Notes
=========================

This release merges up the fixes that appears in v2.43.7, v2.44.4, and
v2.45.4 to address the following CVEs: CVE-2025-27613, CVE-2025-27614,
CVE-2025-46334, CVE-2025-46835, CVE-2025-48384, CVE-2025-48385, and
CVE-2025-48386. See the release notes for v2.43.7 for details.

View File

@ -0,0 +1,8 @@
Git v2.47.3 Release Notes
=========================

This release merges up the fixes that appears in v2.43.7, v2.44.4,
v2.45.4, and v2.46.4 to address the following CVEs: CVE-2025-27613,
CVE-2025-27614, CVE-2025-46334, CVE-2025-46835, CVE-2025-48384,
CVE-2025-48385, and CVE-2025-48386. See the release notes for v2.43.7
for details.

View File

@ -0,0 +1,8 @@
Git v2.48.2 Release Notes
=========================

This release merges up the fixes that appears in v2.43.7, v2.44.4,
v2.45.4, v2.46.4, and v2.47.3 to address the following CVEs:
CVE-2025-27613, CVE-2025-27614, CVE-2025-46334, CVE-2025-46835,
CVE-2025-48384, CVE-2025-48385, and CVE-2025-48386. See the release
notes for v2.43.7 for details.

View File

@ -0,0 +1,12 @@
Git v2.49.1 Release Notes
=========================

This release merges up the fixes that appear in v2.43.7, v2.44.4,
v2.45.4, v2.46.4, v2.47.3, and v2.48.2 to address the following CVEs:
CVE-2025-27613, CVE-2025-27614, CVE-2025-46334, CVE-2025-46835,
CVE-2025-48384, CVE-2025-48385, and CVE-2025-48386. See the release
notes for v2.43.7 for details.

It also contains some updates to various CI bits to work around
and/or to adjust to the deprecation of use of Ubuntu 20.04 GitHub
Actions CI, updates to to Fedora base image.

View File

@ -36,7 +36,7 @@ UI, Workflows & Features
* Auth-related (and unrelated) error handling in send-email has been * Auth-related (and unrelated) error handling in send-email has been
made more robust. made more robust.


* Updating multiple references have only been possible in all-or-none * Updating multiple references have only been possible in an all-or-nothing
fashion with transactions, but it can be more efficient to batch fashion with transactions, but it can be more efficient to batch
multiple updates even when some of them are allowed to fail in a multiple updates even when some of them are allowed to fail in a
best-effort manner. A new "best effort batches of updates" mode best-effort manner. A new "best effort batches of updates" mode
@ -53,7 +53,7 @@ UI, Workflows & Features


* The build procedure installs bash (but not zsh) completion script. * The build procedure installs bash (but not zsh) completion script.


* send-email has been updated to work better with Outlook's smtp server. * send-email has been updated to work better with Outlook's SMTP server.


* "git diff --minimal" used to give non-minimal output when its * "git diff --minimal" used to give non-minimal output when its
optimization kicked in, which has been disabled. optimization kicked in, which has been disabled.
@ -62,7 +62,7 @@ UI, Workflows & Features
delta chains from forming in a corner case even when there is no delta chains from forming in a corner case even when there is no
such cycle. such cycle.


* Make repository clean-up tasks "gc" can do available to "git * Make repository clean-up tasks that "gc" can do available to "git
maintenance" front-end. maintenance" front-end.


* Bundle-URI feature did not use refs recorded in the bundle other * Bundle-URI feature did not use refs recorded in the bundle other
@ -188,7 +188,7 @@ Performance, Internal Implementation, Development Support etc.
been dropped. been dropped.


* The code path to access the "packed-refs" file while "fsck" is * The code path to access the "packed-refs" file while "fsck" is
taught to mmap the file, instead of reading the whole file in the taught to mmap the file, instead of reading the whole file into
memory. memory.


* Assorted fixes for issues found with CodeQL. * Assorted fixes for issues found with CodeQL.
@ -201,6 +201,17 @@ Performance, Internal Implementation, Development Support etc.
we ended up checking for these non-existent files repeatedly, which we ended up checking for these non-existent files repeatedly, which
has been optimized by memoizing the non-existence. has been optimized by memoizing the non-existence.


* Build settings have been improved for BSD based systems.

* Newer version of libcURL detected curl_easy_setopt() calls we made
with platform-natural "int" when we should have used "long", which
all have been corrected.

* Tests that compare $HOME and $(pwd), which should be the same
directory unless the tests chdir's around, would fail when the user
enters the test directory via symbolic links, which has been
corrected.



Fixes since v2.49 Fixes since v2.49
----------------- -----------------
@ -316,8 +327,9 @@ Fixes since v2.49
* Fix for scheduled maintenance tasks on platforms using launchctl. * Fix for scheduled maintenance tasks on platforms using launchctl.
(merge eb2d7beb0e jh/gc-launchctl-schedule-fix later to maint). (merge eb2d7beb0e jh/gc-launchctl-schedule-fix later to maint).


* Update to arm64 Windows port. * Update to arm64 Windows port (part of which had been reverted as it
(merge 436a42215e js/windows-arm64 later to maint). broke builds for existing platforms, which may need to be redone in
future releases).


* hashmap API clean-up to ensure hashmap_clear() leaves a cleared map * hashmap API clean-up to ensure hashmap_clear() leaves a cleared map
in a reusable state. in a reusable state.
@ -380,14 +392,19 @@ Fixes since v2.49
reverse failed to give the mode bits of the path "removed" by the reverse failed to give the mode bits of the path "removed" by the
patch to the file it creates, which has been corrected. patch to the file it creates, which has been corrected.


* "git verify-refs" (and hence "git fsck --reference") started * "git verify-refs" errored out in a repository in which
erroring out in a repository in which secondary worktrees were linked worktrees were prepared with Git 2.43 or lower.
prepared with Git 2.43 or lower.
(merge d5b3c38b8a sj/ref-contents-check-fix later to maint). (merge d5b3c38b8a sj/ref-contents-check-fix later to maint).


* Update total_ram() functrion on BSD variants. * Update total_ram() function on BSD variants.


* Update online_cpus() functrion on BSD variants. * Update online_cpus() function on BSD variants.

* Revert a botched bswap.h change that broke ntohll() functions on
big-endian systems with __builtin_bswap32/64().

* Fixes for GitHub Actions Coverity job.
(merge 3cc4fc1ebd js/github-ci-win-coverity-fix later to maint).


* Other code cleanup, docfix, build fix, etc. * Other code cleanup, docfix, build fix, etc.
(merge 227c4f33a0 ja/doc-block-delimiter-markup-fix later to maint). (merge 227c4f33a0 ja/doc-block-delimiter-markup-fix later to maint).

View File

@ -0,0 +1,8 @@
Git v2.50.1 Release Notes
=========================

This release merges up the fixes that appear in v2.43.7, v2.44.4,
v2.45.4, v2.46.4, v2.47.3, v2.48.2, and v2.49.1 to address the
following CVEs: CVE-2025-27613, CVE-2025-27614, CVE-2025-46334,
CVE-2025-46835, CVE-2025-48384, CVE-2025-48385, and
CVE-2025-48386. See the release notes for v2.43.7 for details.

View File

@ -0,0 +1,222 @@
Git v2.51 Release Notes
=======================

UI, Workflows & Features
------------------------

* Userdiff patterns for the R language have been added.

* Documentation for "git send-email" has been updated with a bit more
credential helper and OAuth information.

* "git cat-file --batch" learns to understand %(objectmode) atom to
allow the caller to tell missing objects (due to repository
corruption) and submodules (whose commit objects are OK to be
missing) apart.

* "git diff --no-index dirA dirB" can limit the comparison with
pathspec at the end of the command line, just like normal "git
diff".

* "git subtree" (in contrib/) learned to grok GPG signing its commits.

* "git whatchanged" that is longer to type than "git log --raw"
which is its modern rough equivalent has outlived its usefulness
more than 10 years ago. Plan to deprecate and remove it.

* An interchange format for stash entries is defined, and subcommand
of "git stash" to import/export has been added.

* "git merge/pull" has been taught the "--compact-summary" option to
use the compact-summary format, intead of diffstat, when showing
the summary of the incoming changes.

* "git imap-send" has been broken for a long time, which has been
resurrected and then taught to talk OAuth2.0 etc.

* Some error messages from "git imap-send" has been updated.

* When "git daemon" sees a signal while attempting to accept() a new
client, instead of retrying, it skipped it by mistake, which has
been corrected.

* The reftable ref backend has matured enough; Git 3.0 will make it
the default format in a newly created repositories by default.

* "netrc" credential helper has been improved to understand textual
service names (like smtp) in addition to the numeric port numbers
(like 25).


Performance, Internal Implementation, Development Support etc.
--------------------------------------------------------------

* "git pack-objects" learned to find delta bases from blobs at the
same path, using the --path-walk API.

* CodingGuidelines update.

* Add settings for Solaris 10 & 11.

* Meson-based build/test framework now understands TAP output
generated by our tests.

* "Do not explicitly initialize to zero" rule has been clarified in
the CodingGuidelines document.

* A test helper "test_seq" function learned the "-f <fmt>" option,
which allowed us to simplify a lot of test scripts.

* A lot of stale stuff has been removed from the contrib/ hierarchy.

* "git push" and "git fetch" are taught to update refs in batches to
gain performance.

* Some code paths in the "git prune" used to ignore passed in
repository object and used the_repository singleton instance
instead, which has been corrected.

* Update ".clang-format" and ".editorconfig" to match our style guide
a bit better.

* "make coccicheck" succeeds even when spatch made suggestions, which
has been updated to fail in such a case.

* Code clean-up around object access API.

* Define .precision to more canned parse-options type to avoid bugs
coming from using a variable with a wrong type to capture the
parsed values.

* Flipping the default hash function to SHA-256 at Git 3.0 boundary
is planned.


Fixes since v2.50
-----------------

Unless otherwise noted, all the changes in 2.50.X maintenance track,
including security updates, are included in this release.

* A memory-leak in an error code path has been plugged.
(merge 7082da85cb ly/commit-graph-graph-write-leakfix later to maint).

* A memory-leak in an error code path has been plugged.
(merge aedebdb6b9 ly/fetch-pack-leakfix later to maint).

* Some leftover references to documentation source files that no
longer exist, due to recent ".txt" -> ".adoc" renaming, have been
corrected.
(merge 3717a5775a jw/doc-txt-to-adoc-refs later to maint).

* "git stash -p <pathspec>" improvements.
(merge 468817bab2 pw/stash-p-pathspec-fixes later to maint).

* "git send-email" incremented its internal message counter when a
message was edited, which made logic that treats the first message
specially misbehave, which has been corrected.
(merge 2cc27b3501 ag/send-email-edit-threading-fix later to maint).

* "git stash" recorded a wrong branch name when submodules are
present in the current checkout, which has been corrected.
(merge ffb36c64f2 kj/stash-onbranch-submodule-fix later to maint).

* When asking to apply mailmap to both author and committer field
while showing a commit object, the field that appears later was not
correctly parsed and replaced, which has been corrected.
(merge abf94a283f sa/multi-mailmap-fix later to maint).

* "git maintenance" lacked the care "git gc" had to avoid holding
onto the repository lock for too long during packing refs, which
has been remedied.
(merge 1b5074e614 ps/maintenance-ref-lock later to maint).

* Avoid regexp_constraint and instead use comparison_constraint when
listing functions to exclude from application of coccinelle rules,
as spatch can be built with different regexp engine X-<.
(merge f2ad545813 jc/cocci-avoid-regexp-constraint later to maint).

* Updating submodules from the upstream did not work well when
submodule's HEAD is detached, which has been improved.
(merge ca62f524c1 jk/submodule-remote-lookup-cleanup later to maint).

* Remove unnecessary check from "git daemon" code.
(merge 0c856224d2 cb/daemon-fd-check-fix later to maint).

* Use of sysctl() system call to learn the total RAM size used on
BSDs has been corrected.
(merge 781c1cf571 cb/total-ram-bsd-fix later to maint).

* Drop FreeBSD 4 support and declare that we support only FreeBSD 12
or later, which has memmem() supported.
(merge 0392f976a7 bs/config-mak-freebsd later to maint).

* A diff-filter with negative-only specification like "git log
--diff-filter=d" did not trigger correctly, which has been fixed.
(merge 375ac087c5 jk/all-negative-diff-filter-fix later to maint).

* A failure to open the index file for writing due to conflicting
access did not state what went wrong, which has been corrected.
(merge 9455397a5c hy/read-cache-lock-error-fix later to maint).

* Tempfile removal fix in the codepath to sign commits with SSH keys.
(merge 4498127b04 re/ssh-sign-buffer-fix later to maint).

* Code and test clean-up around string-list API.
(merge 6e5b26c3ff sj/string-list later to maint).

* "git apply -N" should start from the current index and register
only new files, but it instead started from an empty index, which
has been corrected.
(merge 2b49d97fcb rp/apply-intent-to-add-fix later to maint).

* Leakfix with a new and a bit invasive test on pack-bitmap files.
(merge bfd5522e98 ly/load-bitmap-leakfix later to maint).

* "git fetch --prune" used to be O(n^2) expensive when there are many
refs, which has been corrected.
(merge 87d8d8c5d0 ph/fetch-prune-optim later to maint).

* When a ref creation at refs/heads/foo/bar fails, the files backend
now removes refs/heads/foo/ if the directory is otherwise not used.
(merge a3a7f20516 ps/refs-files-remove-empty-parent later to maint).

* "pack-objects" has been taught to avoid pointing into objects in
cruft packs from midx.

* "git remote" now detects remote names that overlap with each other
(e.g., remote nickname "outer" and "outer/inner" are used at the
same time), as it will lead to overlapping remote-tracking
branches.
(merge a5a727c448 jk/remote-avoid-overlapping-names later to maint).

* The gpg.program configuration variable, which names a pathname to
the (custom) GPG compatible program, can now be spelled with ~tilde
expansion.
(merge 7d275cd5c0 jb/gpg-program-variable-is-a-pathname later to maint).

* Other code cleanup, docfix, build fix, etc.
(merge b257adb571 lo/my-first-ow-doc-update later to maint).
(merge 8b34b6a220 ly/sequencer-update-squash-is-fixup-only later to maint).
(merge 5dceb8bd05 ly/do-not-localize-bug-messages later to maint).
(merge 61372dd613 ly/commit-buffer-reencode-leakfix later to maint).
(merge 81cd1eef7d ly/pack-bitmap-root-leakfix later to maint).
(merge bfc9f9cc64 ly/submodule-update-failure-leakfix later to maint).
(merge 65dff89c6b ma/doc-diff-cc-headers later to maint).
(merge efb61591ee jm/bundle-uri-debug-output-to-fp later to maint).
(merge a3d278bb64 ly/prepare-show-merge-leakfix later to maint).
(merge 1fde1c5daf ac/preload-index-wo-the-repository later to maint).
(merge 855cfc65ae rm/t2400-modernize later to maint).
(merge 2939494284 ly/run-builtin-use-passed-in-repo later to maint).
(merge ff73f375bb jg/mailinfo-leakfix later to maint).
(merge 996f14c02b jj/doc-branch-markup-fix later to maint).
(merge 1e77de1864 cb/ci-freebsd-update-to-14.3 later to maint).
(merge b0e9d25865 jk/fix-leak-send-pack later to maint).
(merge f3a9558c8c bs/remote-helpers-doc-markup-fix later to maint).
(merge c4e9775c60 kh/doc-config-subcommands later to maint).
(merge de404249ab ps/perlless-test-fixes later to maint).
(merge 953049eed8 ts/merge-orig-head-doc-fix later to maint).
(merge 0c83bbc704 rj/freebsd-sysinfo-build-fix later to maint).
(merge ad7780b38f ps/doc-pack-refs-auto-with-files-backend-fix later to maint).
(merge f4fa8a3687 rh/doc-glob-pathspec-fix later to maint).
(merge b27be108c8 ja/doc-git-log-markup later to maint).

View File

@ -43,7 +43,7 @@ ifdef::doctype-book[]
endif::doctype-book[] endif::doctype-book[]


[literal-inlinemacro] [literal-inlinemacro]
{eval:re.sub(r'(&lt;[-a-zA-Z0-9.]+&gt;)', r'<emphasis>\1</emphasis>', re.sub(r'([\[\s|()>]|^|\]|&gt;)(\.?([-a-zA-Z0-9:+=~@\\\*\/_^\$]+\.?)+|,)',r'\1<literal>\2</literal>', re.sub(r'(\.\.\.?)([^\]$.])', r'<literal>\1</literal>\2', macros.passthroughs[int(attrs['passtext'][1:-1])] if attrs['passtext'][1:-1].isnumeric() else attrs['passtext'][1:-1])))} {eval:re.sub(r'(&lt;[-a-zA-Z0-9.]+&gt;)', r'<emphasis>\1</emphasis>', re.sub(r'([\[\s|()>]|^|\]|&gt;)(\.?([-a-zA-Z0-9:+=~@\\\*\/_^\$%]+\.?)+|,)',r'\1<literal>\2</literal>', re.sub(r'(\.\.\.?)([^\]$.])', r'<literal>\1</literal>\2', macros.passthroughs[int(attrs['passtext'][1:-1])] if attrs['passtext'][1:-1].isnumeric() else attrs['passtext'][1:-1])))}


endif::backend-docbook[] endif::backend-docbook[]



View File

@ -73,7 +73,7 @@ module Git
elsif type == :monospaced elsif type == :monospaced
node.text.gsub(/(\.\.\.?)([^\]$\.])/, '<literal>\1</literal>\2') node.text.gsub(/(\.\.\.?)([^\]$\.])/, '<literal>\1</literal>\2')
.gsub(/^\.\.\.?$/, '<literal>\0</literal>') .gsub(/^\.\.\.?$/, '<literal>\0</literal>')
.gsub(%r{([\[\s|()>.]|^|\]|&gt;)(\.?([-a-zA-Z0-9:+=~@/_^\$\\\*]+\.{0,2})+|,)}, '\1<literal>\2</literal>') .gsub(%r{([\[\s|()>.]|^|\]|&gt;)(\.?([-a-zA-Z0-9:+=~@/_^\$\\\*%]+\.{0,2})+|,)}, '\1<literal>\2</literal>')
.gsub(/(&lt;[-a-zA-Z0-9.]+&gt;)/, '<emphasis>\1</emphasis>') .gsub(/(&lt;[-a-zA-Z0-9.]+&gt;)/, '<emphasis>\1</emphasis>')
else else
open, close, supports_phrase = QUOTE_TAGS[type] open, close, supports_phrase = QUOTE_TAGS[type]
@ -102,7 +102,7 @@ module Git
if node.type == :monospaced if node.type == :monospaced
node.text.gsub(/(\.\.\.?)([^\]$.])/, '<code>\1</code>\2') node.text.gsub(/(\.\.\.?)([^\]$.])/, '<code>\1</code>\2')
.gsub(/^\.\.\.?$/, '<code>\0</code>') .gsub(/^\.\.\.?$/, '<code>\0</code>')
.gsub(%r{([\[\s|()>.]|^|\]|&gt;)(\.?([-a-zA-Z0-9:+=~@,/_^\$\\\*]+\.{0,2})+)}, '\1<code>\2</code>') .gsub(%r{([\[\s|()>.]|^|\]|&gt;)(\.?([-a-zA-Z0-9:+=~@,/_^\$\\\*%]+\.{0,2})+)}, '\1<code>\2</code>')
.gsub(/(&lt;[-a-zA-Z0-9.]+&gt;)/, '<em>\1</em>') .gsub(/(&lt;[-a-zA-Z0-9.]+&gt;)/, '<em>\1</em>')


else else

View File

@ -69,9 +69,9 @@ This option defaults to `never`.
`git fetch`) to lookup the default branch for merging. Without `git fetch`) to lookup the default branch for merging. Without
this option, `git pull` defaults to merge the first refspec fetched. this option, `git pull` defaults to merge the first refspec fetched.
Specify multiple values to get an octopus merge. Specify multiple values to get an octopus merge.
If you wish to setup `git pull` so that it merges into <name> from If you wish to setup `git pull` so that it merges into _<name>_ from
another branch in the local repository, you can point another branch in the local repository, you can point
branch.<name>.merge to the desired branch, and use the relative path `branch.<name>.merge` to the desired branch, and use the relative path
setting `.` (a period) for `branch.<name>.remote`. setting `.` (a period) for `branch.<name>.remote`.


`branch.<name>.mergeOptions`:: `branch.<name>.mergeOptions`::

View File

@ -20,6 +20,16 @@ walking fewer objects.
+ +
* `pack.allowPackReuse=multi` may improve the time it takes to create a pack by * `pack.allowPackReuse=multi` may improve the time it takes to create a pack by
reusing objects from multiple packs instead of just one. reusing objects from multiple packs instead of just one.
+
* `pack.usePathWalk` may speed up packfile creation and make the packfiles be
significantly smaller in the presence of certain filename collisions with Git's
default name-hash.
+
* `init.defaultRefFormat=reftable` causes newly initialized repositories to use
the reftable format for storing references. This new format solves issues with
case-insensitive filesystems, compresses better and performs significantly
better with many use cases. Refer to Documentation/technical/reftable.adoc for
more information on this new storage format.


feature.manyFiles:: feature.manyFiles::
Enable config options that optimize for repos with many files in the Enable config options that optimize for repos with many files in the

View File

@ -68,9 +68,15 @@ format.encodeEmailHeaders::
Defaults to true. Defaults to true.


format.pretty:: format.pretty::
ifndef::with-breaking-changes[]
The default pretty format for log/show/whatchanged command. The default pretty format for log/show/whatchanged command.
See linkgit:git-log[1], linkgit:git-show[1], See linkgit:git-log[1], linkgit:git-show[1],
linkgit:git-whatchanged[1]. linkgit:git-whatchanged[1].
endif::with-breaking-changes[]
ifdef::with-breaking-changes[]
The default pretty format for log/show command.
See linkgit:git-log[1], linkgit:git-show[1].
endif::with-breaking-changes[]


format.thread:: format.thread::
The default threading style for 'git format-patch'. Can be The default threading style for 'git format-patch'. Can be

View File

@ -47,7 +47,8 @@ gitcvs.dbDriver::
May not contain double colons (`:`). Default: 'SQLite'. May not contain double colons (`:`). Default: 'SQLite'.
See linkgit:git-cvsserver[1]. See linkgit:git-cvsserver[1].


gitcvs.dbUser, gitcvs.dbPass:: gitcvs.dbUser::
gitcvs.dbPass::
Database user and password. Only useful if setting `gitcvs.dbDriver`, Database user and password. Only useful if setting `gitcvs.dbDriver`,
since SQLite has no concept of database users and/or passwords. since SQLite has no concept of database users and/or passwords.
'gitcvs.dbUser' supports variable substitution (see 'gitcvs.dbUser' supports variable substitution (see

View File

@ -1,5 +1,5 @@
gpg.program:: gpg.program::
Use this custom program instead of "`gpg`" found on `$PATH` when Pathname of the program to use instead of "`gpg`" when
making or verifying a PGP signature. The program must support the making or verifying a PGP signature. The program must support the
same command-line interface as GPG, namely, to verify a detached same command-line interface as GPG, namely, to verify a detached
signature, "`gpg --verify $signature - <$file`" is run, and the signature, "`gpg --verify $signature - <$file`" is run, and the

View File

@ -289,7 +289,8 @@ for most push problems, but can increase memory consumption
significantly since the entire buffer is allocated even for small significantly since the entire buffer is allocated even for small
pushes. pushes.


http.lowSpeedLimit, http.lowSpeedTime:: http.lowSpeedLimit::
http.lowSpeedTime::
If the HTTP transfer speed, in bytes per second, is less than If the HTTP transfer speed, in bytes per second, is less than
'http.lowSpeedLimit' for longer than 'http.lowSpeedTime' seconds, 'http.lowSpeedLimit' for longer than 'http.lowSpeedTime' seconds,
the transfer is aborted. the transfer is aborted.

View File

@ -1,7 +1,9 @@
imap.folder:: imap.folder::
The folder to drop the mails into, which is typically the Drafts The folder to drop the mails into, which is typically the Drafts
folder. For example: "INBOX.Drafts", "INBOX/Drafts" or folder. For example: `INBOX.Drafts`, `INBOX/Drafts` or
"[Gmail]/Drafts". Required. `[Gmail]/Drafts`. The IMAP folder to interact with MUST be specified;
the value of this configuration variable is used as the fallback
default value when the `--folder` option is not given.


imap.tunnel:: imap.tunnel::
Command used to set up a tunnel to the IMAP server through which Command used to set up a tunnel to the IMAP server through which
@ -40,5 +42,6 @@ imap.authMethod::
Specify the authentication method for authenticating with the IMAP server. Specify the authentication method for authenticating with the IMAP server.
If Git was built with the NO_CURL option, or if your curl version is older If Git was built with the NO_CURL option, or if your curl version is older
than 7.34.0, or if you're running git-imap-send with the `--no-curl` than 7.34.0, or if you're running git-imap-send with the `--no-curl`
option, the only supported method is 'CRAM-MD5'. If this is not set option, the only supported methods are `PLAIN`, `CRAM-MD5`, `OAUTHBEARER`
then 'git imap-send' uses the basic IMAP plaintext LOGIN command. and `XOAUTH2`. If this is not set then `git imap-send` uses the basic IMAP
plaintext `LOGIN` command.

View File

@ -1,64 +1,76 @@
log.abbrevCommit:: `log.abbrevCommit`::
If true, makes linkgit:git-log[1], linkgit:git-show[1], and If `true`, make
linkgit:git-whatchanged[1] assume `--abbrev-commit`. You may ifndef::with-breaking-changes[]
linkgit:git-log[1], linkgit:git-show[1], and
linkgit:git-whatchanged[1]
endif::with-breaking-changes[]
ifdef::with-breaking-changes[]
linkgit:git-log[1] and linkgit:git-show[1]
endif::with-breaking-changes[]
assume `--abbrev-commit`. You may
override this option with `--no-abbrev-commit`. override this option with `--no-abbrev-commit`.


log.date:: `log.date`::
Set the default date-time mode for the 'log' command. Set the default date-time mode for the `log` command.
Setting a value for log.date is similar to using 'git log''s Setting a value for log.date is similar to using `git log`'s
`--date` option. See linkgit:git-log[1] for details. `--date` option. See linkgit:git-log[1] for details.
+ +
If the format is set to "auto:foo" and the pager is in use, format If the format is set to "auto:foo" and the pager is in use, format
"foo" will be used for the date format. Otherwise, "default" will "foo" will be used for the date format. Otherwise, "default" will
be used. be used.


log.decorate:: `log.decorate`::
Print out the ref names of any commits that are shown by the log Print out the ref names of any commits that are shown by the log
command. If 'short' is specified, the ref name prefixes 'refs/heads/', command. Possible values are:
'refs/tags/' and 'refs/remotes/' will not be printed. If 'full' is +
specified, the full ref name (including prefix) will be printed. ----
If 'auto' is specified, then if the output is going to a terminal, `short`;; the ref name prefixes `refs/heads/`, `refs/tags/` and
the ref names are shown as if 'short' were given, otherwise no ref `refs/remotes/` are not printed.
names are shown. This is the same as the `--decorate` option `full`;; the full ref name (including prefix) are printed.
of the `git log`. `auto`;; if the output is going to a terminal,
the ref names are shown as if `short` were given, otherwise no ref
names are shown.
----
+
This is the same as the `--decorate` option of the `git log`.


log.initialDecorationSet:: `log.initialDecorationSet`::
By default, `git log` only shows decorations for certain known ref By default, `git log` only shows decorations for certain known ref
namespaces. If 'all' is specified, then show all refs as namespaces. If 'all' is specified, then show all refs as
decorations. decorations.


log.excludeDecoration:: `log.excludeDecoration`::
Exclude the specified patterns from the log decorations. This is Exclude the specified patterns from the log decorations. This is
similar to the `--decorate-refs-exclude` command-line option, but similar to the `--decorate-refs-exclude` command-line option, but
the config option can be overridden by the `--decorate-refs` the config option can be overridden by the `--decorate-refs`
option. option.


log.diffMerges:: `log.diffMerges`::
Set diff format to be used when `--diff-merges=on` is Set diff format to be used when `--diff-merges=on` is
specified, see `--diff-merges` in linkgit:git-log[1] for specified, see `--diff-merges` in linkgit:git-log[1] for
details. Defaults to `separate`. details. Defaults to `separate`.


log.follow:: `log.follow`::
If `true`, `git log` will act as if the `--follow` option was used when If `true`, `git log` will act as if the `--follow` option was used when
a single <path> is given. This has the same limitations as `--follow`, a single <path> is given. This has the same limitations as `--follow`,
i.e. it cannot be used to follow multiple files and does not work well i.e. it cannot be used to follow multiple files and does not work well
on non-linear history. on non-linear history.


log.graphColors:: `log.graphColors`::
A list of colors, separated by commas, that can be used to draw A list of colors, separated by commas, that can be used to draw
history lines in `git log --graph`. history lines in `git log --graph`.


log.showRoot:: `log.showRoot`::
If true, the initial commit will be shown as a big creation event. If true, the initial commit will be shown as a big creation event.
This is equivalent to a diff against an empty tree. This is equivalent to a diff against an empty tree.
Tools like linkgit:git-log[1] or linkgit:git-whatchanged[1], which Tools like linkgit:git-log[1] or linkgit:git-whatchanged[1], which
normally hide the root commit will now show it. True by default. normally hide the root commit will now show it. True by default.


log.showSignature:: `log.showSignature`::
If true, makes linkgit:git-log[1], linkgit:git-show[1], and If true, makes linkgit:git-log[1], linkgit:git-show[1], and
linkgit:git-whatchanged[1] assume `--show-signature`. linkgit:git-whatchanged[1] assume `--show-signature`.


log.mailmap:: `log.mailmap`::
If true, makes linkgit:git-log[1], linkgit:git-show[1], and If true, makes linkgit:git-log[1], linkgit:git-show[1], and
linkgit:git-whatchanged[1] assume `--use-mailmap`, otherwise linkgit:git-whatchanged[1] assume `--use-mailmap`, otherwise
assume `--no-use-mailmap`. True by default. assume `--no-use-mailmap`. True by default.

View File

@ -81,8 +81,18 @@ as `false`. Defaults to `conflict`.
attributes" in linkgit:gitattributes[5]. attributes" in linkgit:gitattributes[5].


`merge.stat`:: `merge.stat`::
Whether to print the diffstat between `ORIG_HEAD` and the merge result What, if anything, to print between `ORIG_HEAD` and the merge result
at the end of the merge. True by default. at the end of the merge. Possible values are:
+
--
`false`;; Show nothing.
`true`;; Show `git diff --diffstat --summary ORIG_HEAD`.
`compact`;; Show `git diff --compact-summary ORIG_HEAD`.
--
+
but any unrecognised value (e.g., a value added by a future version of
Git) is taken as `true` instead of triggering an error. Defaults to
`true`.


`merge.autoStash`:: `merge.autoStash`::
When set to `true`, automatically create a temporary stash entry When set to `true`, automatically create a temporary stash entry

View File

@ -155,6 +155,10 @@ pack.useSparse::
commits contain certain types of direct renames. Default is commits contain certain types of direct renames. Default is
`true`. `true`.


pack.usePathWalk::
Enable the `--path-walk` option by default for `git pack-objects`
processes. See linkgit:git-pack-objects[1] for full details.

pack.preferBitmapTips:: pack.preferBitmapTips::
When selecting which commits will receive bitmaps, prefer a When selecting which commits will receive bitmaps, prefer a
commit at the tip of any reference that is a suffix of any value commit at the tip of any reference that is a suffix of any value

View File

@ -39,3 +39,10 @@ repack.cruftThreads::
a cruft pack and the respective parameters are not given over a cruft pack and the respective parameters are not given over
the command line. See similarly named `pack.*` configuration the command line. See similarly named `pack.*` configuration
variables for defaults and meaning. variables for defaults and meaning.

repack.midxMustContainCruft::
When set to true, linkgit:git-repack[1] will unconditionally include
cruft pack(s), if any, in the multi-pack index when invoked with
`--write-midx`. When false, cruft packs are only included in the MIDX
when necessary (e.g., because they might be required to form a
reachability closure with MIDX bitmaps). Defaults to true.

View File

@ -1,38 +1,38 @@
sendemail.identity:: sendemail.identity::
A configuration identity. When given, causes values in the A configuration identity. When given, causes values in the
'sendemail.<identity>' subsection to take precedence over `sendemail.<identity>` subsection to take precedence over
values in the 'sendemail' section. The default identity is values in the `sendemail` section. The default identity is
the value of `sendemail.identity`. the value of `sendemail.identity`.


sendemail.smtpEncryption:: sendemail.smtpEncryption::
See linkgit:git-send-email[1] for description. Note that this See linkgit:git-send-email[1] for description. Note that this
setting is not subject to the 'identity' mechanism. setting is not subject to the `identity` mechanism.


sendemail.smtpSSLCertPath:: sendemail.smtpSSLCertPath::
Path to ca-certificates (either a directory or a single file). Path to ca-certificates (either a directory or a single file).
Set it to an empty string to disable certificate verification. Set it to an empty string to disable certificate verification.


sendemail.<identity>.*:: sendemail.<identity>.*::
Identity-specific versions of the 'sendemail.*' parameters Identity-specific versions of the `sendemail.*` parameters
found below, taking precedence over those when this found below, taking precedence over those when this
identity is selected, through either the command-line or identity is selected, through either the command-line or
`sendemail.identity`. `sendemail.identity`.


sendemail.multiEdit:: sendemail.multiEdit::
If true (default), a single editor instance will be spawned to edit If `true` (default), a single editor instance will be spawned to edit
files you have to edit (patches when `--annotate` is used, and the files you have to edit (patches when `--annotate` is used, and the
summary when `--compose` is used). If false, files will be edited one summary when `--compose` is used). If `false`, files will be edited one
after the other, spawning a new editor each time. after the other, spawning a new editor each time.


sendemail.confirm:: sendemail.confirm::
Sets the default for whether to confirm before sending. Must be Sets the default for whether to confirm before sending. Must be
one of 'always', 'never', 'cc', 'compose', or 'auto'. See `--confirm` one of `always`, `never`, `cc`, `compose`, or `auto`. See `--confirm`
in the linkgit:git-send-email[1] documentation for the meaning of these in the linkgit:git-send-email[1] documentation for the meaning of these
values. values.


sendemail.mailmap:: sendemail.mailmap::
If true, makes linkgit:git-send-email[1] assume `--mailmap`, If `true`, makes linkgit:git-send-email[1] assume `--mailmap`,
otherwise assume `--no-mailmap`. False by default. otherwise assume `--no-mailmap`. `False` by default.


sendemail.mailmap.file:: sendemail.mailmap.file::
The location of a linkgit:git-send-email[1] specific augmenting The location of a linkgit:git-send-email[1] specific augmenting
@ -51,7 +51,7 @@ sendemail.aliasesFile::


sendemail.aliasFileType:: sendemail.aliasFileType::
Format of the file(s) specified in sendemail.aliasesFile. Must be Format of the file(s) specified in sendemail.aliasesFile. Must be
one of 'mutt', 'mailrc', 'pine', 'elm', 'gnus', or 'sendmail'. one of `mutt`, `mailrc`, `pine`, `elm`, `gnus`, or `sendmail`.
+ +
What an alias file in each format looks like can be found in What an alias file in each format looks like can be found in
the documentation of the email program of the same name. The the documentation of the email program of the same name. The
@ -96,12 +96,17 @@ sendemail.xmailer::
linkgit:git-send-email[1] command-line options. See its linkgit:git-send-email[1] command-line options. See its
documentation for details. documentation for details.


sendemail.outlookidfix::
If `true`, makes linkgit:git-send-email[1] assume `--outlook-id-fix`,
and if `false` assume `--no-outlook-id-fix`. If not specified, it will
behave the same way as if `--outlook-id-fix` is not specified.

sendemail.signedOffCc (deprecated):: sendemail.signedOffCc (deprecated)::
Deprecated alias for `sendemail.signedOffByCc`. Deprecated alias for `sendemail.signedOffByCc`.


sendemail.smtpBatchSize:: sendemail.smtpBatchSize::
Number of messages to be sent per connection, after that a relogin Number of messages to be sent per connection, after that a relogin
will happen. If the value is 0 or undefined, send all messages in will happen. If the value is `0` or undefined, send all messages in
one connection. one connection.
See also the `--batch-size` option of linkgit:git-send-email[1]. See also the `--batch-size` option of linkgit:git-send-email[1].


@ -111,5 +116,5 @@ sendemail.smtpReloginDelay::


sendemail.forbidSendmailVariables:: sendemail.forbidSendmailVariables::
To avoid common misconfiguration mistakes, linkgit:git-send-email[1] To avoid common misconfiguration mistakes, linkgit:git-send-email[1]
will abort with a warning if any configuration options for "sendmail" will abort with a warning if any configuration options for `sendmail`
exist. Set this variable to bypass the check. exist. Set this variable to bypass the check.

View File

@ -138,7 +138,7 @@ or like this (when the `--cc` option is used):
+ +
[synopsis] [synopsis]
index <hash>,<hash>..<hash> index <hash>,<hash>..<hash>
mode <mode>,<mode>`..`<mode> mode <mode>,<mode>..<mode>
new file mode <mode> new file mode <mode>
deleted file mode <mode>,<mode> deleted file mode <mode>,<mode>
+ +

View File

@ -37,32 +37,32 @@ endif::git-diff[]
endif::git-format-patch[] endif::git-format-patch[]


ifdef::git-log[] ifdef::git-log[]
-m:: `-m`::
Show diffs for merge commits in the default format. This is Show diffs for merge commits in the default format. This is
similar to `--diff-merges=on`, except `-m` will similar to `--diff-merges=on`, except `-m` will
produce no output unless `-p` is given as well. produce no output unless `-p` is given as well.


-c:: `-c`::
Produce combined diff output for merge commits. Produce combined diff output for merge commits.
Shortcut for `--diff-merges=combined -p`. Shortcut for `--diff-merges=combined -p`.


--cc:: `--cc`::
Produce dense combined diff output for merge commits. Produce dense combined diff output for merge commits.
Shortcut for `--diff-merges=dense-combined -p`. Shortcut for `--diff-merges=dense-combined -p`.


--dd:: `--dd`::
Produce diff with respect to first parent for both merge and Produce diff with respect to first parent for both merge and
regular commits. regular commits.
Shortcut for `--diff-merges=first-parent -p`. Shortcut for `--diff-merges=first-parent -p`.


--remerge-diff:: `--remerge-diff`::
Produce remerge-diff output for merge commits. Produce remerge-diff output for merge commits.
Shortcut for `--diff-merges=remerge -p`. Shortcut for `--diff-merges=remerge -p`.


--no-diff-merges:: `--no-diff-merges`::
Synonym for `--diff-merges=off`. Synonym for `--diff-merges=off`.


--diff-merges=<format>:: `--diff-merges=<format>`::
Specify diff format to be used for merge commits. Default is Specify diff format to be used for merge commits. Default is
{diff-merges-default} unless `--first-parent` is in use, in {diff-merges-default} unless `--first-parent` is in use, in
which case `first-parent` is the default. which case `first-parent` is the default.
@ -70,48 +70,54 @@ ifdef::git-log[]
The following formats are supported: The following formats are supported:
+ +
-- --
off, none:: `off`::
`none`::
Disable output of diffs for merge commits. Useful to override Disable output of diffs for merge commits. Useful to override
implied value. implied value.


on, m:: `on`::
`m`::
Make diff output for merge commits to be shown in the default Make diff output for merge commits to be shown in the default
format. The default format can be changed using format. The default format can be changed using
`log.diffMerges` configuration variable, whose default value `log.diffMerges` configuration variable, whose default value
is `separate`. is `separate`.


first-parent, 1:: `first-parent`::
`1`::
Show full diff with respect to first parent. This is the same Show full diff with respect to first parent. This is the same
format as `--patch` produces for non-merge commits. format as `--patch` produces for non-merge commits.


separate:: `separate`::
Show full diff with respect to each of parents. Show full diff with respect to each of parents.
Separate log entry and diff is generated for each parent. Separate log entry and diff is generated for each parent.


combined, c:: `combined`::
`c`::
Show differences from each of the parents to the merge Show differences from each of the parents to the merge
result simultaneously instead of showing pairwise diff between result simultaneously instead of showing pairwise diff between
a parent and the result one at a time. Furthermore, it lists a parent and the result one at a time. Furthermore, it lists
only files which were modified from all parents. only files which were modified from all parents.


dense-combined, cc:: `dense-combined`::
`cc`::
Further compress output produced by `--diff-merges=combined` Further compress output produced by `--diff-merges=combined`
by omitting uninteresting hunks whose contents in the parents by omitting uninteresting hunks whose contents in the parents
have only two variants and the merge result picks one of them have only two variants and the merge result picks one of them
without modification. without modification.


remerge, r:: `remerge`::
Remerge two-parent merge commits to create a temporary tree `r`:: Remerge two-parent merge commits to create a temporary tree
object--potentially containing files with conflict markers object--potentially containing files with conflict markers
and such. A diff is then shown between that temporary tree and such. A diff is then shown between that temporary tree
and the actual merge commit. and the actual merge commit.
--
+ +
The output emitted when this option is used is subject to change, and The output emitted when this option is used is subject to change, and
so is its interaction with other options (unless explicitly so is its interaction with other options (unless explicitly
documented). documented).
--


--combined-all-paths::
`--combined-all-paths`::
Cause combined diffs (used for merge commits) to Cause combined diffs (used for merge commits) to
list the name of the file from all parents. It thus only has list the name of the file from all parents. It thus only has
effect when `--diff-merges=[dense-]combined` is in use, and effect when `--diff-merges=[dense-]combined` is in use, and

View File

@ -75,13 +75,14 @@ OPTIONS
tree. If `--check` is in effect, merely check that it would tree. If `--check` is in effect, merely check that it would
apply cleanly to the index entry. apply cleanly to the index entry.


-N::
--intent-to-add:: --intent-to-add::
When applying the patch only to the working tree, mark new When applying the patch only to the working tree, mark new
files to be added to the index later (see `--intent-to-add` files to be added to the index later (see `--intent-to-add`
option in linkgit:git-add[1]). This option is ignored unless option in linkgit:git-add[1]). This option is ignored if
running in a Git repository and `--index` is not specified. `--index` or `--cached` are used, and has no effect outside a Git
Note that `--index` could be implied by other options such repository. Note that `--index` could be implied by other options
as `--cached` or `--3way`. such as `--3way`.


-3:: -3::
--3way:: --3way::

View File

@ -307,6 +307,11 @@ newline. The available atoms are:
`objecttype`:: `objecttype`::
The type of the object (the same as `cat-file -t` reports). The type of the object (the same as `cat-file -t` reports).


`objectmode`::
If the specified object has mode information (such as a tree or
index entry), the mode expressed as an octal integer. Otherwise,
empty string.

`objectsize`:: `objectsize`::
The size, in bytes, of the object (the same as `cat-file -s` The size, in bytes, of the object (the same as `cat-file -s`
reports). reports).
@ -368,6 +373,14 @@ If a name is specified that might refer to more than one object (an ambiguous sh
<object> SP ambiguous LF <object> SP ambiguous LF
------------ ------------


If a name is specified that refers to a submodule entry in a tree and the
target object does not exist in the repository, then `cat-file` will ignore
any custom format and print (with the object ID of the submodule):

------------
<oid> SP submodule LF
------------

If `--follow-symlinks` is used, and a symlink in the repository points If `--follow-symlinks` is used, and a symlink in the repository points
outside the repository, then `cat-file` will ignore any custom format outside the repository, then `cat-file` will ignore any custom format
and print: and print:

View File

@ -10,9 +10,9 @@ SYNOPSIS
-------- --------
[verse] [verse]
'git config list' [<file-option>] [<display-option>] [--includes] 'git config list' [<file-option>] [<display-option>] [--includes]
'git config get' [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name> 'git config get' [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<pattern>] [--fixed-value] [--default=<default>] [--url=<url>] <name>
'git config set' [<file-option>] [--type=<type>] [--all] [--value=<value>] [--fixed-value] <name> <value> 'git config set' [<file-option>] [--type=<type>] [--all] [--value=<pattern>] [--fixed-value] <name> <value>
'git config unset' [<file-option>] [--all] [--value=<value>] [--fixed-value] <name> 'git config unset' [<file-option>] [--all] [--value=<pattern>] [--fixed-value] <name>
'git config rename-section' [<file-option>] <old-name> <new-name> 'git config rename-section' [<file-option>] <old-name> <new-name>
'git config remove-section' [<file-option>] <name> 'git config remove-section' [<file-option>] <name>
'git config edit' [<file-option>] 'git config edit' [<file-option>]
@ -26,7 +26,7 @@ escaped.


Multiple lines can be added to an option by using the `--append` option. Multiple lines can be added to an option by using the `--append` option.
If you want to update or unset an option which can occur on multiple If you want to update or unset an option which can occur on multiple
lines, a `value-pattern` (which is an extended regular expression, lines, `--value=<pattern>` (which is an extended regular expression,
unless the `--fixed-value` option is given) needs to be given. Only the unless the `--fixed-value` option is given) needs to be given. Only the
existing values that match the pattern are updated or unset. If existing values that match the pattern are updated or unset. If
you want to handle the lines that do *not* match the pattern, just you want to handle the lines that do *not* match the pattern, just
@ -109,7 +109,7 @@ OPTIONS


--replace-all:: --replace-all::
Default behavior is to replace at most one line. This replaces Default behavior is to replace at most one line. This replaces
all lines matching the key (and optionally the `value-pattern`). all lines matching the key (and optionally `--value=<pattern>`).


--append:: --append::
Adds a new line to the option without altering any existing Adds a new line to the option without altering any existing
@ -200,11 +200,19 @@ See also <<FILES>>.
section in linkgit:gitrevisions[7] for a more complete list of section in linkgit:gitrevisions[7] for a more complete list of
ways to spell blob names. ways to spell blob names.


`--value=<pattern>`::
`--no-value`::
With `get`, `set`, and `unset`, match only against
_<pattern>_. The pattern is an extended regular expression unless
`--fixed-value` is given.
+
Use `--no-value` to unset _<pattern>_.

--fixed-value:: --fixed-value::
When used with the `value-pattern` argument, treat `value-pattern` as When used with `--value=<pattern>`, treat _<pattern>_ as
an exact string instead of a regular expression. This will restrict an exact string instead of a regular expression. This will restrict
the name/value pairs that are matched to only those where the value the name/value pairs that are matched to only those where the value
is exactly equal to the `value-pattern`. is exactly equal to _<pattern>_.


--type <type>:: --type <type>::
'git config' will ensure that any input or output is valid under the given 'git config' will ensure that any input or output is valid under the given
@ -259,6 +267,12 @@ Valid `<type>`'s include:
Output only the names of config variables for `list` or Output only the names of config variables for `list` or
`get`. `get`.


`--show-names`::
`--no-show-names`::
With `get`, show config keys in addition to their values. The
default is `--no-show-names` unless `--url` is given and there
are no subsections in _<name>_.

--show-origin:: --show-origin::
Augment the output of all queried config options with the Augment the output of all queried config options with the
origin type (file, standard input, blob, command line) and origin type (file, standard input, blob, command line) and

View File

@ -14,7 +14,7 @@ git diff [<options>] --cached [--merge-base] [<commit>] [--] [<path>...]
git diff [<options>] [--merge-base] <commit> [<commit>...] <commit> [--] [<path>...] git diff [<options>] [--merge-base] <commit> [<commit>...] <commit> [--] [<path>...]
git diff [<options>] <commit>...<commit> [--] [<path>...] git diff [<options>] <commit>...<commit> [--] [<path>...]
git diff [<options>] <blob> <blob> git diff [<options>] <blob> <blob>
git diff [<options>] --no-index [--] <path> <path> git diff [<options>] --no-index [--] <path> <path> [<pathspec>...]


DESCRIPTION DESCRIPTION
----------- -----------
@ -31,14 +31,18 @@ files on disk.
further add to the index but you still haven't. You can further add to the index but you still haven't. You can
stage these changes by using linkgit:git-add[1]. stage these changes by using linkgit:git-add[1].


`git diff [<options>] --no-index [--] <path> <path>`:: `git diff [<options>] --no-index [--] <path> <path> [<pathspec>...]`::


This form is to compare the given two paths on the This form is to compare the given two paths on the
filesystem. You can omit the `--no-index` option when filesystem. You can omit the `--no-index` option when
running the command in a working tree controlled by Git and running the command in a working tree controlled by Git and
at least one of the paths points outside the working tree, at least one of the paths points outside the working tree,
or when running the command outside a working tree or when running the command outside a working tree
controlled by Git. This form implies `--exit-code`. controlled by Git. This form implies `--exit-code`. If both
paths point to directories, additional pathspecs may be
provided. These will limit the files included in the
difference. All such pathspecs must be relative as they
apply to both sides of the diff.


`git diff [<options>] --cached [--merge-base] [<commit>] [--] [<path>...]`:: `git diff [<options>] --cached [--merge-base] [<commit>] [--] [<path>...]`::



View File

@ -9,21 +9,24 @@ git-imap-send - Send a collection of patches from stdin to an IMAP folder
SYNOPSIS SYNOPSIS
-------- --------
[verse] [verse]
'git imap-send' [-v] [-q] [--[no-]curl] 'git imap-send' [-v] [-q] [--[no-]curl] [(--folder|-f) <folder>]
'git imap-send' --list




DESCRIPTION DESCRIPTION
----------- -----------
This command uploads a mailbox generated with 'git format-patch' This command uploads a mailbox generated with `git format-patch`
into an IMAP drafts folder. This allows patches to be sent as into an IMAP drafts folder. This allows patches to be sent as
other email is when using mail clients that cannot read mailbox other email is when using mail clients that cannot read mailbox
files directly. The command also works with any general mailbox files directly. The command also works with any general mailbox
in which emails have the fields "From", "Date", and "Subject" in in which emails have the fields `From`, `Date`, and `Subject` in
that order. that order.


Typical usage is something like: Typical usage is something like:


git format-patch --signoff --stdout --attach origin | git imap-send ------
$ git format-patch --signoff --stdout --attach origin | git imap-send
------




OPTIONS OPTIONS
@ -37,6 +40,11 @@ OPTIONS
--quiet:: --quiet::
Be quiet. Be quiet.


-f <folder>::
--folder=<folder>::
Specify the folder in which the emails have to saved.
For example: `--folder=[Gmail]/Drafts` or `-f INBOX/Drafts`.

--curl:: --curl::
Use libcurl to communicate with the IMAP server, unless tunneling Use libcurl to communicate with the IMAP server, unless tunneling
into it. Ignored if Git was built without the USE_CURL_FOR_IMAP_SEND into it. Ignored if Git was built without the USE_CURL_FOR_IMAP_SEND
@ -47,6 +55,8 @@ OPTIONS
using libcurl. Ignored if Git was built with the NO_OPENSSL option using libcurl. Ignored if Git was built with the NO_OPENSSL option
set. set.


--list::
Run the IMAP LIST command to output a list of all the folders present.


CONFIGURATION CONFIGURATION
------------- -------------
@ -102,20 +112,56 @@ Using Gmail's IMAP interface:


--------- ---------
[imap] [imap]
folder = "[Gmail]/Drafts" folder = "[Gmail]/Drafts"
host = imaps://imap.gmail.com host = imaps://imap.gmail.com
user = user@gmail.com user = user@gmail.com
port = 993 port = 993
--------- ---------


Gmail does not allow using your regular password for `git imap-send`.
If you have multi-factor authentication set up on your Gmail account, you
can generate an app-specific password for use with `git imap-send`.
Visit https://security.google.com/settings/security/apppasswords to create
it. Alternatively, use OAuth2.0 authentication as described below.

[NOTE] [NOTE]
You might need to instead use: `folder = "[Google Mail]/Drafts"` if you get an error You might need to instead use: `folder = "[Google Mail]/Drafts"` if you get an error
that the "Folder doesn't exist". that the "Folder doesn't exist". You can also run `git imap-send --list` to get a
list of available folders.


[NOTE] [NOTE]
If your Gmail account is set to another language than English, the name of the "Drafts" If your Gmail account is set to another language than English, the name of the "Drafts"
folder will be localized. folder will be localized.


If you want to use OAuth2.0 based authentication, you can specify
`OAUTHBEARER` or `XOAUTH2` mechanism in your config. It is more secure
than using app-specific passwords, and also does not enforce the need of
having multi-factor authentication. You will have to use an OAuth2.0
access token in place of your password when using this authentication.

---------
[imap]
folder = "[Gmail]/Drafts"
host = imaps://imap.gmail.com
user = user@gmail.com
port = 993
authmethod = OAUTHBEARER
---------

Using Outlook's IMAP interface:

Unlike Gmail, Outlook only supports OAuth2.0 based authentication. Also, it
supports only `XOAUTH2` as the mechanism.

---------
[imap]
folder = "Drafts"
host = imaps://outlook.office365.com
user = user@outlook.com
port = 993
authmethod = XOAUTH2
---------

Once the commits are ready to be sent, run the following command: Once the commits are ready to be sent, run the following command:


$ git format-patch --cover-letter -M --stdout origin/master | git imap-send $ git format-patch --cover-letter -M --stdout origin/master | git imap-send
@ -124,6 +170,10 @@ Just make sure to disable line wrapping in the email client (Gmail's web
interface will wrap lines no matter what, so you need to use a real interface will wrap lines no matter what, so you need to use a real
IMAP client). IMAP client).


In case you are using OAuth2.0 authentication, it is easier to use credential
helpers to generate tokens. Credential helpers suggested in
linkgit:git-send-email[1] can be used for `git imap-send` as well.

CAUTION CAUTION
------- -------
It is still your responsibility to make sure that the email message It is still your responsibility to make sure that the email message

View File

@ -8,8 +8,8 @@ git-log - Show commit logs


SYNOPSIS SYNOPSIS
-------- --------
[verse] [synopsis]
'git log' [<options>] [<revision-range>] [[--] <path>...] git log [<options>] [<revision-range>] [[--] <path>...]


DESCRIPTION DESCRIPTION
----------- -----------
@ -27,28 +27,34 @@ each commit introduces are shown.
OPTIONS OPTIONS
------- -------


--follow:: `--follow`::
Continue listing the history of a file beyond renames Continue listing the history of a file beyond renames
(works only for a single file). (works only for a single file).


--no-decorate:: `--no-decorate`::
--decorate[=short|full|auto|no]:: `--decorate[=(short|full|auto|no)]`::
Print out the ref names of any commits that are shown. If 'short' is Print out the ref names of any commits that are shown. Possible values
specified, the ref name prefixes 'refs/heads/', 'refs/tags/' and are:
'refs/remotes/' will not be printed. If 'full' is specified, the +
full ref name (including prefix) will be printed. If 'auto' is ----
specified, then if the output is going to a terminal, the ref names `short`;; the ref name prefixes `refs/heads/`, `refs/tags/` and
are shown as if 'short' were given, otherwise no ref names are `refs/remotes/` are not printed.
shown. The option `--decorate` is short-hand for `--decorate=short`. `full`;; the full ref name (including prefix) is printed.
Default to configuration value of `log.decorate` if configured, `auto`:: if the output is going to a terminal, the ref names
otherwise, `auto`. are shown as if `short` were given, otherwise no ref names are
shown.
----
+
The option `--decorate` is short-hand for `--decorate=short`. Default to
configuration value of `log.decorate` if configured, otherwise, `auto`.


--decorate-refs=<pattern>:: `--decorate-refs=<pattern>`::
--decorate-refs-exclude=<pattern>:: `--decorate-refs-exclude=<pattern>`::
For each candidate reference, do not use it for decoration if it For each candidate reference, do not use it for decoration if it
matches any patterns given to `--decorate-refs-exclude` or if it matches any of the _<pattern>_ parameters given to
doesn't match any of the patterns given to `--decorate-refs`. The `--decorate-refs-exclude` or if it doesn't match any of the
`log.excludeDecoration` config option allows excluding refs from _<pattern>_ parameters given to `--decorate-refs`.
The `log.excludeDecoration` config option allows excluding refs from
the decorations, but an explicit `--decorate-refs` pattern will the decorations, but an explicit `--decorate-refs` pattern will
override a match in `log.excludeDecoration`. override a match in `log.excludeDecoration`.
+ +
@ -56,51 +62,51 @@ If none of these options or config settings are given, then references are
used as decoration if they match `HEAD`, `refs/heads/`, `refs/remotes/`, used as decoration if they match `HEAD`, `refs/heads/`, `refs/remotes/`,
`refs/stash/`, or `refs/tags/`. `refs/stash/`, or `refs/tags/`.


--clear-decorations:: `--clear-decorations`::
When specified, this option clears all previous `--decorate-refs` When specified, this option clears all previous `--decorate-refs`
or `--decorate-refs-exclude` options and relaxes the default or `--decorate-refs-exclude` options and relaxes the default
decoration filter to include all references. This option is decoration filter to include all references. This option is
assumed if the config value `log.initialDecorationSet` is set to assumed if the config value `log.initialDecorationSet` is set to
`all`. `all`.


--source:: `--source`::
Print out the ref name given on the command line by which each Print out the ref name given on the command line by which each
commit was reached. commit was reached.


--[no-]mailmap:: `--[no-]mailmap`::
--[no-]use-mailmap:: `--[no-]use-mailmap`::
Use mailmap file to map author and committer names and email Use mailmap file to map author and committer names and email
addresses to canonical real names and email addresses. See addresses to canonical real names and email addresses. See
linkgit:git-shortlog[1]. linkgit:git-shortlog[1].


--full-diff:: `--full-diff`::
Without this flag, `git log -p <path>...` shows commits that Without this flag, `git log -p <path>...` shows commits that
touch the specified paths, and diffs about the same specified touch the specified paths, and diffs about the same specified
paths. With this, the full diff is shown for commits that touch paths. With this, the full diff is shown for commits that touch
the specified paths; this means that "<path>..." limits only the specified paths; this means that "`<path>...`" limits only
commits, and doesn't limit diff for those commits. commits, and doesn't limit diff for those commits.
+ +
Note that this affects all diff-based output types, e.g. those Note that this affects all diff-based output types, e.g. those
produced by `--stat`, etc. produced by `--stat`, etc.


--log-size:: `--log-size`::
Include a line ``log size <number>'' in the output for each commit, Include a line `log size <number>` in the output for each commit,
where <number> is the length of that commit's message in bytes. where _<number>_ is the length of that commit's message in bytes.
Intended to speed up tools that read log messages from `git log` Intended to speed up tools that read log messages from `git log`
output by allowing them to allocate space in advance. output by allowing them to allocate space in advance.


include::line-range-options.adoc[] include::line-range-options.adoc[]


<revision-range>:: _<revision-range>_::
Show only commits in the specified revision range. When no Show only commits in the specified revision range. When no
<revision-range> is specified, it defaults to `HEAD` (i.e. the _<revision-range>_ is specified, it defaults to `HEAD` (i.e. the
whole history leading to the current commit). `origin..HEAD` whole history leading to the current commit). `origin..HEAD`
specifies all the commits reachable from the current commit specifies all the commits reachable from the current commit
(i.e. `HEAD`), but not from `origin`. For a complete list of (i.e. `HEAD`), but not from `origin`. For a complete list of
ways to spell <revision-range>, see the 'Specifying Ranges' ways to spell _<revision-range>_, see the 'Specifying Ranges'
section of linkgit:gitrevisions[7]. section of linkgit:gitrevisions[7].


[--] <path>...:: `[--] <path>...`::
Show only commits that are enough to explain how the files Show only commits that are enough to explain how the files
that match the specified paths came to be. See 'History that match the specified paths came to be. See 'History
Simplification' below for details and other simplification Simplification' below for details and other simplification
@ -145,14 +151,14 @@ EXAMPLES


`git log --since="2 weeks ago" -- gitk`:: `git log --since="2 weeks ago" -- gitk`::


Show the changes during the last two weeks to the file 'gitk'. Show the changes during the last two weeks to the file `gitk`.
The `--` is necessary to avoid confusion with the *branch* named The `--` is necessary to avoid confusion with the *branch* named
'gitk' `gitk`


`git log --name-status release..test`:: `git log --name-status release..test`::


Show the commits that are in the "test" branch but not yet Show the commits that are in the "`test`" branch but not yet
in the "release" branch, along with the list of paths in the "`release`" branch, along with the list of paths
each commit modifies. each commit modifies.


`git log --follow builtin/rev-list.c`:: `git log --follow builtin/rev-list.c`::
@ -164,7 +170,7 @@ EXAMPLES
`git log --branches --not --remotes=origin`:: `git log --branches --not --remotes=origin`::


Shows all commits that are in any of local branches but not in Shows all commits that are in any of local branches but not in
any of remote-tracking branches for 'origin' (what you have that any of remote-tracking branches for `origin` (what you have that
origin doesn't). origin doesn't).


`git log master --not --remotes=*/master`:: `git log master --not --remotes=*/master`::
@ -200,11 +206,11 @@ CONFIGURATION
See linkgit:git-config[1] for core variables and linkgit:git-diff[1] See linkgit:git-config[1] for core variables and linkgit:git-diff[1]
for settings related to diff generation. for settings related to diff generation.


format.pretty:: `format.pretty`::
Default for the `--format` option. (See 'Pretty Formats' above.) Default for the `--format` option. (See 'Pretty Formats' above.)
Defaults to `medium`. Defaults to `medium`.


i18n.logOutputEncoding:: `i18n.logOutputEncoding`::
Encoding to use when displaying logs. (See 'Discussion' above.) Encoding to use when displaying logs. (See 'Discussion' above.)
Defaults to the value of `i18n.commitEncoding` if set, and UTF-8 Defaults to the value of `i18n.commitEncoding` if set, and UTF-8
otherwise. otherwise.

View File

@ -172,7 +172,7 @@ rerere-gc::


worktree-prune:: worktree-prune::
The `worktree-prune` task deletes stale or broken worktrees. See The `worktree-prune` task deletes stale or broken worktrees. See
linkit:git-worktree[1] for more information. linkgit:git-worktree[1] for more information.


OPTIONS OPTIONS
------- -------

View File

@ -9,7 +9,7 @@ git-merge - Join two or more development histories together
SYNOPSIS SYNOPSIS
-------- --------
[synopsis] [synopsis]
git merge [-n] [--stat] [--no-commit] [--squash] [--[no-]edit] git merge [-n] [--stat] [--compact-summary] [--no-commit] [--squash] [--[no-]edit]
[--no-verify] [-s <strategy>] [-X <strategy-option>] [-S[<keyid>]] [--no-verify] [-s <strategy>] [-X <strategy-option>] [-S[<keyid>]]
[--[no-]allow-unrelated-histories] [--[no-]allow-unrelated-histories]
[--[no-]rerere-autoupdate] [-m <msg>] [-F <file>] [--[no-]rerere-autoupdate] [-m <msg>] [-F <file>]
@ -28,8 +28,8 @@ Assume the following history exists and the current branch is
`master`: `master`:


------------ ------------
A---B---C topic A---B---C topic
/ /
D---E---F---G master D---E---F---G master
------------ ------------


@ -38,11 +38,11 @@ Then `git merge topic` will replay the changes made on the
its current commit (`C`) on top of `master`, and record the result its current commit (`C`) on top of `master`, and record the result
in a new commit along with the names of the two parent commits and in a new commit along with the names of the two parent commits and
a log message from the user describing the changes. Before the operation, a log message from the user describing the changes. Before the operation,
`ORIG_HEAD` is set to the tip of the current branch (`C`). `ORIG_HEAD` is set to the tip of the current branch (`G`).


------------ ------------
A---B---C topic A---B---C topic
/ \ / \
D---E---F---G---H master D---E---F---G---H master
------------ ------------



View File

@ -10,13 +10,13 @@ SYNOPSIS
-------- --------
[verse] [verse]
'git pack-objects' [-q | --progress | --all-progress] [--all-progress-implied] 'git pack-objects' [-q | --progress | --all-progress] [--all-progress-implied]
[--no-reuse-delta] [--delta-base-offset] [--non-empty] [--no-reuse-delta] [--delta-base-offset] [--non-empty]
[--local] [--incremental] [--window=<n>] [--depth=<n>] [--local] [--incremental] [--window=<n>] [--depth=<n>]
[--revs [--unpacked | --all]] [--keep-pack=<pack-name>] [--revs [--unpacked | --all]] [--keep-pack=<pack-name>]
[--cruft] [--cruft-expiration=<time>] [--cruft] [--cruft-expiration=<time>]
[--stdout [--filter=<filter-spec>] | <base-name>] [--stdout [--filter=<filter-spec>] | <base-name>]
[--shallow] [--keep-true-parents] [--[no-]sparse] [--shallow] [--keep-true-parents] [--[no-]sparse]
[--name-hash-version=<n>] < <object-list> [--name-hash-version=<n>] [--path-walk] < <object-list>




DESCRIPTION DESCRIPTION
@ -87,13 +87,21 @@ base-name::
reference was included in the resulting packfile. This reference was included in the resulting packfile. This
can be useful to send new tags to native Git clients. can be useful to send new tags to native Git clients.


--stdin-packs:: --stdin-packs[=<mode>]::
Read the basenames of packfiles (e.g., `pack-1234abcd.pack`) Read the basenames of packfiles (e.g., `pack-1234abcd.pack`)
from the standard input, instead of object names or revision from the standard input, instead of object names or revision
arguments. The resulting pack contains all objects listed in the arguments. The resulting pack contains all objects listed in the
included packs (those not beginning with `^`), excluding any included packs (those not beginning with `^`), excluding any
objects listed in the excluded packs (beginning with `^`). objects listed in the excluded packs (beginning with `^`).
+ +
When `mode` is "follow", objects from packs not listed on stdin receive
special treatment. Objects within unlisted packs will be included if
those objects are (1) reachable from the included packs, and (2) not
found in any excluded packs. This mode is useful, for example, to
resurrect once-unreachable objects found in cruft packs to generate
packs which are closed under reachability up to the boundary set by the
excluded packs.
+
Incompatible with `--revs`, or options that imply `--revs` (such as Incompatible with `--revs`, or options that imply `--revs` (such as
`--all`), with the exception of `--unpacked`, which is compatible. `--all`), with the exception of `--unpacked`, which is compatible.


@ -375,6 +383,17 @@ many different directories. At the moment, this version is not allowed
when writing reachability bitmap files with `--write-bitmap-index` and it when writing reachability bitmap files with `--write-bitmap-index` and it
will be automatically changed to version `1`. will be automatically changed to version `1`.


--path-walk::
Perform compression by first organizing objects by path, then a
second pass that compresses across paths as normal. This has the
potential to improve delta compression especially in the presence
of filenames that cause collisions in Git's default name-hash
algorithm.
+
Incompatible with `--delta-islands`, `--shallow`, or `--filter`. The
`--use-bitmap-index` option will be ignored in the presence of
`--path-walk.`



DELTA ISLANDS DELTA ISLANDS
------------- -------------

View File

@ -66,7 +66,10 @@ Pack refs as needed depending on the current state of the ref database. The
behavior depends on the ref format used by the repository and may change in the behavior depends on the ref format used by the repository and may change in the
future. future.
+ +
- "files": No special handling for `--auto` has been implemented. - "files": Loose references are packed into the `packed-refs` file
based on the ratio of loose references to the size of the
`packed-refs` file. The bigger the `packed-refs` file, the more loose
references need to exist before we repack.
+ +
- "reftable": Tables are compacted such that they form a geometric - "reftable": Tables are compacted such that they form a geometric
sequence. For two tables N and N+1, where N+1 is newer, this sequence. For two tables N and N+1, where N+1 is newer, this

View File

@ -11,7 +11,7 @@ SYNOPSIS
[verse] [verse]
'git repack' [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m] 'git repack' [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]
[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>] [--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>]
[--write-midx] [--name-hash-version=<n>] [--write-midx] [--name-hash-version=<n>] [--path-walk]


DESCRIPTION DESCRIPTION
----------- -----------
@ -258,6 +258,9 @@ linkgit:git-multi-pack-index[1]).
Provide this argument to the underlying `git pack-objects` process. Provide this argument to the underlying `git pack-objects` process.
See linkgit:git-pack-objects[1] for full details. See linkgit:git-pack-objects[1] for full details.


--path-walk::
Pass the `--path-walk` option to the underlying `git pack-objects`
process. See linkgit:git-pack-objects[1] for full details.


CONFIGURATION CONFIGURATION
------------- -------------

View File

@ -21,7 +21,7 @@ Takes the patches given on the command line and emails them out.
Patches can be specified as files, directories (which will send all Patches can be specified as files, directories (which will send all
files in the directory), or directly as a revision list. In the files in the directory), or directly as a revision list. In the
last case, any format accepted by linkgit:git-format-patch[1] can last case, any format accepted by linkgit:git-format-patch[1] can
be passed to git send-email, as well as options understood by be passed to `git send-email`, as well as options understood by
linkgit:git-format-patch[1]. linkgit:git-format-patch[1].


The header of the email is configurable via command-line options. If not The header of the email is configurable via command-line options. If not
@ -35,11 +35,11 @@ There are two formats accepted for patch files:
This is what linkgit:git-format-patch[1] generates. Most headers and MIME This is what linkgit:git-format-patch[1] generates. Most headers and MIME
formatting are ignored. formatting are ignored.


2. The original format used by Greg Kroah-Hartman's 'send_lots_of_email.pl' 2. The original format used by Greg Kroah-Hartman's `send_lots_of_email.pl`
script script
+ +
This format expects the first line of the file to contain the "Cc:" value This format expects the first line of the file to contain the `Cc:` value
and the "Subject:" of the message as the second line. and the `Subject:` of the message as the second line.




OPTIONS OPTIONS
@ -54,13 +54,13 @@ Composing
`sendemail.multiEdit`. `sendemail.multiEdit`.


--bcc=<address>,...:: --bcc=<address>,...::
Specify a "Bcc:" value for each email. Default is the value of Specify a `Bcc:` value for each email. Default is the value of
`sendemail.bcc`. `sendemail.bcc`.
+ +
This option may be specified multiple times. This option may be specified multiple times.


--cc=<address>,...:: --cc=<address>,...::
Specify a starting "Cc:" value for each email. Specify a starting `Cc:` value for each email.
Default is the value of `sendemail.cc`. Default is the value of `sendemail.cc`.
+ +
This option may be specified multiple times. This option may be specified multiple times.
@ -69,14 +69,14 @@ This option may be specified multiple times.
Invoke a text editor (see GIT_EDITOR in linkgit:git-var[1]) Invoke a text editor (see GIT_EDITOR in linkgit:git-var[1])
to edit an introductory message for the patch series. to edit an introductory message for the patch series.
+ +
When `--compose` is used, git send-email will use the From, To, Cc, Bcc, When `--compose` is used, `git send-email` will use the `From`, `To`, `Cc`,
Subject, Reply-To, and In-Reply-To headers specified in the message. If `Bcc`, `Subject`, `Reply-To`, and `In-Reply-To` headers specified in the
the body of the message (what you type after the headers and a blank message. If the body of the message (what you type after the headers and a
line) only contains blank (or Git: prefixed) lines, the summary won't be blank line) only contains blank (or `Git:` prefixed) lines, the summary won't be
sent, but the headers mentioned above will be used unless they are sent, but the headers mentioned above will be used unless they are
removed. removed.
+ +
Missing From or In-Reply-To headers will be prompted for. Missing `From` or `In-Reply-To` headers will be prompted for.
+ +
See the CONFIGURATION section for `sendemail.multiEdit`. See the CONFIGURATION section for `sendemail.multiEdit`.


@ -85,13 +85,13 @@ See the CONFIGURATION section for `sendemail.multiEdit`.
the value of the `sendemail.from` configuration option is used. If the value of the `sendemail.from` configuration option is used. If
neither the command-line option nor `sendemail.from` are set, then the neither the command-line option nor `sendemail.from` are set, then the
user will be prompted for the value. The default for the prompt will be user will be prompted for the value. The default for the prompt will be
the value of GIT_AUTHOR_IDENT, or GIT_COMMITTER_IDENT if that is not the value of `GIT_AUTHOR_IDENT`, or `GIT_COMMITTER_IDENT` if that is not
set, as returned by "git var -l". set, as returned by `git var -l`.


--reply-to=<address>:: --reply-to=<address>::
Specify the address where replies from recipients should go to. Specify the address where replies from recipients should go to.
Use this if replies to messages should go to another address than what Use this if replies to messages should go to another address than what
is specified with the --from parameter. is specified with the `--from` parameter.


--in-reply-to=<identifier>:: --in-reply-to=<identifier>::
Make the first mail (or all the mails with `--no-thread`) appear as a Make the first mail (or all the mails with `--no-thread`) appear as a
@ -112,14 +112,14 @@ illustration below where `[PATCH v2 0/3]` is in reply to `[PATCH 0/2]`:
[PATCH v2 2/3] New tests [PATCH v2 2/3] New tests
[PATCH v2 3/3] Implementation [PATCH v2 3/3] Implementation
+ +
Only necessary if --compose is also set. If --compose Only necessary if `--compose` is also set. If `--compose`
is not set, this will be prompted for. is not set, this will be prompted for.


--[no-]outlook-id-fix:: --[no-]outlook-id-fix::
Microsoft Outlook SMTP servers discard the Message-ID sent via email and Microsoft Outlook SMTP servers discard the Message-ID sent via email and
assign a new random Message-ID, thus breaking threads. assign a new random Message-ID, thus breaking threads.
+ +
With `--outlook-id-fix`, 'git send-email' uses a mechanism specific to With `--outlook-id-fix`, `git send-email` uses a mechanism specific to
Outlook servers to learn the Message-ID the server assigned to fix the Outlook servers to learn the Message-ID the server assigned to fix the
threading. Use it only when you know that the server reports the threading. Use it only when you know that the server reports the
rewritten Message-ID the same way as Outlook servers do. rewritten Message-ID the same way as Outlook servers do.
@ -130,14 +130,14 @@ to 'smtp.office365.com' or 'smtp-mail.outlook.com'. Use


--subject=<string>:: --subject=<string>::
Specify the initial subject of the email thread. Specify the initial subject of the email thread.
Only necessary if --compose is also set. If --compose Only necessary if `--compose` is also set. If `--compose`
is not set, this will be prompted for. is not set, this will be prompted for.


--to=<address>,...:: --to=<address>,...::
Specify the primary recipient of the emails generated. Generally, this Specify the primary recipient of the emails generated. Generally, this
will be the upstream maintainer of the project involved. Default is the will be the upstream maintainer of the project involved. Default is the
value of the `sendemail.to` configuration value; if that is unspecified, value of the `sendemail.to` configuration value; if that is unspecified,
and --to-cmd is not specified, this will be prompted for. and `--to-cmd` is not specified, this will be prompted for.
+ +
This option may be specified multiple times. This option may be specified multiple times.


@ -145,30 +145,30 @@ This option may be specified multiple times.
When encountering a non-ASCII message or subject that does not When encountering a non-ASCII message or subject that does not
declare its encoding, add headers/quoting to indicate it is declare its encoding, add headers/quoting to indicate it is
encoded in <encoding>. Default is the value of the encoded in <encoding>. Default is the value of the
'sendemail.assume8bitEncoding'; if that is unspecified, this `sendemail.assume8bitEncoding`; if that is unspecified, this
will be prompted for if any non-ASCII files are encountered. will be prompted for if any non-ASCII files are encountered.
+ +
Note that no attempts whatsoever are made to validate the encoding. Note that no attempts whatsoever are made to validate the encoding.


--compose-encoding=<encoding>:: --compose-encoding=<encoding>::
Specify encoding of compose message. Default is the value of the Specify encoding of compose message. Default is the value of the
'sendemail.composeEncoding'; if that is unspecified, UTF-8 is assumed. `sendemail.composeEncoding`; if that is unspecified, UTF-8 is assumed.


--transfer-encoding=(7bit|8bit|quoted-printable|base64|auto):: --transfer-encoding=(7bit|8bit|quoted-printable|base64|auto)::
Specify the transfer encoding to be used to send the message over SMTP. Specify the transfer encoding to be used to send the message over SMTP.
7bit will fail upon encountering a non-ASCII message. quoted-printable `7bit` will fail upon encountering a non-ASCII message. `quoted-printable`
can be useful when the repository contains files that contain carriage can be useful when the repository contains files that contain carriage
returns, but makes the raw patch email file (as saved from a MUA) much returns, but makes the raw patch email file (as saved from an MUA) much
harder to inspect manually. base64 is even more fool proof, but also harder to inspect manually. `base64` is even more fool proof, but also
even more opaque. auto will use 8bit when possible, and quoted-printable even more opaque. `auto` will use `8bit` when possible, and
otherwise. `quoted-printable` otherwise.
+ +
Default is the value of the `sendemail.transferEncoding` configuration Default is the value of the `sendemail.transferEncoding` configuration
value; if that is unspecified, default to `auto`. value; if that is unspecified, default to `auto`.


--xmailer:: --xmailer::
--no-xmailer:: --no-xmailer::
Add (or prevent adding) the "X-Mailer:" header. By default, Add (or prevent adding) the `X-Mailer:` header. By default,
the header is added, but it can be turned off by setting the the header is added, but it can be turned off by setting the
`sendemail.xmailer` configuration variable to `false`. `sendemail.xmailer` configuration variable to `false`.


@ -178,9 +178,9 @@ Sending
--envelope-sender=<address>:: --envelope-sender=<address>::
Specify the envelope sender used to send the emails. Specify the envelope sender used to send the emails.
This is useful if your default address is not the address that is This is useful if your default address is not the address that is
subscribed to a list. In order to use the 'From' address, set the subscribed to a list. In order to use the `From` address, set the
value to "auto". If you use the sendmail binary, you must have value to `auto`. If you use the `sendmail` binary, you must have
suitable privileges for the -f parameter. Default is the value of the suitable privileges for the `-f` parameter. Default is the value of the
`sendemail.envelopeSender` configuration variable; if that is `sendemail.envelopeSender` configuration variable; if that is
unspecified, choosing the envelope sender is left to your MTA. unspecified, choosing the envelope sender is left to your MTA.


@ -189,27 +189,27 @@ Sending
be sendmail-like; specifically, it must support the `-i` option. be sendmail-like; specifically, it must support the `-i` option.
The command will be executed in the shell if necessary. Default The command will be executed in the shell if necessary. Default
is the value of `sendemail.sendmailCmd`. If unspecified, and if is the value of `sendemail.sendmailCmd`. If unspecified, and if
--smtp-server is also unspecified, git-send-email will search `--smtp-server` is also unspecified, `git send-email` will search
for `sendmail` in `/usr/sbin`, `/usr/lib` and $PATH. for `sendmail` in `/usr/sbin`, `/usr/lib` and `$PATH`.


--smtp-encryption=<encryption>:: --smtp-encryption=<encryption>::
Specify in what way encrypting begins for the SMTP connection. Specify in what way encrypting begins for the SMTP connection.
Valid values are 'ssl' and 'tls'. Any other value reverts to plain Valid values are `ssl` and `tls`. Any other value reverts to plain
(unencrypted) SMTP, which defaults to port 25. (unencrypted) SMTP, which defaults to port 25.
Despite the names, both values will use the same newer version of TLS, Despite the names, both values will use the same newer version of TLS,
but for historic reasons have these names. 'ssl' refers to "implicit" but for historic reasons have these names. `ssl` refers to "implicit"
encryption (sometimes called SMTPS), that uses port 465 by default. encryption (sometimes called SMTPS), that uses port 465 by default.
'tls' refers to "explicit" encryption (often known as STARTTLS), `tls` refers to "explicit" encryption (often known as STARTTLS),
that uses port 25 by default. Other ports might be used by the SMTP that uses port 25 by default. Other ports might be used by the SMTP
server, which are not the default. Commonly found alternative port for server, which are not the default. Commonly found alternative port for
'tls' and unencrypted is 587. You need to check your provider's `tls` and unencrypted is 587. You need to check your provider's
documentation or your server configuration to make sure documentation or your server configuration to make sure
for your own case. Default is the value of `sendemail.smtpEncryption`. for your own case. Default is the value of `sendemail.smtpEncryption`.


--smtp-domain=<FQDN>:: --smtp-domain=<FQDN>::
Specifies the Fully Qualified Domain Name (FQDN) used in the Specifies the Fully Qualified Domain Name (FQDN) used in the
HELO/EHLO command to the SMTP server. Some servers require the HELO/EHLO command to the SMTP server. Some servers require the
FQDN to match your IP address. If not set, git send-email attempts FQDN to match your IP address. If not set, `git send-email` attempts
to determine your FQDN automatically. Default is the value of to determine your FQDN automatically. Default is the value of
`sendemail.smtpDomain`. `sendemail.smtpDomain`.


@ -223,10 +223,10 @@ $ git send-email --smtp-auth="PLAIN LOGIN GSSAPI" ...
+ +
If at least one of the specified mechanisms matches the ones advertised by the If at least one of the specified mechanisms matches the ones advertised by the
SMTP server and if it is supported by the utilized SASL library, the mechanism SMTP server and if it is supported by the utilized SASL library, the mechanism
is used for authentication. If neither 'sendemail.smtpAuth' nor `--smtp-auth` is used for authentication. If neither `sendemail.smtpAuth` nor `--smtp-auth`
is specified, all mechanisms supported by the SASL library can be used. The is specified, all mechanisms supported by the SASL library can be used. The
special value 'none' maybe specified to completely disable authentication special value `none` maybe specified to completely disable authentication
independently of `--smtp-user` independently of `--smtp-user`.


--smtp-pass[=<password>]:: --smtp-pass[=<password>]::
Password for SMTP-AUTH. The argument is optional: If no Password for SMTP-AUTH. The argument is optional: If no
@ -238,16 +238,16 @@ Furthermore, passwords need not be specified in configuration files
or on the command line. If a username has been specified (with or on the command line. If a username has been specified (with
`--smtp-user` or a `sendemail.smtpUser`), but no password has been `--smtp-user` or a `sendemail.smtpUser`), but no password has been
specified (with `--smtp-pass` or `sendemail.smtpPass`), then specified (with `--smtp-pass` or `sendemail.smtpPass`), then
a password is obtained using 'git-credential'. a password is obtained using linkgit:git-credential[1].


--no-smtp-auth:: --no-smtp-auth::
Disable SMTP authentication. Short hand for `--smtp-auth=none` Disable SMTP authentication. Short hand for `--smtp-auth=none`.


--smtp-server=<host>:: --smtp-server=<host>::
If set, specifies the outgoing SMTP server to use (e.g. If set, specifies the outgoing SMTP server to use (e.g.
`smtp.example.com` or a raw IP address). If unspecified, and if `smtp.example.com` or a raw IP address). If unspecified, and if
`--sendmail-cmd` is also unspecified, the default is to search `--sendmail-cmd` is also unspecified, the default is to search
for `sendmail` in `/usr/sbin`, `/usr/lib` and $PATH if such a for `sendmail` in `/usr/sbin`, `/usr/lib` and `$PATH` if such a
program is available, falling back to `localhost` otherwise. program is available, falling back to `localhost` otherwise.
+ +
For backward compatibility, this option can also specify a full pathname For backward compatibility, this option can also specify a full pathname
@ -260,7 +260,7 @@ instead.
Specifies a port different from the default port (SMTP Specifies a port different from the default port (SMTP
servers typically listen to smtp port 25, but may also listen to servers typically listen to smtp port 25, but may also listen to
submission port 587, or the common SSL smtp port 465); submission port 587, or the common SSL smtp port 465);
symbolic port names (e.g. "submission" instead of 587) symbolic port names (e.g. `submission` instead of 587)
are also accepted. The port can also be set with the are also accepted. The port can also be set with the
`sendemail.smtpServerPort` configuration variable. `sendemail.smtpServerPort` configuration variable.


@ -269,23 +269,25 @@ instead.
Default value can be specified by the `sendemail.smtpServerOption` Default value can be specified by the `sendemail.smtpServerOption`
configuration option. configuration option.
+ +
The --smtp-server-option option must be repeated for each option you want The `--smtp-server-option` option must be repeated for each option you want
to pass to the server. Likewise, different lines in the configuration files to pass to the server. Likewise, different lines in the configuration files
must be used for each option. must be used for each option.


--smtp-ssl:: --smtp-ssl::
Legacy alias for '--smtp-encryption ssl'. Legacy alias for `--smtp-encryption ssl`.


--smtp-ssl-cert-path:: --smtp-ssl-cert-path::
Path to a store of trusted CA certificates for SMTP SSL/TLS Path to a store of trusted CA certificates for SMTP SSL/TLS
certificate validation (either a directory that has been processed certificate validation (either a directory that has been processed
by 'c_rehash', or a single file containing one or more PEM format by `c_rehash`, or a single file containing one or more PEM format
certificates concatenated together: see verify(1) -CAfile and certificates concatenated together: see the description of the
-CApath for more information on these). Set it to an empty string `-CAfile` _<file>_ and the `-CApath` _<dir>_ options of
to disable certificate verification. Defaults to the value of the https://docs.openssl.org/master/man1/openssl-verify/
`sendemail.smtpSSLCertPath` configuration variable, if set, or the [OpenSSL's verify(1) manual page] for more information on these).
backing SSL library's compiled-in default otherwise (which should Set it to an empty string to disable certificate verification.
be the best choice on most platforms). Defaults to the value of the `sendemail.smtpSSLCertPath` configuration
variable, if set, or the backing SSL library's compiled-in default
otherwise (which should be the best choice on most platforms).


--smtp-user=<user>:: --smtp-user=<user>::
Username for SMTP-AUTH. Default is the value of `sendemail.smtpUser`; Username for SMTP-AUTH. Default is the value of `sendemail.smtpUser`;
@ -298,18 +300,18 @@ must be used for each option.
connection and authentication problems. connection and authentication problems.


--batch-size=<num>:: --batch-size=<num>::
Some email servers (e.g. smtp.163.com) limit the number emails to be Some email servers (e.g. 'smtp.163.com') limit the number of emails to be
sent per session (connection) and this will lead to a failure when sent per session (connection) and this will lead to a failure when
sending many messages. With this option, send-email will disconnect after sending many messages. With this option, send-email will disconnect after
sending $<num> messages and wait for a few seconds (see --relogin-delay) sending _<num>_ messages and wait for a few seconds
and reconnect, to work around such a limit. You may want to (see `--relogin-delay`) and reconnect, to work around such a limit.
use some form of credential helper to avoid having to retype You may want to use some form of credential helper to avoid having to
your password every time this happens. Defaults to the retype your password every time this happens. Defaults to the
`sendemail.smtpBatchSize` configuration variable. `sendemail.smtpBatchSize` configuration variable.


--relogin-delay=<int>:: --relogin-delay=<int>::
Waiting $<int> seconds before reconnecting to SMTP server. Used together Waiting _<int>_ seconds before reconnecting to SMTP server. Used together
with --batch-size option. Defaults to the `sendemail.smtpReloginDelay` with `--batch-size` option. Defaults to the `sendemail.smtpReloginDelay`
configuration variable. configuration variable.


Automating Automating
@ -318,7 +320,7 @@ Automating
--no-to:: --no-to::
--no-cc:: --no-cc::
--no-bcc:: --no-bcc::
Clears any list of "To:", "Cc:", "Bcc:" addresses previously Clears any list of `To:`, `Cc:`, `Bcc:` addresses previously
set via config. set via config.


--no-identity:: --no-identity::
@ -327,13 +329,13 @@ Automating


--to-cmd=<command>:: --to-cmd=<command>::
Specify a command to execute once per patch file which Specify a command to execute once per patch file which
should generate patch file specific "To:" entries. should generate patch file specific `To:` entries.
Output of this command must be single email address per line. Output of this command must be single email address per line.
Default is the value of 'sendemail.toCmd' configuration value. Default is the value of `sendemail.toCmd` configuration value.


--cc-cmd=<command>:: --cc-cmd=<command>::
Specify a command to execute once per patch file which Specify a command to execute once per patch file which
should generate patch file specific "Cc:" entries. should generate patch file specific `Cc:` entries.
Output of this command must be single email address per line. Output of this command must be single email address per line.
Default is the value of `sendemail.ccCmd` configuration value. Default is the value of `sendemail.ccCmd` configuration value.


@ -341,7 +343,7 @@ Automating
Specify a command that is executed once per outgoing message Specify a command that is executed once per outgoing message
and output RFC 2822 style header lines to be inserted into and output RFC 2822 style header lines to be inserted into
them. When the `sendemail.headerCmd` configuration variable is them. When the `sendemail.headerCmd` configuration variable is
set, its value is always used. When --header-cmd is provided set, its value is always used. When `--header-cmd` is provided
at the command line, its value takes precedence over the at the command line, its value takes precedence over the
`sendemail.headerCmd` configuration variable. `sendemail.headerCmd` configuration variable.


@ -350,7 +352,7 @@ Automating


--[no-]chain-reply-to:: --[no-]chain-reply-to::
If this is set, each email will be sent as a reply to the previous If this is set, each email will be sent as a reply to the previous
email sent. If disabled with "--no-chain-reply-to", all emails after email sent. If disabled with `--no-chain-reply-to`, all emails after
the first will be sent as replies to the first email sent. When using the first will be sent as replies to the first email sent. When using
this, it is recommended that the first file given be an overview of the this, it is recommended that the first file given be an overview of the
entire patch series. Disabled by default, but the `sendemail.chainReplyTo` entire patch series. Disabled by default, but the `sendemail.chainReplyTo`
@ -358,79 +360,80 @@ Automating


--identity=<identity>:: --identity=<identity>::
A configuration identity. When given, causes values in the A configuration identity. When given, causes values in the
'sendemail.<identity>' subsection to take precedence over `sendemail.<identity>` subsection to take precedence over
values in the 'sendemail' section. The default identity is values in the `sendemail` section. The default identity is
the value of `sendemail.identity`. the value of `sendemail.identity`.


--[no-]signed-off-by-cc:: --[no-]signed-off-by-cc::
If this is set, add emails found in the `Signed-off-by` trailer or Cc: lines to the If this is set, add emails found in the `Signed-off-by` trailer or `Cc:`
cc list. Default is the value of `sendemail.signedOffByCc` configuration lines to the cc list. Default is the value of `sendemail.signedOffByCc`
value; if that is unspecified, default to --signed-off-by-cc. configuration value; if that is unspecified, default to
`--signed-off-by-cc`.


--[no-]cc-cover:: --[no-]cc-cover::
If this is set, emails found in Cc: headers in the first patch of If this is set, emails found in `Cc:` headers in the first patch of
the series (typically the cover letter) are added to the cc list the series (typically the cover letter) are added to the cc list
for each email set. Default is the value of 'sendemail.ccCover' for each email set. Default is the value of `sendemail.ccCover`
configuration value; if that is unspecified, default to --no-cc-cover. configuration value; if that is unspecified, default to `--no-cc-cover`.


--[no-]to-cover:: --[no-]to-cover::
If this is set, emails found in To: headers in the first patch of If this is set, emails found in `To:` headers in the first patch of
the series (typically the cover letter) are added to the to list the series (typically the cover letter) are added to the to list
for each email set. Default is the value of 'sendemail.toCover' for each email set. Default is the value of `sendemail.toCover`
configuration value; if that is unspecified, default to --no-to-cover. configuration value; if that is unspecified, default to `--no-to-cover`.


--suppress-cc=<category>:: --suppress-cc=<category>::
Specify an additional category of recipients to suppress the Specify an additional category of recipients to suppress the
auto-cc of: auto-cc of:
+ +
-- --
- 'author' will avoid including the patch author. - `author` will avoid including the patch author.
- 'self' will avoid including the sender. - `self` will avoid including the sender.
- 'cc' will avoid including anyone mentioned in Cc lines in the patch header - `cc` will avoid including anyone mentioned in Cc lines in the patch header
except for self (use 'self' for that). except for self (use `self` for that).
- 'bodycc' will avoid including anyone mentioned in Cc lines in the - `bodycc` will avoid including anyone mentioned in Cc lines in the
patch body (commit message) except for self (use 'self' for that). patch body (commit message) except for self (use `self` for that).
- 'sob' will avoid including anyone mentioned in the Signed-off-by trailers except - `sob` will avoid including anyone mentioned in the Signed-off-by trailers except
for self (use 'self' for that). for self (use `self` for that).
- 'misc-by' will avoid including anyone mentioned in Acked-by, - `misc-by` will avoid including anyone mentioned in Acked-by,
Reviewed-by, Tested-by and other "-by" lines in the patch body, Reviewed-by, Tested-by and other "-by" lines in the patch body,
except Signed-off-by (use 'sob' for that). except Signed-off-by (use `sob` for that).
- 'cccmd' will avoid running the --cc-cmd. - `cccmd` will avoid running the --cc-cmd.
- 'body' is equivalent to 'sob' + 'bodycc' + 'misc-by'. - `body` is equivalent to `sob` + `bodycc` + `misc-by`.
- 'all' will suppress all auto cc values. - `all` will suppress all auto cc values.
-- --
+ +
Default is the value of `sendemail.suppressCc` configuration value; if Default is the value of `sendemail.suppressCc` configuration value; if
that is unspecified, default to 'self' if --suppress-from is that is unspecified, default to `self` if `--suppress-from` is
specified, as well as 'body' if --no-signed-off-cc is specified. specified, as well as `body` if `--no-signed-off-cc` is specified.


--[no-]suppress-from:: --[no-]suppress-from::
If this is set, do not add the From: address to the cc: list. If this is set, do not add the `From:` address to the `Cc:` list.
Default is the value of `sendemail.suppressFrom` configuration Default is the value of `sendemail.suppressFrom` configuration
value; if that is unspecified, default to --no-suppress-from. value; if that is unspecified, default to `--no-suppress-from`.


--[no-]thread:: --[no-]thread::
If this is set, the In-Reply-To and References headers will be If this is set, the `In-Reply-To` and `References` headers will be
added to each email sent. Whether each mail refers to the added to each email sent. Whether each mail refers to the
previous email (`deep` threading per 'git format-patch' previous email (`deep` threading per `git format-patch`
wording) or to the first email (`shallow` threading) is wording) or to the first email (`shallow` threading) is
governed by "--[no-]chain-reply-to". governed by `--[no-]chain-reply-to`.
+ +
If disabled with "--no-thread", those headers will not be added If disabled with `--no-thread`, those headers will not be added
(unless specified with --in-reply-to). Default is the value of the (unless specified with `--in-reply-to`). Default is the value of the
`sendemail.thread` configuration value; if that is unspecified, `sendemail.thread` configuration value; if that is unspecified,
default to --thread. default to `--thread`.
+ +
It is up to the user to ensure that no In-Reply-To header already It is up to the user to ensure that no In-Reply-To header already
exists when 'git send-email' is asked to add it (especially note that exists when `git send-email` is asked to add it (especially note that
'git format-patch' can be configured to do the threading itself). `git format-patch` can be configured to do the threading itself).
Failure to do so may not produce the expected result in the Failure to do so may not produce the expected result in the
recipient's MUA. recipient's MUA.


--[no-]mailmap:: --[no-]mailmap::
Use the mailmap file (see linkgit:gitmailmap[5]) to map all Use the mailmap file (see linkgit:gitmailmap[5]) to map all
addresses to their canonical real name and email address. Additional addresses to their canonical real name and email address. Additional
mailmap data specific to git-send-email may be provided using the mailmap data specific to `git send-email` may be provided using the
`sendemail.mailmap.file` or `sendemail.mailmap.blob` configuration `sendemail.mailmap.file` or `sendemail.mailmap.blob` configuration
values. Defaults to `sendemail.mailmap`. values. Defaults to `sendemail.mailmap`.


@ -441,17 +444,17 @@ Administering
Confirm just before sending: Confirm just before sending:
+ +
-- --
- 'always' will always confirm before sending - `always` will always confirm before sending.
- 'never' will never confirm before sending - `never` will never confirm before sending.
- 'cc' will confirm before sending when send-email has automatically - `cc` will confirm before sending when send-email has automatically
added addresses from the patch to the Cc list added addresses from the patch to the Cc list.
- 'compose' will confirm before sending the first message when using --compose. - `compose` will confirm before sending the first message when using --compose.
- 'auto' is equivalent to 'cc' + 'compose' - `auto` is equivalent to `cc` + `compose`.
-- --
+ +
Default is the value of `sendemail.confirm` configuration value; if that Default is the value of `sendemail.confirm` configuration value; if that
is unspecified, default to 'auto' unless any of the suppress options is unspecified, default to `auto` unless any of the suppress options
have been specified, in which case default to 'compose'. have been specified, in which case default to `compose`.


--dry-run:: --dry-run::
Do everything except actually send the emails. Do everything except actually send the emails.
@ -460,10 +463,10 @@ have been specified, in which case default to 'compose'.
When an argument may be understood either as a reference or as a file name, When an argument may be understood either as a reference or as a file name,
choose to understand it as a format-patch argument (`--format-patch`) choose to understand it as a format-patch argument (`--format-patch`)
or as a file name (`--no-format-patch`). By default, when such a conflict or as a file name (`--no-format-patch`). By default, when such a conflict
occurs, git send-email will fail. occurs, `git send-email` will fail.


--quiet:: --quiet::
Make git-send-email less verbose. One line per email should be Make `git send-email` less verbose. One line per email should be
all that is output. all that is output.


--[no-]validate:: --[no-]validate::
@ -474,7 +477,7 @@ have been specified, in which case default to 'compose'.
* Invoke the sendemail-validate hook if present (see linkgit:githooks[5]). * Invoke the sendemail-validate hook if present (see linkgit:githooks[5]).
* Warn of patches that contain lines longer than * Warn of patches that contain lines longer than
998 characters unless a suitable transfer encoding 998 characters unless a suitable transfer encoding
('auto', 'base64', or 'quoted-printable') is used; (`auto`, `base64`, or `quoted-printable`) is used;
this is due to SMTP limits as described by this is due to SMTP limits as described by
https://www.ietf.org/rfc/rfc5322.txt. https://www.ietf.org/rfc/rfc5322.txt.
-- --
@ -493,13 +496,13 @@ Information
Instead of the normal operation, dump the shorthand alias names from Instead of the normal operation, dump the shorthand alias names from
the configured alias file(s), one per line in alphabetical order. Note the configured alias file(s), one per line in alphabetical order. Note
that this only includes the alias name and not its expanded email addresses. that this only includes the alias name and not its expanded email addresses.
See 'sendemail.aliasesFile' for more information about aliases. See `sendemail.aliasesFile` for more information about aliases.


--translate-aliases:: --translate-aliases::
Instead of the normal operation, read from standard input and Instead of the normal operation, read from standard input and
interpret each line as an email alias. Translate it according to the interpret each line as an email alias. Translate it according to the
configured alias file(s). Output each translated name and email configured alias file(s). Output each translated name and email
address to standard output, one per line. See 'sendemail.aliasFile' address to standard output, one per line. See `sendemail.aliasFile`
for more information about aliases. for more information about aliases.


CONFIGURATION CONFIGURATION
@ -524,15 +527,18 @@ edit `~/.gitconfig` to specify your account settings:
smtpServerPort = 587 smtpServerPort = 587
---- ----


Gmail does not allow using your regular password for `git send-email`.
If you have multi-factor authentication set up on your Gmail account, you can If you have multi-factor authentication set up on your Gmail account, you can
generate an app-specific password for use with 'git send-email'. Visit generate an app-specific password for use with `git send-email`. Visit
https://security.google.com/settings/security/apppasswords to create it. https://security.google.com/settings/security/apppasswords to create it.


You can also use OAuth2.0 authentication with Gmail. `OAUTHBEARER` and Alternatively, instead of using an app-specific password, you can use
`XOAUTH2` are common methods used for this type of authentication. Gmail OAuth2.0 authentication with Gmail. OAuth2.0 is more secure than
supports both of them. As an example, if you want to use `OAUTHBEARER`, edit app-specific passwords, and works regardless of whether you have multi-factor
your `~/.gitconfig` file and add `smtpAuth = OAUTHBEARER` to your account authentication set up. `OAUTHBEARER` and `XOAUTH2` are common mechanisms used
settings: for this type of authentication. Gmail supports both of them. As an example,
if you want to use `OAUTHBEARER`, edit your `~/.gitconfig` file and add
`smtpAuth = OAUTHBEARER` to your account settings:


---- ----
[sendemail] [sendemail]
@ -543,11 +549,15 @@ settings:
smtpAuth = OAUTHBEARER smtpAuth = OAUTHBEARER
---- ----


Another alternative is using a tool developed by Google known as
https://github.com/google/gmail-oauth2-tools/tree/master/go/sendgmail[sendgmail]
to send emails using `git send-email`.

Use Microsoft Outlook as the SMTP Server Use Microsoft Outlook as the SMTP Server
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unlike Gmail, Microsoft Outlook no longer supports app-specific passwords. Unlike Gmail, Microsoft Outlook no longer supports app-specific passwords.
Therefore, OAuth2.0 authentication must be used for Outlook. Also, it only Therefore, OAuth2.0 authentication must be used for Outlook. Also, it only
supports `XOAUTH2` authentication method. supports `XOAUTH2` authentication mechanism.


Edit `~/.gitconfig` to specify your account settings for Outlook and use its Edit `~/.gitconfig` to specify your account settings for Outlook and use its
SMTP server with `git send-email`: SMTP server with `git send-email`:
@ -579,8 +589,7 @@ next time.


If you are using OAuth2.0 authentication, you need to use an access token in If you are using OAuth2.0 authentication, you need to use an access token in
place of a password when prompted. Various OAuth2.0 token generators are place of a password when prompted. Various OAuth2.0 token generators are
available online. Community maintained credential helpers for Gmail and Outlook available online. Community maintained credential helpers are also available:
are also available:


- https://github.com/AdityaGarg8/git-credential-email[git-credential-gmail] - https://github.com/AdityaGarg8/git-credential-email[git-credential-gmail]
(cross platform, dedicated helper for authenticating Gmail accounts) (cross platform, dedicated helper for authenticating Gmail accounts)
@ -588,15 +597,65 @@ are also available:
- https://github.com/AdityaGarg8/git-credential-email[git-credential-outlook] - https://github.com/AdityaGarg8/git-credential-email[git-credential-outlook]
(cross platform, dedicated helper for authenticating Microsoft Outlook accounts) (cross platform, dedicated helper for authenticating Microsoft Outlook accounts)


- https://github.com/AdityaGarg8/git-credential-email[git-credential-yahoo]
(cross platform, dedicated helper for authenticating Yahoo accounts)

- https://github.com/AdityaGarg8/git-credential-email[git-credential-aol]
(cross platform, dedicated helper for authenticating AOL accounts)

You can also see linkgit:gitcredentials[7] for more OAuth based authentication You can also see linkgit:gitcredentials[7] for more OAuth based authentication
helpers. helpers.


Proton Mail does not provide an SMTP server to send emails. If you are a paid
customer of Proton Mail, you can use
https://proton.me/mail/bridge[Proton Mail Bridge]
officially provided by Proton Mail to create a local SMTP server for sending
emails. For both free and paid users, community maintained projects like
https://github.com/AdityaGarg8/git-credential-email[git-protonmail] can be
used.

Note: the following core Perl modules that may be installed with your Note: the following core Perl modules that may be installed with your
distribution of Perl are required: distribution of Perl are required:
MIME::Base64, MIME::QuotedPrint, Net::Domain and Net::SMTP.
These additional Perl modules are also required:
Authen::SASL and Mail::Address.


https://metacpan.org/pod/MIME::Base64[MIME::Base64],
https://metacpan.org/pod/MIME::QuotedPrint[MIME::QuotedPrint],
https://metacpan.org/pod/Net::Domain[Net::Domain] and
https://metacpan.org/pod/Net::SMTP[Net::SMTP].

These additional Perl modules are also required:

https://metacpan.org/pod/Authen::SASL[Authen::SASL] and
https://metacpan.org/pod/Mail::Address[Mail::Address].

Exploiting the `sendmailCmd` option of `git send-email`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Apart from sending emails via an SMTP server, `git send-email` can also send
emails through any application that supports sendmail-like commands. You can
read documentation of `--sendmail-cmd=<command>` above for more information.
This ability can be very useful if you want to use another application as an
SMTP client for `git send-email`, or if your email provider uses proprietary
APIs instead of SMTP to send emails.

As an example, lets see how to configure https://marlam.de/msmtp/[msmtp], a
popular SMTP client found in many Linux distributions. Edit `~/.gitconfig`
to instruct `git-send-email` to use it for sending emails.

----
[sendemail]
sendmailCmd = /usr/bin/msmtp # Change this to the path where msmtp is installed
----

Links of a few such community maintained helpers are:

- https://marlam.de/msmtp/[msmtp]
(popular SMTP client with many features, available for Linux and macOS)

- https://github.com/AdityaGarg8/git-credential-email[git-protonmail]
(cross platform client that can send emails using the ProtonMail API)

- https://github.com/AdityaGarg8/git-credential-email[git-msgraph]
(cross platform client that can send emails using the Microsoft Graph API)


SEE ALSO SEE ALSO
-------- --------

View File

@ -23,6 +23,8 @@ SYNOPSIS
'git stash' clear 'git stash' clear
'git stash' create [<message>] 'git stash' create [<message>]
'git stash' store [(-m | --message) <message>] [-q | --quiet] <commit> 'git stash' store [(-m | --message) <message>] [-q | --quiet] <commit>
'git stash' export (--print | --to-ref <ref>) [<stash>...]
'git stash' import <commit>


DESCRIPTION DESCRIPTION
----------- -----------
@ -154,6 +156,18 @@ store::
reflog. This is intended to be useful for scripts. It is reflog. This is intended to be useful for scripts. It is
probably not the command you want to use; see "push" above. probably not the command you want to use; see "push" above.


export ( --print | --to-ref <ref> ) [<stash>...]::

Export the specified stashes, or all of them if none are specified, to
a chain of commits which can be transferred using the normal fetch and
push mechanisms, then imported using the `import` subcommand.

import <commit>::

Import the specified stashes from the specified commit, which must have been
created by `export`, and add them to the list of stashes. To replace the
existing stashes, use `clear` first.

OPTIONS OPTIONS
------- -------
-a:: -a::
@ -242,6 +256,19 @@ literally (including newlines and quotes).
+ +
Quiet, suppress feedback messages. Quiet, suppress feedback messages.


--print::
This option is only valid for the `export` command.
+
Create the chain of commits representing the exported stashes without
storing it anywhere in the ref namespace and print the object ID to
standard output. This is designed for scripts.

--to-ref::
This option is only valid for the `export` command.
+
Create the chain of commits representing the exported stashes and store
it to the specified ref.

\--:: \--::
This option is only valid for `push` command. This option is only valid for `push` command.
+ +
@ -259,7 +286,7 @@ For more details, see the 'pathspec' entry in linkgit:gitglossary[7].


<stash>:: <stash>::
This option is only valid for `apply`, `branch`, `drop`, `pop`, This option is only valid for `apply`, `branch`, `drop`, `pop`,
`show` commands. `show`, and `export` commands.
+ +
A reference of the form `stash@{<revision>}`. When no `<stash>` is A reference of the form `stash@{<revision>}`. When no `<stash>` is
given, the latest stash is assumed (that is, `stash@{0}`). given, the latest stash is assumed (that is, `stash@{0}`).

View File

@ -8,8 +8,14 @@ git-whatchanged - Show logs with differences each commit introduces


SYNOPSIS SYNOPSIS
-------- --------
[verse] [synopsis]
'git whatchanged' <option>... git whatchanged <option>...

WARNING
-------
`git whatchanged` has been deprecated and is scheduled for removal in
a future version of Git, as it is merely `git log` with different
default; `whatchanged` is not even shorter to type than `log --raw`.


DESCRIPTION DESCRIPTION
----------- -----------

View File

@ -133,10 +133,6 @@ Popular helpers with OAuth support include:


- https://github.com/hickford/git-credential-oauth[git-credential-oauth] (cross platform, included in many Linux distributions) - https://github.com/hickford/git-credential-oauth[git-credential-oauth] (cross platform, included in many Linux distributions)


- https://github.com/AdityaGarg8/git-credential-email[git-credential-gmail] (cross platform, dedicated helper to authenticate Gmail accounts for linkgit:git-send-email[1])

- https://github.com/AdityaGarg8/git-credential-email[git-credential-outlook] (cross platform, dedicated helper to authenticate Microsoft Outlook accounts for linkgit:git-send-email[1])

CREDENTIAL CONTEXTS CREDENTIAL CONTEXTS
------------------- -------------------



View File

@ -54,7 +54,7 @@ In general a client can request to speak protocol v2 by sending
`version=2` through the respective side-channel for the transport being `version=2` through the respective side-channel for the transport being
used which inevitably sets `GIT_PROTOCOL`. More information can be used which inevitably sets `GIT_PROTOCOL`. More information can be
found in linkgit:gitprotocol-pack[5] and linkgit:gitprotocol-http[5], as well as the found in linkgit:gitprotocol-pack[5] and linkgit:gitprotocol-http[5], as well as the
`GIT_PROTOCOL` definition in `git.txt`. In all cases the `GIT_PROTOCOL` definition in linkgit:git[1]. In all cases the
response from the server is the capability advertisement. response from the server is the capability advertisement.


Git Transport Git Transport
@ -99,7 +99,7 @@ Uses the `--http-backend-info-refs` option to
linkgit:git-upload-pack[1]. linkgit:git-upload-pack[1].


The server may need to be configured to pass this header's contents via The server may need to be configured to pass this header's contents via
the `GIT_PROTOCOL` variable. See the discussion in `git-http-backend.txt`. the `GIT_PROTOCOL` variable. See the discussion in linkgit:git-http-backend[1].


Capability Advertisement Capability Advertisement
------------------------ ------------------------

View File

@ -498,7 +498,7 @@ set by Git if the remote helper has the 'option' capability.
ask for the tag specifically. Some helpers may be able to ask for the tag specifically. Some helpers may be able to
use this option to avoid a second network connection. use this option to avoid a second network connection.


'option dry-run' {'true'|'false'}: 'option dry-run' {'true'|'false'}::
If true, pretend the operation completed successfully, If true, pretend the operation completed successfully,
but don't actually change any repository data. For most but don't actually change any repository data. For most
helpers this only applies to the 'push', if supported. helpers this only applies to the 'push', if supported.

View File

@ -418,9 +418,8 @@ full pathname may have special meaning:


- A leading "`**`" followed by a slash means match in all - A leading "`**`" followed by a slash means match in all
directories. For example, "`**/foo`" matches file or directory directories. For example, "`**/foo`" matches file or directory
"`foo`" anywhere, the same as pattern "`foo`". "`**/foo/bar`" "`foo`" anywhere. "`**/foo/bar`" matches file or directory "`bar`"
matches file or directory "`bar`" anywhere that is directly anywhere that is directly under directory "`foo`".
under directory "`foo`".


- A trailing "`/**`" matches everything inside. For example, - A trailing "`/**`" matches everything inside. For example,
"`abc/**`" matches all files inside directory "abc", relative "`abc/**`" matches all files inside directory "abc", relative

View File

@ -1,30 +1,30 @@
'<start>' and '<end>' can take one of these forms: _<start>_ and _<end>_ can take one of these forms:


- number - _<number>_
+ +
If '<start>' or '<end>' is a number, it specifies an If _<start>_ or _<end>_ is a number, it specifies an
absolute line number (lines count from 1). absolute line number (lines count from 1).
+ +


- `/regex/` - `/<regex>/`
+ +
This form will use the first line matching the given This form will use the first line matching the given
POSIX regex. If '<start>' is a regex, it will search from the end of POSIX _<regex>_. If _<start>_ is a regex, it will search from the end of
the previous `-L` range, if any, otherwise from the start of file. the previous `-L` range, if any, otherwise from the start of file.
If '<start>' is `^/regex/`, it will search from the start of file. If _<start>_ is `^/<regex>/`, it will search from the start of file.
If '<end>' is a regex, it will search If _<end>_ is a regex, it will search starting at the line given by
starting at the line given by '<start>'. _<start>_.
+ +


- +offset or -offset - `+<offset>` or `-<offset>`
+ +
This is only valid for '<end>' and will specify a number This is only valid for _<end>_ and will specify a number
of lines before or after the line given by '<start>'. of lines before or after the line given by _<start>_.


+ +
If `:<funcname>` is given in place of '<start>' and '<end>', it is a If `:<funcname>` is given in place of _<start>_ and _<end>_, it is a
regular expression that denotes the range from the first funcname line regular expression that denotes the range from the first funcname line
that matches '<funcname>', up to the next funcname line. `:<funcname>` that matches _<funcname>_, up to the next funcname line. `:<funcname>`
searches from the end of the previous `-L` range, if any, otherwise searches from the end of the previous `-L` range, if any, otherwise
from the start of file. `^:<funcname>` searches from the start of from the start of file. `^:<funcname>` searches from the start of
file. The function names are determined in the same way as `git diff` file. The function names are determined in the same way as `git diff`

View File

@ -1,12 +1,12 @@
-L<start>,<end>:<file>:: `-L<start>,<end>:<file>`::
-L:<funcname>:<file>:: `-L:<funcname>:<file>`::


Trace the evolution of the line range given by '<start>,<end>', Trace the evolution of the line range given by `<start>,<end>`,
or by the function name regex '<funcname>', within the '<file>'. You may or by the function name regex _<funcname>_, within the _<file>_. You may
not give any pathspec limiters. This is currently limited to not give any pathspec limiters. This is currently limited to
a walk starting from a single revision, i.e., you may only a walk starting from a single revision, i.e., you may only
give zero or one positive revision arguments, and give zero or one positive revision arguments, and
'<start>' and '<end>' (or '<funcname>') must exist in the starting revision. _<start>_ and _<end>_ (or _<funcname>_) must exist in the starting revision.
You can specify this option more than once. Implies `--patch`. You can specify this option more than once. Implies `--patch`.
Patch output can be suppressed using `--no-patch`, but other diff formats Patch output can be suppressed using `--no-patch`, but other diff formats
(namely `--raw`, `--numstat`, `--shortstat`, `--dirstat`, `--summary`, (namely `--raw`, `--numstat`, `--shortstat`, `--dirstat`, `--summary`,

View File

@ -113,6 +113,9 @@ include::signoff-option.adoc[]
With `-n` or `--no-stat` do not show a diffstat at the end of the With `-n` or `--no-stat` do not show a diffstat at the end of the
merge. merge.


`--compact-summary`::
Show a compact-summary at the end of the merge.

`--squash`:: `--squash`::
`--no-squash`:: `--no-squash`::
Produce the working tree and index state as if a real merge Produce the working tree and index state as if a real merge

View File

@ -158,7 +158,6 @@ manpages = {
'git-verify-tag.adoc' : 1, 'git-verify-tag.adoc' : 1,
'git-version.adoc' : 1, 'git-version.adoc' : 1,
'git-web--browse.adoc' : 1, 'git-web--browse.adoc' : 1,
'git-whatchanged.adoc' : 1,
'git-worktree.adoc' : 1, 'git-worktree.adoc' : 1,
'git-write-tree.adoc' : 1, 'git-write-tree.adoc' : 1,
'git.adoc' : 1, 'git.adoc' : 1,
@ -207,6 +206,7 @@ manpages = {


manpages_breaking_changes = { manpages_breaking_changes = {
'git-pack-redundant.adoc' : 1, 'git-pack-redundant.adoc' : 1,
'git-whatchanged.adoc' : 1,
} }


if not get_option('breaking_changes') if not get_option('breaking_changes')
@ -375,8 +375,7 @@ foreach manpage, category : manpages
output: fs.stem(manpage) + '.xml', output: fs.stem(manpage) + '.xml',
) )


manpage_path = fs.stem(manpage) + '.' + category.to_string() custom_target(
manpage_target = custom_target(
command: [ command: [
xmlto, xmlto,
'-m', '@INPUT0@', '-m', '@INPUT0@',
@ -392,7 +391,7 @@ foreach manpage, category : manpages
'manpage-normal.xsl', 'manpage-normal.xsl',
'manpage-bold-literal.xsl', 'manpage-bold-literal.xsl',
], ],
output: manpage_path, output: fs.stem(manpage) + '.' + category.to_string(),
install: true, install: true,
install_dir: get_option('mandir') / 'man' + category.to_string(), install_dir: get_option('mandir') / 'man' + category.to_string(),
) )

View File

@ -2,11 +2,11 @@ PRETTY FORMATS
-------------- --------------


If the commit is a merge, and if the pretty-format If the commit is a merge, and if the pretty-format
is not 'oneline', 'email' or 'raw', an additional line is is not `oneline`, `email` or `raw`, an additional line is
inserted before the 'Author:' line. This line begins with inserted before the `Author:` line. This line begins with
"Merge: " and the hashes of ancestral commits are printed, "Merge: " and the hashes of ancestral commits are printed,
separated by spaces. Note that the listed commits may not separated by spaces. Note that the listed commits may not
necessarily be the list of the *direct* parent commits if you necessarily be the list of the 'direct' parent commits if you
have limited your view of history: for example, if you are have limited your view of history: for example, if you are
only interested in changes related to a certain directory or only interested in changes related to a certain directory or
file. file.
@ -14,24 +14,24 @@ file.
There are several built-in formats, and you can define There are several built-in formats, and you can define
additional formats by setting a pretty.<name> additional formats by setting a pretty.<name>
config option to either another format name, or a config option to either another format name, or a
'format:' string, as described below (see `format:` string, as described below (see
linkgit:git-config[1]). Here are the details of the linkgit:git-config[1]). Here are the details of the
built-in formats: built-in formats:


* 'oneline' * `oneline`


<hash> <title-line> <hash> <title-line>
+ +
This is designed to be as compact as possible. This is designed to be as compact as possible.


* 'short' * `short`


commit <hash> commit <hash>
Author: <author> Author: <author>


<title-line> <title-line>


* 'medium' * `medium`


commit <hash> commit <hash>
Author: <author> Author: <author>
@ -41,7 +41,7 @@ This is designed to be as compact as possible.


<full-commit-message> <full-commit-message>


* 'full' * `full`


commit <hash> commit <hash>
Author: <author> Author: <author>
@ -51,7 +51,7 @@ This is designed to be as compact as possible.


<full-commit-message> <full-commit-message>


* 'fuller' * `fuller`


commit <hash> commit <hash>
Author: <author> Author: <author>
@ -63,18 +63,18 @@ This is designed to be as compact as possible.


<full-commit-message> <full-commit-message>


* 'reference' * `reference`


<abbrev-hash> (<title-line>, <short-author-date>) <abbrev-hash> (<title-line>, <short-author-date>)
+ +
This format is used to refer to another commit in a commit message and This format is used to refer to another commit in a commit message and
is the same as `--pretty='format:%C(auto)%h (%s, %ad)'`. By default, is the same as ++--pretty=\'format:%C(auto)%h (%s, %ad)'++. By default,
the date is formatted with `--date=short` unless another `--date` option the date is formatted with `--date=short` unless another `--date` option
is explicitly specified. As with any `format:` with format is explicitly specified. As with any `format:` with format
placeholders, its output is not affected by other options like placeholders, its output is not affected by other options like
`--decorate` and `--walk-reflogs`. `--decorate` and `--walk-reflogs`.


* 'email' * `email`


From <hash> <date> From <hash> <date>
From: <author> From: <author>
@ -83,30 +83,30 @@ placeholders, its output is not affected by other options like


<full-commit-message> <full-commit-message>


* 'mboxrd' * `mboxrd`
+ +
Like 'email', but lines in the commit message starting with "From " Like `email`, but lines in the commit message starting with "From "
(preceded by zero or more ">") are quoted with ">" so they aren't (preceded by zero or more ">") are quoted with ">" so they aren't
confused as starting a new commit. confused as starting a new commit.


* 'raw' * `raw`
+ +
The 'raw' format shows the entire commit exactly as The `raw` format shows the entire commit exactly as
stored in the commit object. Notably, the hashes are stored in the commit object. Notably, the hashes are
displayed in full, regardless of whether --abbrev or displayed in full, regardless of whether `--abbrev` or
--no-abbrev are used, and 'parents' information show the `--no-abbrev` are used, and 'parents' information show the
true parent commits, without taking grafts or history true parent commits, without taking grafts or history
simplification into account. Note that this format affects the way simplification into account. Note that this format affects the way
commits are displayed, but not the way the diff is shown e.g. with commits are displayed, but not the way the diff is shown e.g. with
`git log --raw`. To get full object names in a raw diff format, `git log --raw`. To get full object names in a raw diff format,
use `--no-abbrev`. use `--no-abbrev`.


* 'format:<format-string>' * `format:<format-string>`
+ +
The 'format:<format-string>' format allows you to specify which information The `format:<format-string>` format allows you to specify which information
you want to show. It works a little bit like printf format, you want to show. It works a little bit like printf format,
with the notable exception that you get a newline with '%n' with the notable exception that you get a newline with `%n`
instead of '\n'. instead of `\n`.
+ +
E.g, 'format:"The author of %h was %an, %ar%nThe title was >>%s<<%n"' E.g, 'format:"The author of %h was %an, %ar%nThe title was >>%s<<%n"'
would show something like this: would show something like this:
@ -120,158 +120,161 @@ The title was >>t4119: test autocomputing -p<n> for traditional diff input.<<
The placeholders are: The placeholders are:


- Placeholders that expand to a single literal character: - Placeholders that expand to a single literal character:
'%n':: newline ++%n++:: newline
'%%':: a raw '%' ++%%++:: a raw ++%++
'%x00':: '%x' followed by two hexadecimal digits is replaced with a ++%x00++:: ++%x++ followed by two hexadecimal digits is replaced with a
byte with the hexadecimal digits' value (we will call this byte with the hexadecimal digits' value (we will call this
"literal formatting code" in the rest of this document). "literal formatting code" in the rest of this document).


- Placeholders that affect formatting of later placeholders: - Placeholders that affect formatting of later placeholders:
'%Cred':: switch color to red ++%Cred++:: switch color to red
'%Cgreen':: switch color to green ++%Cgreen++:: switch color to green
'%Cblue':: switch color to blue ++%Cblue++:: switch color to blue
'%Creset':: reset color ++%Creset++:: reset color
'%C(...)':: color specification, as described under Values in the ++%C(++_<spec>_++)++:: color specification, as described under Values in the
"CONFIGURATION FILE" section of linkgit:git-config[1]. By "CONFIGURATION FILE" section of linkgit:git-config[1]. By
default, colors are shown only when enabled for log output default, colors are shown only when enabled for log output
(by `color.diff`, `color.ui`, or `--color`, and respecting (by `color.diff`, `color.ui`, or `--color`, and respecting
the `auto` settings of the former if we are going to a the `auto` settings of the former if we are going to a
terminal). `%C(auto,...)` is accepted as a historical terminal). ++%C(auto,++_<spec>_++)++ is accepted as a historical
synonym for the default (e.g., `%C(auto,red)`). Specifying synonym for the default (e.g., ++%C(auto,red)++). Specifying
`%C(always,...)` will show the colors even when color is ++%C(always,++_<spec>_++)++ will show the colors even when color is
not otherwise enabled (though consider just using not otherwise enabled (though consider just using
`--color=always` to enable color for the whole output, `--color=always` to enable color for the whole output,
including this format and anything else git might color). including this format and anything else git might color).
`auto` alone (i.e. `%C(auto)`) will turn on auto coloring `auto` alone (i.e. ++%C(auto)++) will turn on auto coloring
on the next placeholders until the color is switched on the next placeholders until the color is switched
again. again.
'%m':: left (`<`), right (`>`) or boundary (`-`) mark ++%m++:: left (`<`), right (`>`) or boundary (`-`) mark
'%w([<w>[,<i1>[,<i2>]]])':: switch line wrapping, like the -w option of ++%w(++`[<w>[,<i1>[,<i2>]]]`++)++:: switch line wrapping, like the `-w` option of
linkgit:git-shortlog[1]. linkgit:git-shortlog[1].
'%<( <N> [,trunc|ltrunc|mtrunc])':: make the next placeholder take at ++%<(++`<n>[,(trunc|ltrunc|mtrunc)]`++)++:: make the next placeholder take at
least N column widths, padding spaces on least N column widths, padding spaces on
the right if necessary. Optionally the right if necessary. Optionally
truncate (with ellipsis '..') at the left (ltrunc) `..ft`, truncate (with ellipsis `..`) at the left (ltrunc) `..ft`,
the middle (mtrunc) `mi..le`, or the end the middle (mtrunc) `mi..le`, or the end
(trunc) `rig..`, if the output is longer than (trunc) `rig..`, if the output is longer than
N columns. _<n>_ columns.
Note 1: that truncating Note 1: that truncating
only works correctly with N >= 2. only works correctly with _<n>_ >= 2.
Note 2: spaces around the N and M (see below) Note 2: spaces around the _<n>_ and _<m>_ (see below)
values are optional. values are optional.
Note 3: Emojis and other wide characters Note 3: Emojis and other wide characters
will take two display columns, which may will take two display columns, which may
over-run column boundaries. over-run column boundaries.
Note 4: decomposed character combining marks Note 4: decomposed character combining marks
may be misplaced at padding boundaries. may be misplaced at padding boundaries.
'%<|( <M> )':: make the next placeholder take at least until Mth ++%<|(++_<m>_ ++)++:: make the next placeholder take at least until _<m>_ th
display column, padding spaces on the right if necessary. display column, padding spaces on the right if necessary.
Use negative M values for column positions measured Use negative _<m>_ values for column positions measured
from the right hand edge of the terminal window. from the right hand edge of the terminal window.
'%>( <N> )', '%>|( <M> )':: similar to '%<( <N> )', '%<|( <M> )' respectively, ++%>(++_<n>_++)++::
++%>|(++_<m>_++)++:: similar to ++%<(++_<n>_++)++, ++%<|(++_<m>_++)++ respectively,
but padding spaces on the left but padding spaces on the left
'%>>( <N> )', '%>>|( <M> )':: similar to '%>( <N> )', '%>|( <M> )' ++%>>(++_<n>_++)++::
++%>>|(++_<m>_++)++:: similar to ++%>(++_<n>_++)++, ++%>|(++_<m>_++)++
respectively, except that if the next respectively, except that if the next
placeholder takes more spaces than given and placeholder takes more spaces than given and
there are spaces on its left, use those there are spaces on its left, use those
spaces spaces
'%><( <N> )', '%><|( <M> )':: similar to '%<( <N> )', '%<|( <M> )' ++%><(++_<n>_++)++::
++%><|(++_<m>_++)++:: similar to ++%<(++_<n>_++)++, ++%<|(++_<m>_++)++
respectively, but padding both sides respectively, but padding both sides
(i.e. the text is centered) (i.e. the text is centered)


- Placeholders that expand to information extracted from the commit: - Placeholders that expand to information extracted from the commit:
'%H':: commit hash +%H+:: commit hash
'%h':: abbreviated commit hash +%h+:: abbreviated commit hash
'%T':: tree hash +%T+:: tree hash
'%t':: abbreviated tree hash +%t+:: abbreviated tree hash
'%P':: parent hashes +%P+:: parent hashes
'%p':: abbreviated parent hashes +%p+:: abbreviated parent hashes
'%an':: author name +%an+:: author name
'%aN':: author name (respecting .mailmap, see linkgit:git-shortlog[1] +%aN+:: author name (respecting .mailmap, see linkgit:git-shortlog[1]
or linkgit:git-blame[1]) or linkgit:git-blame[1])
'%ae':: author email +%ae+:: author email
'%aE':: author email (respecting .mailmap, see linkgit:git-shortlog[1] +%aE+:: author email (respecting .mailmap, see linkgit:git-shortlog[1]
or linkgit:git-blame[1]) or linkgit:git-blame[1])
'%al':: author email local-part (the part before the '@' sign) +%al+:: author email local-part (the part before the `@` sign)
'%aL':: author local-part (see '%al') respecting .mailmap, see +%aL+:: author local-part (see +%al+) respecting .mailmap, see
linkgit:git-shortlog[1] or linkgit:git-blame[1]) linkgit:git-shortlog[1] or linkgit:git-blame[1])
'%ad':: author date (format respects --date= option) +%ad+:: author date (format respects --date= option)
'%aD':: author date, RFC2822 style +%aD+:: author date, RFC2822 style
'%ar':: author date, relative +%ar+:: author date, relative
'%at':: author date, UNIX timestamp +%at+:: author date, UNIX timestamp
'%ai':: author date, ISO 8601-like format +%ai+:: author date, ISO 8601-like format
'%aI':: author date, strict ISO 8601 format +%aI+:: author date, strict ISO 8601 format
'%as':: author date, short format (`YYYY-MM-DD`) +%as+:: author date, short format (`YYYY-MM-DD`)
'%ah':: author date, human style (like the `--date=human` option of +%ah+:: author date, human style (like the `--date=human` option of
linkgit:git-rev-list[1]) linkgit:git-rev-list[1])
'%cn':: committer name +%cn+:: committer name
'%cN':: committer name (respecting .mailmap, see +%cN+:: committer name (respecting .mailmap, see
linkgit:git-shortlog[1] or linkgit:git-blame[1]) linkgit:git-shortlog[1] or linkgit:git-blame[1])
'%ce':: committer email +%ce+:: committer email
'%cE':: committer email (respecting .mailmap, see +%cE+:: committer email (respecting .mailmap, see
linkgit:git-shortlog[1] or linkgit:git-blame[1]) linkgit:git-shortlog[1] or linkgit:git-blame[1])
'%cl':: committer email local-part (the part before the '@' sign) +%cl+:: committer email local-part (the part before the `@` sign)
'%cL':: committer local-part (see '%cl') respecting .mailmap, see +%cL+:: committer local-part (see +%cl+) respecting .mailmap, see
linkgit:git-shortlog[1] or linkgit:git-blame[1]) linkgit:git-shortlog[1] or linkgit:git-blame[1])
'%cd':: committer date (format respects --date= option) +%cd+:: committer date (format respects --date= option)
'%cD':: committer date, RFC2822 style +%cD+:: committer date, RFC2822 style
'%cr':: committer date, relative +%cr+:: committer date, relative
'%ct':: committer date, UNIX timestamp +%ct+:: committer date, UNIX timestamp
'%ci':: committer date, ISO 8601-like format +%ci+:: committer date, ISO 8601-like format
'%cI':: committer date, strict ISO 8601 format +%cI+:: committer date, strict ISO 8601 format
'%cs':: committer date, short format (`YYYY-MM-DD`) +%cs+:: committer date, short format (`YYYY-MM-DD`)
'%ch':: committer date, human style (like the `--date=human` option of +%ch+:: committer date, human style (like the `--date=human` option of
linkgit:git-rev-list[1]) linkgit:git-rev-list[1])
'%d':: ref names, like the --decorate option of linkgit:git-log[1] +%d+:: ref names, like the --decorate option of linkgit:git-log[1]
'%D':: ref names without the " (", ")" wrapping. +%D+:: ref names without the " (", ")" wrapping.
'%(decorate[:<options>])':: ++%(decorate++`[:<option>,...]`++)++::
ref names with custom decorations. The `decorate` string may be followed by a ref names with custom decorations. The `decorate` string may be followed by a
colon and zero or more comma-separated options. Option values may contain colon and zero or more comma-separated options. Option values may contain
literal formatting codes. These must be used for commas (`%x2C`) and closing literal formatting codes. These must be used for commas (`%x2C`) and closing
parentheses (`%x29`), due to their role in the option syntax. parentheses (`%x29`), due to their role in the option syntax.
+ +
** 'prefix=<value>': Shown before the list of ref names. Defaults to "{nbsp}`(`". ** `prefix=<value>`: Shown before the list of ref names. Defaults to "{nbsp}+(+".
** 'suffix=<value>': Shown after the list of ref names. Defaults to "`)`". ** `suffix=<value>`: Shown after the list of ref names. Defaults to "+)+".
** 'separator=<value>': Shown between ref names. Defaults to "`,`{nbsp}". ** `separator=<value>`: Shown between ref names. Defaults to "+,+{nbsp}".
** 'pointer=<value>': Shown between HEAD and the branch it points to, if any. ** `pointer=<value>`: Shown between HEAD and the branch it points to, if any.
Defaults to "{nbsp}`->`{nbsp}". Defaults to "{nbsp}+->+{nbsp}".
** 'tag=<value>': Shown before tag names. Defaults to "`tag:`{nbsp}". ** `tag=<value>`: Shown before tag names. Defaults to "`tag:`{nbsp}".


+ +
For example, to produce decorations with no wrapping For example, to produce decorations with no wrapping
or tag annotations, and spaces as separators: or tag annotations, and spaces as separators:
+ +
`%(decorate:prefix=,suffix=,tag=,separator= )` ++%(decorate:prefix=,suffix=,tag=,separator= )++


'%(describe[:<options>])':: ++%(describe++`[:<option>,...]`++)++::
human-readable name, like linkgit:git-describe[1]; empty string for human-readable name, like linkgit:git-describe[1]; empty string for
undescribable commits. The `describe` string may be followed by a colon and undescribable commits. The `describe` string may be followed by a colon and
zero or more comma-separated options. Descriptions can be inconsistent when zero or more comma-separated options. Descriptions can be inconsistent when
tags are added or removed at the same time. tags are added or removed at the same time.
+ +
** 'tags[=<bool-value>]': Instead of only considering annotated tags, ** `tags[=<bool-value>]`: Instead of only considering annotated tags,
consider lightweight tags as well. consider lightweight tags as well.
** 'abbrev=<number>': Instead of using the default number of hexadecimal digits ** `abbrev=<number>`: Instead of using the default number of hexadecimal digits
(which will vary according to the number of objects in the repository with a (which will vary according to the number of objects in the repository with a
default of 7) of the abbreviated object name, use <number> digits, or as many default of 7) of the abbreviated object name, use <number> digits, or as many
digits as needed to form a unique object name. digits as needed to form a unique object name.
** 'match=<pattern>': Only consider tags matching the given ** `match=<pattern>`: Only consider tags matching the given
`glob(7)` pattern, excluding the "refs/tags/" prefix. `glob(7)` _<pattern>_, excluding the `refs/tags/` prefix.
** 'exclude=<pattern>': Do not consider tags matching the given ** `exclude=<pattern>`: Do not consider tags matching the given
`glob(7)` pattern, excluding the "refs/tags/" prefix. `glob(7)` _<pattern>_, excluding the `refs/tags/` prefix.


'%S':: ref name given on the command line by which the commit was reached +%S+:: ref name given on the command line by which the commit was reached
(like `git log --source`), only works with `git log` (like `git log --source`), only works with `git log`
'%e':: encoding +%e+:: encoding
'%s':: subject +%s+:: subject
'%f':: sanitized subject line, suitable for a filename +%f+:: sanitized subject line, suitable for a filename
'%b':: body +%b+:: body
'%B':: raw body (unwrapped subject and body) +%B+:: raw body (unwrapped subject and body)
ifndef::git-rev-list[] ifndef::git-rev-list[]
'%N':: commit notes +%N+:: commit notes
endif::git-rev-list[] endif::git-rev-list[]
'%GG':: raw verification message from GPG for a signed commit +%GG+:: raw verification message from GPG for a signed commit
'%G?':: show "G" for a good (valid) signature, +%G?+:: show "G" for a good (valid) signature,
"B" for a bad signature, "B" for a bad signature,
"U" for a good signature with unknown validity, "U" for a good signature with unknown validity,
"X" for a good signature that has expired, "X" for a good signature that has expired,
@ -279,86 +282,86 @@ endif::git-rev-list[]
"R" for a good signature made by a revoked key, "R" for a good signature made by a revoked key,
"E" if the signature cannot be checked (e.g. missing key) "E" if the signature cannot be checked (e.g. missing key)
and "N" for no signature and "N" for no signature
'%GS':: show the name of the signer for a signed commit +%GS+:: show the name of the signer for a signed commit
'%GK':: show the key used to sign a signed commit +%GK+:: show the key used to sign a signed commit
'%GF':: show the fingerprint of the key used to sign a signed commit +%GF+:: show the fingerprint of the key used to sign a signed commit
'%GP':: show the fingerprint of the primary key whose subkey was used +%GP+:: show the fingerprint of the primary key whose subkey was used
to sign a signed commit to sign a signed commit
'%GT':: show the trust level for the key used to sign a signed commit +%GT+:: show the trust level for the key used to sign a signed commit
'%gD':: reflog selector, e.g., `refs/stash@{1}` or `refs/stash@{2 +%gD+:: reflog selector, e.g., `refs/stash@{1}` or `refs/stash@{2
minutes ago}`; the format follows the rules described for the minutes ago}`; the format follows the rules described for the
`-g` option. The portion before the `@` is the refname as `-g` option. The portion before the `@` is the refname as
given on the command line (so `git log -g refs/heads/master` given on the command line (so `git log -g refs/heads/master`
would yield `refs/heads/master@{0}`). would yield `refs/heads/master@{0}`).
'%gd':: shortened reflog selector; same as `%gD`, but the refname +%gd+:: shortened reflog selector; same as `%gD`, but the refname
portion is shortened for human readability (so portion is shortened for human readability (so
`refs/heads/master` becomes just `master`). `refs/heads/master` becomes just `master`).
'%gn':: reflog identity name +%gn+:: reflog identity name
'%gN':: reflog identity name (respecting .mailmap, see +%gN+:: reflog identity name (respecting .mailmap, see
linkgit:git-shortlog[1] or linkgit:git-blame[1]) linkgit:git-shortlog[1] or linkgit:git-blame[1])
'%ge':: reflog identity email +%ge+:: reflog identity email
'%gE':: reflog identity email (respecting .mailmap, see +%gE+:: reflog identity email (respecting .mailmap, see
linkgit:git-shortlog[1] or linkgit:git-blame[1]) linkgit:git-shortlog[1] or linkgit:git-blame[1])
'%gs':: reflog subject +%gs+:: reflog subject
'%(trailers[:<options>])':: ++%(trailers++`[:<option>,...]`++)++::
display the trailers of the body as interpreted by display the trailers of the body as interpreted by
linkgit:git-interpret-trailers[1]. The `trailers` string may be followed by linkgit:git-interpret-trailers[1]. The `trailers` string may be followed by
a colon and zero or more comma-separated options. If any option is provided a colon and zero or more comma-separated options. If any option is provided
multiple times, the last occurrence wins. multiple times, the last occurrence wins.
+ +
** 'key=<key>': only show trailers with specified <key>. Matching is done ** `key=<key>`: only show trailers with specified <key>. Matching is done
case-insensitively and trailing colon is optional. If option is case-insensitively and trailing colon is optional. If option is
given multiple times trailer lines matching any of the keys are given multiple times trailer lines matching any of the keys are
shown. This option automatically enables the `only` option so that shown. This option automatically enables the `only` option so that
non-trailer lines in the trailer block are hidden. If that is not non-trailer lines in the trailer block are hidden. If that is not
desired it can be disabled with `only=false`. E.g., desired it can be disabled with `only=false`. E.g.,
`%(trailers:key=Reviewed-by)` shows trailer lines with key +%(trailers:key=Reviewed-by)+ shows trailer lines with key
`Reviewed-by`. `Reviewed-by`.
** 'only[=<bool>]': select whether non-trailer lines from the trailer ** `only[=<bool>]`: select whether non-trailer lines from the trailer
block should be included. block should be included.
** 'separator=<sep>': specify the separator inserted between trailer ** `separator=<sep>`: specify the separator inserted between trailer
lines. Defaults to a line feed character. The string <sep> may contain lines. Defaults to a line feed character. The string <sep> may contain
the literal formatting codes described above. To use comma as the literal formatting codes described above. To use comma as
separator one must use `%x2C` as it would otherwise be parsed as separator one must use `%x2C` as it would otherwise be parsed as
next option. E.g., `%(trailers:key=Ticket,separator=%x2C )` next option. E.g., +%(trailers:key=Ticket,separator=%x2C )+
shows all trailer lines whose key is "Ticket" separated by a comma shows all trailer lines whose key is "Ticket" separated by a comma
and a space. and a space.
** 'unfold[=<bool>]': make it behave as if interpret-trailer's `--unfold` ** `unfold[=<bool>]`: make it behave as if interpret-trailer's `--unfold`
option was given. E.g., option was given. E.g.,
`%(trailers:only,unfold=true)` unfolds and shows all trailer lines. +%(trailers:only,unfold=true)+ unfolds and shows all trailer lines.
** 'keyonly[=<bool>]': only show the key part of the trailer. ** `keyonly[=<bool>]`: only show the key part of the trailer.
** 'valueonly[=<bool>]': only show the value part of the trailer. ** `valueonly[=<bool>]`: only show the value part of the trailer.
** 'key_value_separator=<sep>': specify the separator inserted between ** `key_value_separator=<sep>`: specify the separator inserted between
the key and value of each trailer. Defaults to ": ". Otherwise it the key and value of each trailer. Defaults to ": ". Otherwise it
shares the same semantics as 'separator=<sep>' above. shares the same semantics as `separator=<sep>` above.


NOTE: Some placeholders may depend on other options given to the NOTE: Some placeholders may depend on other options given to the
revision traversal engine. For example, the `%g*` reflog options will revision traversal engine. For example, the +%g*+ reflog options will
insert an empty string unless we are traversing reflog entries (e.g., by insert an empty string unless we are traversing reflog entries (e.g., by
`git log -g`). The `%d` and `%D` placeholders will use the "short" `git log -g`). The +%d+ and +%D+ placeholders will use the "short"
decoration format if `--decorate` was not already provided on the command decoration format if `--decorate` was not already provided on the command
line. line.


The boolean options accept an optional value `[=<bool-value>]`. The The boolean options accept an optional value `[=<bool-value>]`. The
values taken by `--type=bool` git-config[1], like `yes` and `off`, values taken by `--type=bool` linkgit:git-config[1], like `yes` and `off`,
are all accepted. Giving a boolean option without `=<value>` is are all accepted. Giving a boolean option without `=<value>` is
equivalent to giving it with `=true`. equivalent to giving it with `=true`.


If you add a `+` (plus sign) after '%' of a placeholder, a line-feed If you add a `+` (plus sign) after +%+ of a placeholder, a line-feed
is inserted immediately before the expansion if and only if the is inserted immediately before the expansion if and only if the
placeholder expands to a non-empty string. placeholder expands to a non-empty string.


If you add a `-` (minus sign) after '%' of a placeholder, all consecutive If you add a `-` (minus sign) after +%+ of a placeholder, all consecutive
line-feeds immediately preceding the expansion are deleted if and only if the line-feeds immediately preceding the expansion are deleted if and only if the
placeholder expands to an empty string. placeholder expands to an empty string.


If you add a ` ` (space) after '%' of a placeholder, a space If you add a `' '` (space) after +%+ of a placeholder, a space
is inserted immediately before the expansion if and only if the is inserted immediately before the expansion if and only if the
placeholder expands to a non-empty string. placeholder expands to a non-empty string.


* 'tformat:' * `tformat:`
+ +
The 'tformat:' format works exactly like 'format:', except that it The `tformat:` format works exactly like `format:`, except that it
provides "terminator" semantics instead of "separator" semantics. In provides "terminator" semantics instead of "separator" semantics. In
other words, each commit has the message terminator character (usually a other words, each commit has the message terminator character (usually a
newline) appended, rather than a separator placed between entries. newline) appended, rather than a separator placed between entries.
@ -378,7 +381,7 @@ $ git log -2 --pretty=tformat:%h 4da45bef \
7134973 7134973
--------------------- ---------------------
+ +
In addition, any unrecognized string that has a `%` in it is interpreted In addition, any unrecognized string that has a +%+ in it is interpreted
as if it has `tformat:` in front of it. For example, these two are as if it has `tformat:` in front of it. For example, these two are
equivalent: equivalent:
+ +

View File

@ -1,38 +1,38 @@
--pretty[=<format>]:: `--pretty[=<format>]`::
--format=<format>:: `--format=<format>`::


Pretty-print the contents of the commit logs in a given format, Pretty-print the contents of the commit logs in a given format,
where '<format>' can be one of 'oneline', 'short', 'medium', where '<format>' can be one of `oneline`, `short`, `medium`,
'full', 'fuller', 'reference', 'email', 'raw', 'format:<string>' `full`, `fuller`, `reference`, `email`, `raw`, `format:<string>`
and 'tformat:<string>'. When '<format>' is none of the above, and `tformat:<string>`. When _<format>_ is none of the above,
and has '%placeholder' in it, it acts as if and has `%<placeholder>` in it, it acts as if
'--pretty=tformat:<format>' were given. `--pretty=tformat:<format>` were given.
+ +
See the "PRETTY FORMATS" section for some additional details for each See the "PRETTY FORMATS" section for some additional details for each
format. When '=<format>' part is omitted, it defaults to 'medium'. format. When `=<format>` part is omitted, it defaults to `medium`.
+ +
Note: you can specify the default pretty format in the repository NOTE: you can specify the default pretty format in the repository
configuration (see linkgit:git-config[1]). configuration (see linkgit:git-config[1]).


--abbrev-commit:: `--abbrev-commit`::
Instead of showing the full 40-byte hexadecimal commit object Instead of showing the full 40-byte hexadecimal commit object
name, show a prefix that names the object uniquely. name, show a prefix that names the object uniquely.
"--abbrev=<n>" (which also modifies diff output, if it is displayed) `--abbrev=<n>` (which also modifies diff output, if it is displayed)
option can be used to specify the minimum length of the prefix. option can be used to specify the minimum length of the prefix.
+ +
This should make "--pretty=oneline" a whole lot more readable for This should make `--pretty=oneline` a whole lot more readable for
people using 80-column terminals. people using 80-column terminals.


--no-abbrev-commit:: `--no-abbrev-commit`::
Show the full 40-byte hexadecimal commit object name. This negates Show the full 40-byte hexadecimal commit object name. This negates
`--abbrev-commit`, either explicit or implied by other options such `--abbrev-commit`, either explicit or implied by other options such
as "--oneline". It also overrides the `log.abbrevCommit` variable. as `--oneline`. It also overrides the `log.abbrevCommit` variable.


--oneline:: `--oneline`::
This is a shorthand for "--pretty=oneline --abbrev-commit" This is a shorthand for `--pretty=oneline --abbrev-commit`
used together. used together.


--encoding=<encoding>:: `--encoding=<encoding>`::
Commit objects record the character encoding used for the log message Commit objects record the character encoding used for the log message
in their encoding header; this option can be used to tell the in their encoding header; this option can be used to tell the
command to re-code the commit log message in the encoding command to re-code the commit log message in the encoding
@ -44,25 +44,30 @@ people using 80-column terminals.
to convert the commit, we will quietly output the original to convert the commit, we will quietly output the original
object verbatim. object verbatim.


--expand-tabs=<n>:: `--expand-tabs=<n>`::
--expand-tabs:: `--expand-tabs`::
--no-expand-tabs:: `--no-expand-tabs`::
Perform a tab expansion (replace each tab with enough spaces Perform a tab expansion (replace each tab with enough spaces
to fill to the next display column that is a multiple of '<n>') to fill to the next display column that is a multiple of _<n>_)
in the log message before showing it in the output. in the log message before showing it in the output.
`--expand-tabs` is a short-hand for `--expand-tabs=8`, and `--expand-tabs` is a short-hand for `--expand-tabs=8`, and
`--no-expand-tabs` is a short-hand for `--expand-tabs=0`, `--no-expand-tabs` is a short-hand for `--expand-tabs=0`,
which disables tab expansion. which disables tab expansion.
+ +
By default, tabs are expanded in pretty formats that indent the log By default, tabs are expanded in pretty formats that indent the log
message by 4 spaces (i.e. 'medium', which is the default, 'full', message by 4 spaces (i.e. `medium`, which is the default, `full`,
and 'fuller'). and `fuller`).


ifndef::git-rev-list[] ifndef::git-rev-list[]
--notes[=<ref>]:: `--notes[=<ref>]`::
Show the notes (see linkgit:git-notes[1]) that annotate the Show the notes (see linkgit:git-notes[1]) that annotate the
commit, when showing the commit log message. This is the default commit, when showing the commit log message. This is the default
ifndef::with-breaking-changes[]
for `git log`, `git show` and `git whatchanged` commands when for `git log`, `git show` and `git whatchanged` commands when
endif::with-breaking-changes[]
ifdef::with-breaking-changes[]
for `git log` and `git show` commands when
endif::with-breaking-changes[]
there is no `--pretty`, `--format`, or `--oneline` option given there is no `--pretty`, `--format`, or `--oneline` option given
on the command line. on the command line.
+ +
@ -75,28 +80,29 @@ to display. The ref can specify the full refname when it begins
with `refs/notes/`; when it begins with `notes/`, `refs/` and otherwise with `refs/notes/`; when it begins with `notes/`, `refs/` and otherwise
`refs/notes/` is prefixed to form the full name of the ref. `refs/notes/` is prefixed to form the full name of the ref.
+ +
Multiple --notes options can be combined to control which notes are Multiple `--notes` options can be combined to control which notes are
being displayed. Examples: "--notes=foo" will show only notes from being displayed. Examples: "`--notes=foo`" will show only notes from
"refs/notes/foo"; "--notes=foo --notes" will show both notes from `refs/notes/foo`; "`--notes=foo --notes`" will show both notes from
"refs/notes/foo" and from the default notes ref(s). "refs/notes/foo" and from the default notes ref(s).


--no-notes:: `--no-notes`::
Do not show notes. This negates the above `--notes` option, by Do not show notes. This negates the above `--notes` option, by
resetting the list of notes refs from which notes are shown. resetting the list of notes refs from which notes are shown.
Options are parsed in the order given on the command line, so e.g. Options are parsed in the order given on the command line, so e.g.
"--notes --notes=foo --no-notes --notes=bar" will only show notes "`--notes --notes=foo --no-notes --notes=bar`" will only show notes
from "refs/notes/bar". from `refs/notes/bar`.


--show-notes-by-default:: `--show-notes-by-default`::
Show the default notes unless options for displaying specific Show the default notes unless options for displaying specific
notes are given. notes are given.


--show-notes[=<ref>]:: `--show-notes[=<ref>]`::
--[no-]standard-notes:: `--standard-notes`::
These options are deprecated. Use the above --notes/--no-notes `--no-standard-notes`::
These options are deprecated. Use the above `--notes`/`--no-notes`
options instead. options instead.
endif::git-rev-list[] endif::git-rev-list[]


--show-signature:: `--show-signature`::
Check the validity of a signed commit object by passing the signature Check the validity of a signed commit object by passing the signature
to `gpg --verify` and show the output. to `gpg --verify` and show the output.

View File

@ -26,8 +26,8 @@ endif::git-log[]
means "list all the commits which are reachable from 'foo' or 'bar', but means "list all the commits which are reachable from 'foo' or 'bar', but
not from 'baz'". not from 'baz'".


A special notation "'<commit1>'..'<commit2>'" can be used as a A special notation "`<commit1>..<commit2>`" can be used as a
short-hand for "^'<commit1>' '<commit2>'". For example, either of short-hand for "`^<commit1> <commit2>`". For example, either of
the following may be used interchangeably: the following may be used interchangeably:


ifdef::git-rev-list[] ifdef::git-rev-list[]
@ -43,7 +43,7 @@ $ git log HEAD ^origin
----------------------------------------------------------------------- -----------------------------------------------------------------------
endif::git-log[] endif::git-log[]


Another special notation is "'<commit1>'...'<commit2>'" which is useful Another special notation is "`<commit1>...<commit2>`" which is useful
for merges. The resulting set of commits is the symmetric difference for merges. The resulting set of commits is the symmetric difference
between the two operands. The following two commands are equivalent: between the two operands. The following two commands are equivalent:



View File

@ -6,60 +6,60 @@ special notations explained in the description, additional commit
limiting may be applied. limiting may be applied.


Using more options generally further limits the output (e.g. Using more options generally further limits the output (e.g.
`--since=<date1>` limits to commits newer than `<date1>`, and using it `--since=<date1>` limits to commits newer than _<date1>_, and using it
with `--grep=<pattern>` further limits to commits whose log message with `--grep=<pattern>` further limits to commits whose log message
has a line that matches `<pattern>`), unless otherwise noted. has a line that matches _<pattern>_), unless otherwise noted.


Note that these are applied before commit Note that these are applied before commit
ordering and formatting options, such as `--reverse`. ordering and formatting options, such as `--reverse`.


-<number>:: `-<number>`::
-n <number>:: `-n <number>`::
--max-count=<number>:: `--max-count=<number>`::
Limit the number of commits to output. Limit the output to _<number>_ commits.


--skip=<number>:: `--skip=<number>`::
Skip 'number' commits before starting to show the commit output. Skip _<number>_ commits before starting to show the commit output.


--since=<date>:: `--since=<date>`::
--after=<date>:: `--after=<date>`::
Show commits more recent than a specific date. Show commits more recent than _<date>_.


--since-as-filter=<date>:: `--since-as-filter=<date>`::
Show all commits more recent than a specific date. This visits Show all commits more recent than _<date>_. This visits
all commits in the range, rather than stopping at the first commit which all commits in the range, rather than stopping at the first commit which
is older than a specific date. is older than _<date>_.


--until=<date>:: `--until=<date>`::
--before=<date>:: `--before=<date>`::
Show commits older than a specific date. Show commits older than _<date>_.


ifdef::git-rev-list[] ifdef::git-rev-list[]
--max-age=<timestamp>:: `--max-age=<timestamp>`::
--min-age=<timestamp>:: `--min-age=<timestamp>`::
Limit the commits output to specified time range. Limit the commits output to specified time range.
endif::git-rev-list[] endif::git-rev-list[]


--author=<pattern>:: `--author=<pattern>`::
--committer=<pattern>:: `--committer=<pattern>`::
Limit the commits output to ones with author/committer Limit the commits output to ones with author/committer
header lines that match the specified pattern (regular header lines that match the _<pattern>_ regular
expression). With more than one `--author=<pattern>`, expression. With more than one `--author=<pattern>`,
commits whose author matches any of the given patterns are commits whose author matches any of the _<pattern>_ are
chosen (similarly for multiple `--committer=<pattern>`). chosen (similarly for multiple `--committer=<pattern>`).


--grep-reflog=<pattern>:: `--grep-reflog=<pattern>`::
Limit the commits output to ones with reflog entries that Limit the commits output to ones with reflog entries that
match the specified pattern (regular expression). With match the _<pattern>_ regular expression. With
more than one `--grep-reflog`, commits whose reflog message more than one `--grep-reflog`, commits whose reflog message
matches any of the given patterns are chosen. It is an matches any of the given patterns are chosen. It is an
error to use this option unless `--walk-reflogs` is in use. error to use this option unless `--walk-reflogs` is in use.


--grep=<pattern>:: `--grep=<pattern>`::
Limit the commits output to ones with a log message that Limit the commits output to ones with a log message that
matches the specified pattern (regular expression). With matches the _<pattern>_ regular expression. With
more than one `--grep=<pattern>`, commits whose message more than one `--grep=<pattern>`, commits whose message
matches any of the given patterns are chosen (but see matches any of the _<pattern>_ are chosen (but see
`--all-match`). `--all-match`).
ifndef::git-rev-list[] ifndef::git-rev-list[]
+ +
@ -67,35 +67,35 @@ When `--notes` is in effect, the message from the notes is
matched as if it were part of the log message. matched as if it were part of the log message.
endif::git-rev-list[] endif::git-rev-list[]


--all-match:: `--all-match`::
Limit the commits output to ones that match all given `--grep`, Limit the commits output to ones that match all given `--grep`,
instead of ones that match at least one. instead of ones that match at least one.


--invert-grep:: `--invert-grep`::
Limit the commits output to ones with a log message that do not Limit the commits output to ones with a log message that do not
match the pattern specified with `--grep=<pattern>`. match the _<pattern>_ specified with `--grep=<pattern>`.


-i:: `-i`::
--regexp-ignore-case:: `--regexp-ignore-case`::
Match the regular expression limiting patterns without regard to letter Match the regular expression limiting patterns without regard to letter
case. case.


--basic-regexp:: `--basic-regexp`::
Consider the limiting patterns to be basic regular expressions; Consider the limiting patterns to be basic regular expressions;
this is the default. this is the default.


-E:: `-E`::
--extended-regexp:: `--extended-regexp`::
Consider the limiting patterns to be extended regular expressions Consider the limiting patterns to be extended regular expressions
instead of the default basic regular expressions. instead of the default basic regular expressions.


-F:: `-F`::
--fixed-strings:: `--fixed-strings`::
Consider the limiting patterns to be fixed strings (don't interpret Consider the limiting patterns to be fixed strings (don't interpret
pattern as a regular expression). pattern as a regular expression).


-P:: `-P`::
--perl-regexp:: `--perl-regexp`::
Consider the limiting patterns to be Perl-compatible regular Consider the limiting patterns to be Perl-compatible regular
expressions. expressions.
+ +
@ -103,20 +103,20 @@ Support for these types of regular expressions is an optional
compile-time dependency. If Git wasn't compiled with support for them compile-time dependency. If Git wasn't compiled with support for them
providing this option will cause it to die. providing this option will cause it to die.


--remove-empty:: `--remove-empty`::
Stop when a given path disappears from the tree. Stop when a given path disappears from the tree.


--merges:: `--merges`::
Print only merge commits. This is exactly the same as `--min-parents=2`. Print only merge commits. This is exactly the same as `--min-parents=2`.


--no-merges:: `--no-merges`::
Do not print commits with more than one parent. This is Do not print commits with more than one parent. This is
exactly the same as `--max-parents=1`. exactly the same as `--max-parents=1`.


--min-parents=<number>:: `--min-parents=<number>`::
--max-parents=<number>:: `--max-parents=<number>`::
--no-min-parents:: `--no-min-parents`::
--no-max-parents:: `--no-max-parents`::
Show only commits which have at least (or at most) that many parent Show only commits which have at least (or at most) that many parent
commits. In particular, `--max-parents=1` is the same as `--no-merges`, commits. In particular, `--max-parents=1` is the same as `--no-merges`,
`--min-parents=2` is the same as `--merges`. `--max-parents=0` `--min-parents=2` is the same as `--merges`. `--max-parents=0`
@ -126,7 +126,7 @@ providing this option will cause it to die.
again. Equivalent forms are `--min-parents=0` (any commit has 0 or more again. Equivalent forms are `--min-parents=0` (any commit has 0 or more
parents) and `--max-parents=-1` (negative numbers denote no upper limit). parents) and `--max-parents=-1` (negative numbers denote no upper limit).


--first-parent:: `--first-parent`::
When finding commits to include, follow only the first When finding commits to include, follow only the first
parent commit upon seeing a merge commit. This option parent commit upon seeing a merge commit. This option
can give a better overview when viewing the evolution of can give a better overview when viewing the evolution of
@ -141,14 +141,14 @@ This option also changes default diff format for merge commits
to `first-parent`, see `--diff-merges=first-parent` for details. to `first-parent`, see `--diff-merges=first-parent` for details.
endif::git-log[] endif::git-log[]


--exclude-first-parent-only:: `--exclude-first-parent-only`::
When finding commits to exclude (with a '{caret}'), follow only When finding commits to exclude (with a '{caret}'), follow only
the first parent commit upon seeing a merge commit. the first parent commit upon seeing a merge commit.
This can be used to find the set of changes in a topic branch This can be used to find the set of changes in a topic branch
from the point where it diverged from the remote branch, given from the point where it diverged from the remote branch, given
that arbitrary merges can be valid topic branch changes. that arbitrary merges can be valid topic branch changes.


--not:: `--not`::
Reverses the meaning of the '{caret}' prefix (or lack thereof) Reverses the meaning of the '{caret}' prefix (or lack thereof)
for all following revision specifiers, up to the next `--not`. for all following revision specifiers, up to the next `--not`.
When used on the command line before --stdin, the revisions passed When used on the command line before --stdin, the revisions passed
@ -156,37 +156,37 @@ endif::git-log[]
via standard input, the revisions passed on the command line will via standard input, the revisions passed on the command line will
not be affected by it. not be affected by it.


--all:: `--all`::
Pretend as if all the refs in `refs/`, along with `HEAD`, are Pretend as if all the refs in `refs/`, along with `HEAD`, are
listed on the command line as '<commit>'. listed on the command line as _<commit>_.


--branches[=<pattern>]:: `--branches[=<pattern>]`::
Pretend as if all the refs in `refs/heads` are listed Pretend as if all the refs in `refs/heads` are listed
on the command line as '<commit>'. If '<pattern>' is given, limit on the command line as _<commit>_. If _<pattern>_ is given, limit
branches to ones matching given shell glob. If pattern lacks '?', branches to ones matching given shell glob. If _<pattern>_ lacks '?',
'{asterisk}', or '[', '/{asterisk}' at the end is implied. '{asterisk}', or '[', '/{asterisk}' at the end is implied.


--tags[=<pattern>]:: `--tags[=<pattern>]`::
Pretend as if all the refs in `refs/tags` are listed Pretend as if all the refs in `refs/tags` are listed
on the command line as '<commit>'. If '<pattern>' is given, limit on the command line as _<commit>_. If _<pattern>_ is given, limit
tags to ones matching given shell glob. If pattern lacks '?', '{asterisk}', tags to ones matching given shell glob. If pattern lacks '?', '{asterisk}',
or '[', '/{asterisk}' at the end is implied. or '[', '/{asterisk}' at the end is implied.


--remotes[=<pattern>]:: `--remotes[=<pattern>]`::
Pretend as if all the refs in `refs/remotes` are listed Pretend as if all the refs in `refs/remotes` are listed
on the command line as '<commit>'. If '<pattern>' is given, limit on the command line as _<commit>_. If _<pattern>_ is given, limit
remote-tracking branches to ones matching given shell glob. remote-tracking branches to ones matching given shell glob.
If pattern lacks '?', '{asterisk}', or '[', '/{asterisk}' at the end is implied. If pattern lacks '?', '{asterisk}', or '[', '/{asterisk}' at the end is implied.


--glob=<glob-pattern>:: `--glob=<glob-pattern>`::
Pretend as if all the refs matching shell glob '<glob-pattern>' Pretend as if all the refs matching shell glob _<glob-pattern>_
are listed on the command line as '<commit>'. Leading 'refs/', are listed on the command line as _<commit>_. Leading 'refs/',
is automatically prepended if missing. If pattern lacks '?', '{asterisk}', is automatically prepended if missing. If pattern lacks '?', '{asterisk}',
or '[', '/{asterisk}' at the end is implied. or '[', '/{asterisk}' at the end is implied.


--exclude=<glob-pattern>:: `--exclude=<glob-pattern>`::


Do not include refs matching '<glob-pattern>' that the next `--all`, Do not include refs matching _<glob-pattern>_ that the next `--all`,
`--branches`, `--tags`, `--remotes`, or `--glob` would otherwise `--branches`, `--tags`, `--remotes`, or `--glob` would otherwise
consider. Repetitions of this option accumulate exclusion patterns consider. Repetitions of this option accumulate exclusion patterns
up to the next `--all`, `--branches`, `--tags`, `--remotes`, or up to the next `--all`, `--branches`, `--tags`, `--remotes`, or
@ -199,7 +199,7 @@ respectively, and they must begin with `refs/` when applied to `--glob`
or `--all`. If a trailing '/{asterisk}' is intended, it must be given or `--all`. If a trailing '/{asterisk}' is intended, it must be given
explicitly. explicitly.


--exclude-hidden=[fetch|receive|uploadpack]:: `--exclude-hidden=(fetch|receive|uploadpack)`::
Do not include refs that would be hidden by `git-fetch`, Do not include refs that would be hidden by `git-fetch`,
`git-receive-pack` or `git-upload-pack` by consulting the appropriate `git-receive-pack` or `git-upload-pack` by consulting the appropriate
`fetch.hideRefs`, `receive.hideRefs` or `uploadpack.hideRefs` `fetch.hideRefs`, `receive.hideRefs` or `uploadpack.hideRefs`
@ -207,11 +207,11 @@ explicitly.
linkgit:git-config[1]). This option affects the next pseudo-ref option linkgit:git-config[1]). This option affects the next pseudo-ref option
`--all` or `--glob` and is cleared after processing them. `--all` or `--glob` and is cleared after processing them.


--reflog:: `--reflog`::
Pretend as if all objects mentioned by reflogs are listed on the Pretend as if all objects mentioned by reflogs are listed on the
command line as `<commit>`. command line as _<commit>_.


--alternate-refs:: `--alternate-refs`::
Pretend as if all objects mentioned as ref tips of alternate Pretend as if all objects mentioned as ref tips of alternate
repositories were listed on the command line. An alternate repositories were listed on the command line. An alternate
repository is any repository whose object directory is specified repository is any repository whose object directory is specified
@ -219,7 +219,7 @@ explicitly.
be modified by `core.alternateRefsCommand`, etc. See be modified by `core.alternateRefsCommand`, etc. See
linkgit:git-config[1]. linkgit:git-config[1].


--single-worktree:: `--single-worktree`::
By default, all working trees will be examined by the By default, all working trees will be examined by the
following options when there are more than one (see following options when there are more than one (see
linkgit:git-worktree[1]): `--all`, `--reflog` and linkgit:git-worktree[1]): `--all`, `--reflog` and
@ -227,19 +227,19 @@ explicitly.
This option forces them to examine the current working tree This option forces them to examine the current working tree
only. only.


--ignore-missing:: `--ignore-missing`::
Upon seeing an invalid object name in the input, pretend as if Upon seeing an invalid object name in the input, pretend as if
the bad input was not given. the bad input was not given.


ifndef::git-rev-list[] ifndef::git-rev-list[]
--bisect:: `--bisect`::
Pretend as if the bad bisection ref `refs/bisect/bad` Pretend as if the bad bisection ref `refs/bisect/bad`
was listed and as if it was followed by `--not` and the good was listed and as if it was followed by `--not` and the good
bisection refs `refs/bisect/good-*` on the command bisection refs `refs/bisect/good-*` on the command
line. line.
endif::git-rev-list[] endif::git-rev-list[]


--stdin:: `--stdin`::
In addition to getting arguments from the command line, read In addition to getting arguments from the command line, read
them from standard input as well. This accepts commits and them from standard input as well. This accepts commits and
pseudo-options like `--all` and `--glob=`. When a `--` separator pseudo-options like `--all` and `--glob=`. When a `--` separator
@ -249,15 +249,15 @@ endif::git-rev-list[]
influence any subsequent command line arguments. influence any subsequent command line arguments.


ifdef::git-rev-list[] ifdef::git-rev-list[]
--quiet:: `--quiet`::
Don't print anything to standard output. This form Don't print anything to standard output. This form
is primarily meant to allow the caller to is primarily meant to allow the caller to
test the exit status to see if a range of objects is fully test the exit status to see if a range of objects is fully
connected (or not). It is faster than redirecting stdout connected (or not). It is faster than redirecting stdout
to `/dev/null` as the output does not have to be formatted. to `/dev/null` as the output does not have to be formatted.


--disk-usage:: `--disk-usage`::
--disk-usage=human:: `--disk-usage=human`::
Suppress normal output; instead, print the sum of the bytes used Suppress normal output; instead, print the sum of the bytes used
for on-disk storage by the selected commits or objects. This is for on-disk storage by the selected commits or objects. This is
equivalent to piping the output into `git cat-file equivalent to piping the output into `git cat-file
@ -269,11 +269,11 @@ ifdef::git-rev-list[]
in human-readable string(e.g. 12.24 Kib, 3.50 Mib). in human-readable string(e.g. 12.24 Kib, 3.50 Mib).
endif::git-rev-list[] endif::git-rev-list[]


--cherry-mark:: `--cherry-mark`::
Like `--cherry-pick` (see below) but mark equivalent commits Like `--cherry-pick` (see below) but mark equivalent commits
with `=` rather than omitting them, and inequivalent ones with `+`. with `=` rather than omitting them, and inequivalent ones with `+`.


--cherry-pick:: `--cherry-pick`::
Omit any commit that introduces the same change as Omit any commit that introduces the same change as
another commit on the ``other side'' when the set of another commit on the ``other side'' when the set of
commits are limited with symmetric difference. commits are limited with symmetric difference.
@ -286,8 +286,8 @@ cherry-picked from the other branch (for example, ``3rd on b'' may be
cherry-picked from branch A). With this option, such pairs of commits are cherry-picked from branch A). With this option, such pairs of commits are
excluded from the output. excluded from the output.


--left-only:: `--left-only`::
--right-only:: `--right-only`::
List only commits on the respective side of a symmetric difference, List only commits on the respective side of a symmetric difference,
i.e. only those which would be marked `<` resp. `>` by i.e. only those which would be marked `<` resp. `>` by
`--left-right`. `--left-right`.
@ -298,20 +298,20 @@ commits from `B` which are in `A` or are patch-equivalent to a commit in
More precisely, `--cherry-pick --right-only --no-merges` gives the exact More precisely, `--cherry-pick --right-only --no-merges` gives the exact
list. list.


--cherry:: `--cherry`::
A synonym for `--right-only --cherry-mark --no-merges`; useful to A synonym for `--right-only --cherry-mark --no-merges`; useful to
limit the output to the commits on our side and mark those that limit the output to the commits on our side and mark those that
have been applied to the other side of a forked history with have been applied to the other side of a forked history with
`git log --cherry upstream...mybranch`, similar to `git log --cherry upstream...mybranch`, similar to
`git cherry upstream mybranch`. `git cherry upstream mybranch`.


-g:: `-g`::
--walk-reflogs:: `--walk-reflogs`::
Instead of walking the commit ancestry chain, walk Instead of walking the commit ancestry chain, walk
reflog entries from the most recent one to older ones. reflog entries from the most recent one to older ones.
When this option is used you cannot specify commits to When this option is used you cannot specify commits to
exclude (that is, '{caret}commit', 'commit1..commit2', exclude (that is, `^<commit>`, `<commit1>..<commit2>`,
and 'commit1\...commit2' notations cannot be used). and `<commit1>...<commit2>` notations cannot be used).
+ +
With `--pretty` format other than `oneline` and `reference` (for obvious reasons), With `--pretty` format other than `oneline` and `reference` (for obvious reasons),
this causes the output to have two extra lines of information this causes the output to have two extra lines of information
@ -340,29 +340,29 @@ See also linkgit:git-reflog[1].
+ +
Under `--pretty=reference`, this information will not be shown at all. Under `--pretty=reference`, this information will not be shown at all.


--merge:: `--merge`::
Show commits touching conflicted paths in the range `HEAD...<other>`, Show commits touching conflicted paths in the range `HEAD...<other>`,
where `<other>` is the first existing pseudoref in `MERGE_HEAD`, where `<other>` is the first existing pseudoref in `MERGE_HEAD`,
`CHERRY_PICK_HEAD`, `REVERT_HEAD` or `REBASE_HEAD`. Only works `CHERRY_PICK_HEAD`, `REVERT_HEAD` or `REBASE_HEAD`. Only works
when the index has unmerged entries. This option can be used to show when the index has unmerged entries. This option can be used to show
relevant commits when resolving conflicts from a 3-way merge. relevant commits when resolving conflicts from a 3-way merge.


--boundary:: `--boundary`::
Output excluded boundary commits. Boundary commits are Output excluded boundary commits. Boundary commits are
prefixed with `-`. prefixed with `-`.


ifdef::git-rev-list[] ifdef::git-rev-list[]
--use-bitmap-index:: `--use-bitmap-index`::


Try to speed up the traversal using the pack bitmap index (if Try to speed up the traversal using the pack bitmap index (if
one is available). Note that when traversing with `--objects`, one is available). Note that when traversing with `--objects`,
trees and blobs will not have their associated path printed. trees and blobs will not have their associated path printed.


--progress=<header>:: `--progress=<header>`::
Show progress reports on stderr as objects are considered. The Show progress reports on stderr as objects are considered. The
`<header>` text will be printed with each progress update. `<header>` text will be printed with each progress update.


-z:: `-z`::
Instead of being newline-delimited, each outputted object and its Instead of being newline-delimited, each outputted object and its
accompanying metadata is delimited using NUL bytes. Output is printed accompanying metadata is delimited using NUL bytes. Output is printed
in the following form: in the following form:
@ -397,56 +397,56 @@ is how to do it, as there are various strategies to simplify the history.


The following options select the commits to be shown: The following options select the commits to be shown:


<paths>:: `<paths>`::
Commits modifying the given <paths> are selected. Commits modifying the given <paths> are selected.


--simplify-by-decoration:: `--simplify-by-decoration`::
Commits that are referred by some branch or tag are selected. Commits that are referred by some branch or tag are selected.


Note that extra commits can be shown to give a meaningful history. Note that extra commits can be shown to give a meaningful history.


The following options affect the way the simplification is performed: The following options affect the way the simplification is performed:


Default mode:: `Default mode`::
Simplifies the history to the simplest history explaining the Simplifies the history to the simplest history explaining the
final state of the tree. Simplest because it prunes some side final state of the tree. Simplest because it prunes some side
branches if the end result is the same (i.e. merging branches branches if the end result is the same (i.e. merging branches
with the same content) with the same content)


--show-pulls:: `--show-pulls`::
Include all commits from the default mode, but also any merge Include all commits from the default mode, but also any merge
commits that are not TREESAME to the first parent but are commits that are not TREESAME to the first parent but are
TREESAME to a later parent. This mode is helpful for showing TREESAME to a later parent. This mode is helpful for showing
the merge commits that "first introduced" a change to a branch. the merge commits that "first introduced" a change to a branch.


--full-history:: `--full-history`::
Same as the default mode, but does not prune some history. Same as the default mode, but does not prune some history.


--dense:: `--dense`::
Only the selected commits are shown, plus some to have a Only the selected commits are shown, plus some to have a
meaningful history. meaningful history.


--sparse:: `--sparse`::
All commits in the simplified history are shown. All commits in the simplified history are shown.


--simplify-merges:: `--simplify-merges`::
Additional option to `--full-history` to remove some needless Additional option to `--full-history` to remove some needless
merges from the resulting history, as there are no selected merges from the resulting history, as there are no selected
commits contributing to this merge. commits contributing to this merge.


--ancestry-path[=<commit>]:: `--ancestry-path[=<commit>]`::
When given a range of commits to display (e.g. 'commit1..commit2' When given a range of commits to display (e.g. `<commit1>..<commit2>`
or 'commit2 {caret}commit1'), and a commit <commit> in that range, or `<commit2> ^<commit1>`), and a commit _<commit>_ in that range,
only display commits in that range only display commits in that range
that are ancestors of <commit>, descendants of <commit>, or that are ancestors of _<commit>_, descendants of _<commit>_, or
<commit> itself. If no commit is specified, use 'commit1' (the _<commit>_ itself. If no commit is specified, use _<commit1>_ (the
excluded part of the range) as <commit>. Can be passed multiple excluded part of the range) as _<commit>_. Can be passed multiple
times; if so, a commit is included if it is any of the commits times; if so, a commit is included if it is any of the commits
given or if it is an ancestor or descendant of one of them. given or if it is an ancestor or descendant of one of them.


A more detailed explanation follows. A more detailed explanation follows.


Suppose you specified `foo` as the <paths>. We shall call commits Suppose you specified `foo` as the _<paths>_. We shall call commits
that modify `foo` !TREESAME, and the rest TREESAME. (In a diff that modify `foo` !TREESAME, and the rest TREESAME. (In a diff
filtered for `foo`, they look different and equal, respectively.) filtered for `foo`, they look different and equal, respectively.)


@ -466,22 +466,22 @@ The horizontal line of history A---Q is taken to be the first parent of
each merge. The commits are: each merge. The commits are:


* `I` is the initial commit, in which `foo` exists with contents * `I` is the initial commit, in which `foo` exists with contents
``asdf'', and a file `quux` exists with contents ``quux''. Initial `asdf`, and a file `quux` exists with contents `quux`. Initial
commits are compared to an empty tree, so `I` is !TREESAME. commits are compared to an empty tree, so `I` is !TREESAME.


* In `A`, `foo` contains just ``foo''. * In `A`, `foo` contains just `foo`.


* `B` contains the same change as `A`. Its merge `M` is trivial and * `B` contains the same change as `A`. Its merge `M` is trivial and
hence TREESAME to all parents. hence TREESAME to all parents.


* `C` does not change `foo`, but its merge `N` changes it to ``foobar'', * `C` does not change `foo`, but its merge `N` changes it to `foobar`,
so it is not TREESAME to any parent. so it is not TREESAME to any parent.


* `D` sets `foo` to ``baz''. Its merge `O` combines the strings from * `D` sets `foo` to `baz`. Its merge `O` combines the strings from
`N` and `D` to ``foobarbaz''; i.e., it is not TREESAME to any parent. `N` and `D` to `foobarbaz`; i.e., it is not TREESAME to any parent.


* `E` changes `quux` to ``xyzzy'', and its merge `P` combines the * `E` changes `quux` to `xyzzy`, and its merge `P` combines the
strings to ``quux xyzzy''. `P` is TREESAME to `O`, but not to `E`. strings to `quux xyzzy`. `P` is TREESAME to `O`, but not to `E`.


* `X` is an independent root commit that added a new file `side`, and `Y` * `X` is an independent root commit that added a new file `side`, and `Y`
modified it. `Y` is TREESAME to `X`. Its merge `Q` added `side` to `P`, and modified it. `Y` is TREESAME to `X`. Its merge `Q` added `side` to `P`, and
@ -517,7 +517,7 @@ Parent/child relations are only visible with `--parents`, but that does
not affect the commits selected in default mode, so we have shown the not affect the commits selected in default mode, so we have shown the
parent lines. parent lines.


--full-history without parent rewriting:: `--full-history` without parent rewriting::
This mode differs from the default in one point: always follow This mode differs from the default in one point: always follow
all parents of a merge, even if it is TREESAME to one of them. all parents of a merge, even if it is TREESAME to one of them.
Even if more than one side of the merge has commits that are Even if more than one side of the merge has commits that are
@ -536,7 +536,7 @@ Note that without parent rewriting, it is not really possible to talk
about the parent/child relationships between the commits, so we show about the parent/child relationships between the commits, so we show
them disconnected. them disconnected.


--full-history with parent rewriting:: `--full-history` with parent rewriting::
Ordinary commits are only included if they are !TREESAME Ordinary commits are only included if they are !TREESAME
(though this can be changed, see `--sparse` below). (though this can be changed, see `--sparse` below).
+ +
@ -560,18 +560,18 @@ rewritten to contain `E`'s parent `I`. The same happened for `C` and
In addition to the above settings, you can change whether TREESAME In addition to the above settings, you can change whether TREESAME
affects inclusion: affects inclusion:


--dense:: `--dense`::
Commits that are walked are included if they are not TREESAME Commits that are walked are included if they are not TREESAME
to any parent. to any parent.


--sparse:: `--sparse`::
All commits that are walked are included. All commits that are walked are included.
+ +
Note that without `--full-history`, this still simplifies merges: if Note that without `--full-history`, this still simplifies merges: if
one of the parents is TREESAME, we follow only that one, so the other one of the parents is TREESAME, we follow only that one, so the other
sides of the merge are never walked. sides of the merge are never walked.


--simplify-merges:: `--simplify-merges`::
First, build a history graph in the same way that First, build a history graph in the same way that
`--full-history` with parent rewriting does (see above). `--full-history` with parent rewriting does (see above).
+ +
@ -618,9 +618,9 @@ Note the major differences in `N`, `P`, and `Q` over `--full-history`:


There is another simplification mode available: There is another simplification mode available:


--ancestry-path[=<commit>]:: `--ancestry-path[=<commit>]`::
Limit the displayed commits to those which are an ancestor of Limit the displayed commits to those which are an ancestor of
<commit>, or which are a descendant of <commit>, or are <commit> _<commit>_, or which are a descendant of _<commit>_, or are _<commit>_
itself. itself.
+ +
As an example use case, consider the following commit history: As an example use case, consider the following commit history:
@ -636,15 +636,15 @@ As an example use case, consider the following commit history:
A regular 'D..M' computes the set of commits that are ancestors of `M`, A regular 'D..M' computes the set of commits that are ancestors of `M`,
but excludes the ones that are ancestors of `D`. This is useful to see but excludes the ones that are ancestors of `D`. This is useful to see
what happened to the history leading to `M` since `D`, in the sense what happened to the history leading to `M` since `D`, in the sense
that ``what does `M` have that did not exist in `D`''. The result in this that "what does `M` have that did not exist in `D`". The result in this
example would be all the commits, except `A` and `B` (and `D` itself, example would be all the commits, except `A` and `B` (and `D` itself,
of course). of course).
+ +
When we want to find out what commits in `M` are contaminated with the When we want to find out what commits in `M` are contaminated with the
bug introduced by `D` and need fixing, however, we might want to view bug introduced by `D` and need fixing, however, we might want to view
only the subset of 'D..M' that are actually descendants of `D`, i.e. only the subset of `D..M` that are actually descendants of `D`, i.e.
excluding `C` and `K`. This is exactly what the `--ancestry-path` excluding `C` and `K`. This is exactly what the `--ancestry-path`
option does. Applied to the 'D..M' range, it results in: option does. Applied to the `D..M` range, it results in:
+ +
----------------------------------------------------------------------- -----------------------------------------------------------------------
E-------F E-------F
@ -655,7 +655,7 @@ option does. Applied to the 'D..M' range, it results in:
----------------------------------------------------------------------- -----------------------------------------------------------------------
+ +
We can also use `--ancestry-path=D` instead of `--ancestry-path` which We can also use `--ancestry-path=D` instead of `--ancestry-path` which
means the same thing when applied to the 'D..M' range but is just more means the same thing when applied to the `D..M` range but is just more
explicit. explicit.
+ +
If we instead are interested in a given topic within this range, and all If we instead are interested in a given topic within this range, and all
@ -770,7 +770,7 @@ into the important branch. This commit may have information about why
the change `X` came to override the changes from `A` and `B` in its the change `X` came to override the changes from `A` and `B` in its
commit message. commit message.


--show-pulls:: `--show-pulls`::
In addition to the commits shown in the default history, show In addition to the commits shown in the default history, show
each merge commit that is not TREESAME to its first parent but each merge commit that is not TREESAME to its first parent but
is TREESAME to a later parent. is TREESAME to a later parent.
@ -819,7 +819,7 @@ ifdef::git-rev-list[]
Bisection Helpers Bisection Helpers
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~


--bisect:: `--bisect`::
Limit output to the one commit object which is roughly halfway between Limit output to the one commit object which is roughly halfway between
included and excluded commits. Note that the bad bisection ref included and excluded commits. Note that the bad bisection ref
`refs/bisect/bad` is added to the included commits (if it `refs/bisect/bad` is added to the included commits (if it
@ -843,7 +843,7 @@ introduces a regression is thus reduced to a binary search: repeatedly
generate and test new 'midpoint's until the commit chain is of length generate and test new 'midpoint's until the commit chain is of length
one. one.


--bisect-vars:: `--bisect-vars`::
This calculates the same as `--bisect`, except that refs in This calculates the same as `--bisect`, except that refs in
`refs/bisect/` are not used, and except that this outputs `refs/bisect/` are not used, and except that this outputs
text ready to be eval'ed by the shell. These lines will assign the text ready to be eval'ed by the shell. These lines will assign the
@ -855,7 +855,7 @@ one.
`bisect_bad`, and the number of commits we are bisecting right now to `bisect_bad`, and the number of commits we are bisecting right now to
`bisect_all`. `bisect_all`.


--bisect-all:: `--bisect-all`::
This outputs all the commit objects between the included and excluded This outputs all the commit objects between the included and excluded
commits, ordered by their distance to the included and excluded commits, ordered by their distance to the included and excluded
commits. Refs in `refs/bisect/` are not used. The farthest commits. Refs in `refs/bisect/` are not used. The farthest
@ -878,15 +878,15 @@ Commit Ordering


By default, the commits are shown in reverse chronological order. By default, the commits are shown in reverse chronological order.


--date-order:: `--date-order`::
Show no parents before all of its children are shown, but Show no parents before all of its children are shown, but
otherwise show commits in the commit timestamp order. otherwise show commits in the commit timestamp order.


--author-date-order:: `--author-date-order`::
Show no parents before all of its children are shown, but Show no parents before all of its children are shown, but
otherwise show commits in the author timestamp order. otherwise show commits in the author timestamp order.


--topo-order:: `--topo-order`::
Show no parents before all of its children are shown, and Show no parents before all of its children are shown, and
avoid showing commits on multiple lines of history avoid showing commits on multiple lines of history
intermixed. intermixed.
@ -910,8 +910,8 @@ With `--topo-order`, they would show 8 6 5 3 7 4 2 1 (or 8 7 4 2 6 5
avoid showing the commits from two parallel development track mixed avoid showing the commits from two parallel development track mixed
together. together.


--reverse:: `--reverse`::
Output the commits chosen to be shown (see Commit Limiting Output the commits chosen to be shown (see 'Commit Limiting'
section above) in reverse order. Cannot be combined with section above) in reverse order. Cannot be combined with
`--walk-reflogs`. `--walk-reflogs`.
endif::git-shortlog[] endif::git-shortlog[]
@ -923,39 +923,39 @@ Object Traversal
These options are mostly targeted for packing of Git repositories. These options are mostly targeted for packing of Git repositories.


ifdef::git-rev-list[] ifdef::git-rev-list[]
--objects:: `--objects`::
Print the object IDs of any object referenced by the listed Print the object IDs of any object referenced by the listed
commits. `--objects foo ^bar` thus means ``send me commits. `--objects foo ^bar` thus means "send me
all object IDs which I need to download if I have the commit all object IDs which I need to download if I have the commit
object _bar_ but not _foo_''. See also `--object-names` below. object `bar` but not `foo`". See also `--object-names` below.


--in-commit-order:: `--in-commit-order`::
Print tree and blob ids in order of the commits. The tree Print tree and blob ids in order of the commits. The tree
and blob ids are printed after they are first referenced and blob ids are printed after they are first referenced
by a commit. by a commit.


--objects-edge:: `--objects-edge`::
Similar to `--objects`, but also print the IDs of excluded Similar to `--objects`, but also print the IDs of excluded
commits prefixed with a ``-'' character. This is used by commits prefixed with a "`-`" character. This is used by
linkgit:git-pack-objects[1] to build a ``thin'' pack, which records linkgit:git-pack-objects[1] to build a ``thin'' pack, which records
objects in deltified form based on objects contained in these objects in deltified form based on objects contained in these
excluded commits to reduce network traffic. excluded commits to reduce network traffic.


--objects-edge-aggressive:: `--objects-edge-aggressive`::
Similar to `--objects-edge`, but it tries harder to find excluded Similar to `--objects-edge`, but it tries harder to find excluded
commits at the cost of increased time. This is used instead of commits at the cost of increased time. This is used instead of
`--objects-edge` to build ``thin'' packs for shallow repositories. `--objects-edge` to build ``thin'' packs for shallow repositories.


--indexed-objects:: `--indexed-objects`::
Pretend as if all trees and blobs used by the index are listed Pretend as if all trees and blobs used by the index are listed
on the command line. Note that you probably want to use on the command line. Note that you probably want to use
`--objects`, too. `--objects`, too.


--unpacked:: `--unpacked`::
Only useful with `--objects`; print the object IDs that are not Only useful with `--objects`; print the object IDs that are not
in packs. in packs.


--object-names:: `--object-names`::
Only useful with `--objects`; print the names of the object IDs Only useful with `--objects`; print the names of the object IDs
that are found. This is the default behavior. Note that the that are found. This is the default behavior. Note that the
"name" of each object is ambiguous, and mostly intended as a "name" of each object is ambiguous, and mostly intended as a
@ -964,52 +964,52 @@ ifdef::git-rev-list[]
to remove newlines; and if an object would appear multiple times to remove newlines; and if an object would appear multiple times
with different names, only one name is shown. with different names, only one name is shown.


--no-object-names:: `--no-object-names`::
Only useful with `--objects`; does not print the names of the object Only useful with `--objects`; does not print the names of the object
IDs that are found. This inverts `--object-names`. This flag allows IDs that are found. This inverts `--object-names`. This flag allows
the output to be more easily parsed by commands such as the output to be more easily parsed by commands such as
linkgit:git-cat-file[1]. linkgit:git-cat-file[1].


--filter=<filter-spec>:: `--filter=<filter-spec>`::
Only useful with one of the `--objects*`; omits objects (usually Only useful with one of the `--objects*`; omits objects (usually
blobs) from the list of printed objects. The '<filter-spec>' blobs) from the list of printed objects. The _<filter-spec>_
may be one of the following: may be one of the following:
+ +
The form '--filter=blob:none' omits all blobs. The form `--filter=blob:none` omits all blobs.
+ +
The form '--filter=blob:limit=<n>[kmg]' omits blobs of size at least n The form `--filter=blob:limit=<n>[kmg]` omits blobs of size at least _<n>_
bytes or units. n may be zero. The suffixes k, m, and g can be used bytes or units. _<n>_ may be zero. The suffixes `k`, `m`, and `g` can be used
to name units in KiB, MiB, or GiB. For example, 'blob:limit=1k' to name units in KiB, MiB, or GiB. For example, `blob:limit=1k`
is the same as 'blob:limit=1024'. is the same as 'blob:limit=1024'.
+ +
The form '--filter=object:type=(tag|commit|tree|blob)' omits all objects The form `--filter=object:type=(tag|commit|tree|blob)` omits all objects
which are not of the requested type. which are not of the requested type.
+ +
The form '--filter=sparse:oid=<blob-ish>' uses a sparse-checkout The form `--filter=sparse:oid=<blob-ish>` uses a sparse-checkout
specification contained in the blob (or blob-expression) '<blob-ish>' specification contained in the blob (or blob-expression) _<blob-ish>_
to omit blobs that would not be required for a sparse checkout on to omit blobs that would not be required for a sparse checkout on
the requested refs. the requested refs.
+ +
The form '--filter=tree:<depth>' omits all blobs and trees whose depth The form `--filter=tree:<depth>` omits all blobs and trees whose depth
from the root tree is >= <depth> (minimum depth if an object is located from the root tree is >= _<depth>_ (minimum depth if an object is located
at multiple depths in the commits traversed). <depth>=0 will not include at multiple depths in the commits traversed). _<depth>_=0 will not include
any trees or blobs unless included explicitly in the command-line (or any trees or blobs unless included explicitly in the command-line (or
standard input when --stdin is used). <depth>=1 will include only the standard input when `--stdin` is used). _<depth>_=1 will include only the
tree and blobs which are referenced directly by a commit reachable from tree and blobs which are referenced directly by a commit reachable from
<commit> or an explicitly-given object. <depth>=2 is like <depth>=1 _<commit>_ or an explicitly-given object. _<depth>_=2 is like <depth>=1
while also including trees and blobs one more level removed from an while also including trees and blobs one more level removed from an
explicitly-given commit or tree. explicitly-given commit or tree.
+ +
Note that the form '--filter=sparse:path=<path>' that wants to read Note that the form `--filter=sparse:path=<path>` that wants to read
from an arbitrary path on the filesystem has been dropped for security from an arbitrary path on the filesystem has been dropped for security
reasons. reasons.
+ +
Multiple '--filter=' flags can be specified to combine filters. Only Multiple `--filter=` flags can be specified to combine filters. Only
objects which are accepted by every filter are included. objects which are accepted by every filter are included.
+ +
The form '--filter=combine:<filter1>+<filter2>+...<filterN>' can also be The form `--filter=combine:<filter1>+<filter2>+...<filterN>` can also be
used to combined several filters, but this is harder than just repeating used to combined several filters, but this is harder than just repeating
the '--filter' flag and is usually not necessary. Filters are joined by the `--filter` flag and is usually not necessary. Filters are joined by
'{plus}' and individual filters are %-encoded (i.e. URL-encoded). '{plus}' and individual filters are %-encoded (i.e. URL-encoded).
Besides the '{plus}' and '%' characters, the following characters are Besides the '{plus}' and '%' characters, the following characters are
reserved and also must be encoded: `~!@#$^&*()[]{}\;",<>?`+&#39;&#96;+ reserved and also must be encoded: `~!@#$^&*()[]{}\;",<>?`+&#39;&#96;+
@ -1017,52 +1017,52 @@ as well as all characters with ASCII code &lt;= `0x20`, which includes
space and newline. space and newline.
+ +
Other arbitrary characters can also be encoded. For instance, Other arbitrary characters can also be encoded. For instance,
'combine:tree:3+blob:none' and 'combine:tree%3A3+blob%3Anone' are `combine:tree:3+blob:none` and `combine:tree%3A3+blob%3Anone` are
equivalent. equivalent.


--no-filter:: `--no-filter`::
Turn off any previous `--filter=` argument. Turn off any previous `--filter=` argument.


--filter-provided-objects:: `--filter-provided-objects`::
Filter the list of explicitly provided objects, which would otherwise Filter the list of explicitly provided objects, which would otherwise
always be printed even if they did not match any of the filters. Only always be printed even if they did not match any of the filters. Only
useful with `--filter=`. useful with `--filter=`.


--filter-print-omitted:: `--filter-print-omitted`::
Only useful with `--filter=`; prints a list of the objects omitted Only useful with `--filter=`; prints a list of the objects omitted
by the filter. Object IDs are prefixed with a ``~'' character. by the filter. Object IDs are prefixed with a ``~'' character.


--missing=<missing-action>:: `--missing=<missing-action>`::
A debug option to help with future "partial clone" development. A debug option to help with future "partial clone" development.
This option specifies how missing objects are handled. This option specifies how missing objects are handled.
+ +
The form '--missing=error' requests that rev-list stop with an error if The form `--missing=error` requests that rev-list stop with an error if
a missing object is encountered. This is the default action. a missing object is encountered. This is the default action.
+ +
The form '--missing=allow-any' will allow object traversal to continue The form `--missing=allow-any` will allow object traversal to continue
if a missing object is encountered. Missing objects will silently be if a missing object is encountered. Missing objects will silently be
omitted from the results. omitted from the results.
+ +
The form '--missing=allow-promisor' is like 'allow-any', but will only The form `--missing=allow-promisor` is like `allow-any`, but will only
allow object traversal to continue for EXPECTED promisor missing objects. allow object traversal to continue for EXPECTED promisor missing objects.
Unexpected missing objects will raise an error. Unexpected missing objects will raise an error.
+ +
The form '--missing=print' is like 'allow-any', but will also print a The form `--missing=print` is like `allow-any`, but will also print a
list of the missing objects. Object IDs are prefixed with a ``?'' character. list of the missing objects. Object IDs are prefixed with a ``?'' character.
+ +
The form '--missing=print-info' is like 'print', but will also print additional The form `--missing=print-info` is like `print`, but will also print additional
information about the missing object inferred from its containing object. The information about the missing object inferred from its containing object. The
information is all printed on the same line with the missing object ID in the information is all printed on the same line with the missing object ID in the
form: `?<oid> [<token>=<value>]...`. The `<token>=<value>` pairs containing form: `?<oid> [<token>=<value>]...`. The `<token>=<value>` pairs containing
additional information are separated from each other by a SP. The value is additional information are separated from each other by a _SP_. The value is
encoded in a token specific fashion, but SP or LF contained in value are always encoded in a token specific fashion, but _SP_ or _LF_ contained in value are always
expected to be represented in such a way that the resulting encoded value does expected to be represented in such a way that the resulting encoded value does
not have either of these two problematic bytes. Each `<token>=<value>` may be not have either of these two problematic bytes. Each `<token>=<value>` may be
one of the following: one of the following:
+ +
-- --
* The `path=<path>` shows the path of the missing object inferred from a * The `path=<path>` shows the path of the missing object inferred from a
containing object. A path containing SP or special characters is enclosed in containing object. A path containing _SP_ or special characters is enclosed in
double-quotes in the C style as needed. double-quotes in the C style as needed.
+ +
* The `type=<type>` shows the type of the missing object inferred from a * The `type=<type>` shows the type of the missing object inferred from a
@ -1073,7 +1073,7 @@ If some tips passed to the traversal are missing, they will be
considered as missing too, and the traversal will ignore them. In case considered as missing too, and the traversal will ignore them. In case
we cannot get their Object ID though, an error will be raised. we cannot get their Object ID though, an error will be raised.


--exclude-promisor-objects:: `--exclude-promisor-objects`::
(For internal use only.) Prefilter object traversal at (For internal use only.) Prefilter object traversal at
promisor boundary. This is used with partial clone. This is promisor boundary. This is used with partial clone. This is
stronger than `--missing=allow-promisor` because it limits the stronger than `--missing=allow-promisor` because it limits the
@ -1081,7 +1081,7 @@ we cannot get their Object ID though, an error will be raised.
objects. objects.
endif::git-rev-list[] endif::git-rev-list[]


--no-walk[=(sorted|unsorted)]:: `--no-walk[=(sorted|unsorted)]`::
Only show the given commits, but do not traverse their ancestors. Only show the given commits, but do not traverse their ancestors.
This has no effect if a range is specified. If the argument This has no effect if a range is specified. If the argument
`unsorted` is given, the commits are shown in the order they were `unsorted` is given, the commits are shown in the order they were
@ -1090,7 +1090,7 @@ endif::git-rev-list[]
by commit time. by commit time.
Cannot be combined with `--graph`. Cannot be combined with `--graph`.


--do-walk:: `--do-walk`::
Overrides a previous `--no-walk`. Overrides a previous `--no-walk`.
endif::git-shortlog[] endif::git-shortlog[]


@ -1100,16 +1100,21 @@ Commit Formatting


ifdef::git-rev-list[] ifdef::git-rev-list[]
Using these options, linkgit:git-rev-list[1] will act similar to the Using these options, linkgit:git-rev-list[1] will act similar to the
more specialized family of commit log tools: linkgit:git-log[1], more specialized family of commit log tools:
linkgit:git-show[1], and linkgit:git-whatchanged[1] ifndef::with-breaking-changes[]
linkgit:git-log[1], linkgit:git-show[1], and linkgit:git-whatchanged[1].
endif::with-breaking-changes[]
ifdef::with-breaking-changes[]
linkgit:git-log[1] and linkgit:git-show[1].
endif::with-breaking-changes[]
endif::git-rev-list[] endif::git-rev-list[]


include::pretty-options.adoc[] include::pretty-options.adoc[]


--relative-date:: `--relative-date`::
Synonym for `--date=relative`. Synonym for `--date=relative`.


--date=<format>:: `--date=<format>`::
Only takes effect for dates shown in human-readable format, such Only takes effect for dates shown in human-readable format, such
as when using `--pretty`. `log.date` config variable sets a default as when using `--pretty`. `log.date` config variable sets a default
value for the log command's `--date` option. By default, dates value for the log command's `--date` option. By default, dates
@ -1159,12 +1164,12 @@ omitted.
1970). As with `--raw`, this is always in UTC and therefore `-local` 1970). As with `--raw`, this is always in UTC and therefore `-local`
has no effect. has no effect.


`--date=format:...` feeds the format `...` to your system `strftime`, `--date=format:<format>` feeds the _<format>_ to your system `strftime`,
except for %s, %z, and %Z, which are handled internally. except for `%s`, `%z`, and `%Z`, which are handled internally.
Use `--date=format:%c` to show the date in your system locale's Use `--date=format:%c` to show the date in your system locale's
preferred format. See the `strftime` manual for a complete list of preferred format. See the `strftime`(3) manual for a complete list of
format placeholders. When using `-local`, the correct syntax is format placeholders. When using `-local`, the correct syntax is
`--date=format-local:...`. `--date=format-local:<format>`.


`--date=default` is the default format, and is based on ctime(3) `--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, output. It shows a single line with three-letter day of the week,
@ -1174,33 +1179,33 @@ the local time zone is used, e.g. `Thu Jan 1 00:00:00 1970 +0000`.
-- --


ifdef::git-rev-list[] ifdef::git-rev-list[]
--header:: `--header`::
Print the contents of the commit in raw-format; each record is Print the contents of the commit in raw-format; each record is
separated with a NUL character. separated with a NUL character.


--no-commit-header:: `--no-commit-header`::
Suppress the header line containing "commit" and the object ID printed before Suppress the header line containing "commit" and the object ID printed before
the specified format. This has no effect on the built-in formats; only custom the specified format. This has no effect on the built-in formats; only custom
formats are affected. formats are affected.


--commit-header:: `--commit-header`::
Overrides a previous `--no-commit-header`. Overrides a previous `--no-commit-header`.
endif::git-rev-list[] endif::git-rev-list[]


--parents:: `--parents`::
Print also the parents of the commit (in the form "commit parent..."). Print also the parents of the commit (in the form "commit parent...").
Also enables parent rewriting, see 'History Simplification' above. Also enables parent rewriting, see 'History Simplification' above.


--children:: `--children`::
Print also the children of the commit (in the form "commit child..."). Print also the children of the commit (in the form "commit child...").
Also enables parent rewriting, see 'History Simplification' above. Also enables parent rewriting, see 'History Simplification' above.


ifdef::git-rev-list[] ifdef::git-rev-list[]
--timestamp:: `--timestamp`::
Print the raw commit timestamp. Print the raw commit timestamp.
endif::git-rev-list[] endif::git-rev-list[]


--left-right:: `--left-right`::
Mark which side of a symmetric difference a commit is reachable from. Mark which side of a symmetric difference a commit is reachable from.
Commits from the left side are prefixed with `<` and those from Commits from the left side are prefixed with `<` and those from
the right with `>`. If combined with `--boundary`, those the right with `>`. If combined with `--boundary`, those
@ -1229,7 +1234,7 @@ you would get an output like this:
-xxxxxxx... 1st on a -xxxxxxx... 1st on a
----------------------------------------------------------------------- -----------------------------------------------------------------------


--graph:: `--graph`::
Draw a text-based graphical representation of the commit history Draw a text-based graphical representation of the commit history
on the left hand side of the output. This may cause extra lines on the left hand side of the output. This may cause extra lines
to be printed in between commits, in order for the graph history to be printed in between commits, in order for the graph history
@ -1241,15 +1246,15 @@ This enables parent rewriting, see 'History Simplification' above.
This implies the `--topo-order` option by default, but the This implies the `--topo-order` option by default, but the
`--date-order` option may also be specified. `--date-order` option may also be specified.


--show-linear-break[=<barrier>]:: `--show-linear-break[=<barrier>]`::
When --graph is not used, all history branches are flattened When `--graph` is not used, all history branches are flattened
which can make it hard to see that the two consecutive commits which can make it hard to see that the two consecutive commits
do not belong to a linear branch. This option puts a barrier do not belong to a linear branch. This option puts a barrier
in between them in that case. If `<barrier>` is specified, it in between them in that case. If _<barrier>_ is specified, it
is the string that will be shown instead of the default one. is the string that will be shown instead of the default one.


ifdef::git-rev-list[] ifdef::git-rev-list[]
--count:: `--count`::
Print a number stating how many commits would have been Print a number stating how many commits would have been
listed, and suppress all other output. When used together listed, and suppress all other output. When used together
with `--left-right`, instead print the counts for left and with `--left-right`, instead print the counts for left and

View File

@ -56,6 +56,14 @@ better off using the revision walk API instead.
the revision walk so that the walk emits commits marked with the the revision walk so that the walk emits commits marked with the
`UNINTERESTING` flag. `UNINTERESTING` flag.


`edge_aggressive`::
For performance reasons, usually only the boundary commits are
explored to find UNINTERESTING objects. However, in the case of
shallow clones it can be helpful to mark all trees and blobs
reachable from UNINTERESTING tip commits as UNINTERESTING. This
matches the behavior of `--objects-edge-aggressive` in the
revision API.

`pl`:: `pl`::
This pattern list pointer allows focusing the path-walk search to This pattern list pointer allows focusing the path-walk search to
a set of patterns, only emitting paths that match the given a set of patterns, only emitting paths that match the given
@ -69,4 +77,5 @@ Examples


See example usages in: See example usages in:
`t/helper/test-path-walk.c`, `t/helper/test-path-walk.c`,
`builtin/pack-objects.c`,
`builtin/backfill.c` `builtin/backfill.c`

View File

@ -32,7 +32,10 @@ that generally have somebody running test pipelines against regularly:
- OpenBSD - OpenBSD


The platforms which must be supported by the tool should be aligned with our The platforms which must be supported by the tool should be aligned with our
[platform support policy](platform-support.txt). platform support policy (see platform-support.adoc).
// once we lose AsciiDoc compatibility, we can start writing the above as:
// xref:platform-support.adoc#platform-support-policy[platform support policy]
// or something like that, but until then....


=== Auto-detection of supported features === Auto-detection of supported features



View File

@ -440,7 +440,7 @@ understanding these differences can be beneficial.
* blame (only matters when one or more -C flags are passed) * blame (only matters when one or more -C flags are passed)
* and annotate * and annotate
* log * log
* whatchanged * whatchanged (may not exist anymore)
* ls-files * ls-files
* diff-index * diff-index
* diff-tree * diff-tree

View File

@ -4240,7 +4240,7 @@ command `git`. The source side of a builtin is
- an entry in `BUILTIN_OBJECTS` in the `Makefile`. - an entry in `BUILTIN_OBJECTS` in the `Makefile`.


Sometimes, more than one builtin is contained in one source file. For Sometimes, more than one builtin is contained in one source file. For
example, `cmd_whatchanged()` and `cmd_log()` both reside in `builtin/log.c`, example, `cmd_show()` and `cmd_log()` both reside in `builtin/log.c`,
since they share quite a bit of code. In that case, the commands which are since they share quite a bit of code. In that case, the commands which are
_not_ named like the `.c` file in which they live have to be listed in _not_ named like the `.c` file in which they live have to be listed in
`BUILT_INS` in the `Makefile`. `BUILT_INS` in the `Makefile`.
@ -4301,11 +4301,11 @@ Now, for the meat:


----------------------------------------------------------------------------- -----------------------------------------------------------------------------
case 0: case 0:
buf = read_object_with_reference(sha1, argv[1], &size, NULL); buf = odb_read_object_peeled(r->objects, sha1, argv[1], &size, NULL);
----------------------------------------------------------------------------- -----------------------------------------------------------------------------


This is how you read a blob (actually, not only a blob, but any type of This is how you read a blob (actually, not only a blob, but any type of
object). To know how the function `read_object_with_reference()` actually object). To know how the function `odb_read_object_peeled()` actually
works, find the source code for it (something like `git grep works, find the source code for it (something like `git grep
read_object_with | grep ":[a-z]"` in the Git repository), and read read_object_with | grep ":[a-z]"` in the Git repository), and read
the source. the source.

View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh


DEF_VER=v2.50.0-rc1 DEF_VER=v2.50.GIT


LF=' LF='
' '
@ -82,7 +82,7 @@ read GIT_MAJOR_VERSION GIT_MINOR_VERSION GIT_MICRO_VERSION GIT_PATCH_LEVEL trail
$(echo "$GIT_VERSION" 0 0 0 0 | tr '.a-zA-Z-' ' ') $(echo "$GIT_VERSION" 0 0 0 0 | tr '.a-zA-Z-' ' ')
EOF EOF


REPLACED=$(printf "%s" "$INPUT" | sed -e "s|@GIT_VERSION@|$GIT_VERSION|" \ REPLACED=$(printf "%s\n" "$INPUT" | sed -e "s|@GIT_VERSION@|$GIT_VERSION|" \
-e "s|@GIT_MAJOR_VERSION@|$GIT_MAJOR_VERSION|" \ -e "s|@GIT_MAJOR_VERSION@|$GIT_MAJOR_VERSION|" \
-e "s|@GIT_MINOR_VERSION@|$GIT_MINOR_VERSION|" \ -e "s|@GIT_MINOR_VERSION@|$GIT_MINOR_VERSION|" \
-e "s|@GIT_MICRO_VERSION@|$GIT_MICRO_VERSION|" \ -e "s|@GIT_MICRO_VERSION@|$GIT_MICRO_VERSION|" \

View File

@ -114,8 +114,6 @@ include shared.mak
# #
# Define NO_INTPTR_T if you don't have intptr_t or uintptr_t. # Define NO_INTPTR_T if you don't have intptr_t or uintptr_t.
# #
# Define NO_UINTMAX_T if you don't have uintmax_t.
#
# Define NEEDS_SOCKET if linking with libc is not enough (SunOS, # Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
# Patrick Mauritz). # Patrick Mauritz).
# #
@ -1085,8 +1083,8 @@ LIB_OBJS += notes.o
LIB_OBJS += object-file-convert.o LIB_OBJS += object-file-convert.o
LIB_OBJS += object-file.o LIB_OBJS += object-file.o
LIB_OBJS += object-name.o LIB_OBJS += object-name.o
LIB_OBJS += object-store.o
LIB_OBJS += object.o LIB_OBJS += object.o
LIB_OBJS += odb.o
LIB_OBJS += oid-array.o LIB_OBJS += oid-array.o
LIB_OBJS += oidmap.o LIB_OBJS += oidmap.o
LIB_OBJS += oidset.o LIB_OBJS += oidset.o
@ -1367,6 +1365,7 @@ CLAR_TEST_SUITES += u-prio-queue
CLAR_TEST_SUITES += u-reftable-tree CLAR_TEST_SUITES += u-reftable-tree
CLAR_TEST_SUITES += u-strbuf CLAR_TEST_SUITES += u-strbuf
CLAR_TEST_SUITES += u-strcmp-offset CLAR_TEST_SUITES += u-strcmp-offset
CLAR_TEST_SUITES += u-string-list
CLAR_TEST_SUITES += u-strvec CLAR_TEST_SUITES += u-strvec
CLAR_TEST_SUITES += u-trailer CLAR_TEST_SUITES += u-trailer
CLAR_TEST_SUITES += u-urlmatch-normalization CLAR_TEST_SUITES += u-urlmatch-normalization
@ -1918,9 +1917,6 @@ endif
ifdef NO_INTPTR_T ifdef NO_INTPTR_T
COMPAT_CFLAGS += -DNO_INTPTR_T COMPAT_CFLAGS += -DNO_INTPTR_T
endif endif
ifdef NO_UINTMAX_T
BASIC_CFLAGS += -Duintmax_t=uint32_t
endif
ifdef NO_SOCKADDR_STORAGE ifdef NO_SOCKADDR_STORAGE
ifdef NO_IPV6 ifdef NO_IPV6
BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in
@ -3473,11 +3469,14 @@ endif
coccicheck-test: $(COCCI_TEST_RES_GEN) coccicheck-test: $(COCCI_TEST_RES_GEN)


coccicheck: coccicheck-test coccicheck: coccicheck-test

ifdef SPATCH_CONCAT_COCCI ifdef SPATCH_CONCAT_COCCI
coccicheck: contrib/coccinelle/ALL.cocci.patch COCCICHECK_PATCH_MUST_BE_EMPTY_FILES = contrib/coccinelle/ALL.cocci.patch
else else
coccicheck: $(COCCICHECK_PATCHES_INTREE) COCCICHECK_PATCH_MUST_BE_EMPTY_FILES = $(COCCICHECK_PATCHES_INTREE)
endif endif
coccicheck: $(COCCICHECK_PATCH_MUST_BE_EMPTY_FILES)
! grep -q ^ $(COCCICHECK_PATCH_MUST_BE_EMPTY_FILES) /dev/null


# See contrib/coccinelle/README # See contrib/coccinelle/README
coccicheck-pending: coccicheck-test coccicheck-pending: coccicheck-test

View File

@ -1 +1 @@
Documentation/RelNotes/2.50.0.adoc Documentation/RelNotes/2.51.0.adoc

18
apply.c
View File

@ -14,7 +14,7 @@
#include "abspath.h" #include "abspath.h"
#include "base85.h" #include "base85.h"
#include "config.h" #include "config.h"
#include "object-store.h" #include "odb.h"
#include "delta.h" #include "delta.h"
#include "diff.h" #include "diff.h"
#include "dir.h" #include "dir.h"
@ -3204,14 +3204,14 @@ static int apply_binary(struct apply_state *state,
return 0; /* deletion patch */ return 0; /* deletion patch */
} }


if (has_object(the_repository, &oid, 0)) { if (odb_has_object(the_repository->objects, &oid, 0)) {
/* We already have the postimage */ /* We already have the postimage */
enum object_type type; enum object_type type;
unsigned long size; unsigned long size;
char *result; char *result;


result = repo_read_object_file(the_repository, &oid, &type, result = odb_read_object(the_repository->objects, &oid,
&size); &type, &size);
if (!result) if (!result)
return error(_("the necessary postimage %s for " return error(_("the necessary postimage %s for "
"'%s' cannot be read"), "'%s' cannot be read"),
@ -3273,8 +3273,8 @@ static int read_blob_object(struct strbuf *buf, const struct object_id *oid, uns
unsigned long sz; unsigned long sz;
char *result; char *result;


result = repo_read_object_file(the_repository, oid, &type, result = odb_read_object(the_repository->objects, oid,
&sz); &type, &sz);
if (!result) if (!result)
return -1; return -1;
/* XXX read_sha1_file NUL-terminates */ /* XXX read_sha1_file NUL-terminates */
@ -3503,7 +3503,7 @@ static int resolve_to(struct image *image, const struct object_id *result_id)


image_clear(image); image_clear(image);


data = repo_read_object_file(the_repository, result_id, &type, &size); data = odb_read_object(the_repository->objects, result_id, &type, &size);
if (!data || type != OBJ_BLOB) if (!data || type != OBJ_BLOB)
die("unable to read blob object %s", oid_to_hex(result_id)); die("unable to read blob object %s", oid_to_hex(result_id));
strbuf_attach(&image->buf, data, size, size + 1); strbuf_attach(&image->buf, data, size, size + 1);
@ -4565,7 +4565,7 @@ static int create_file(struct apply_state *state, struct patch *patch)


if (patch->conflicted_threeway) if (patch->conflicted_threeway)
return add_conflicted_stages_file(state, patch); return add_conflicted_stages_file(state, patch);
else if (state->update_index) else if (state->check_index || (state->ita_only && patch->is_new > 0))
return add_index_file(state, path, mode, buf, size); return add_index_file(state, path, mode, buf, size);
return 0; return 0;
} }
@ -4833,7 +4833,7 @@ static int apply_patch(struct apply_state *state,
LOCK_DIE_ON_ERROR); LOCK_DIE_ON_ERROR);
} }


if (state->check_index && read_apply_cache(state) < 0) { if ((state->check_index || state->update_index) && read_apply_cache(state) < 0) {
error(_("unable to read index file")); error(_("unable to read index file"));
res = -128; res = -128;
goto end; goto end;

View File

@ -11,7 +11,7 @@
#include "hex.h" #include "hex.h"
#include "tar.h" #include "tar.h"
#include "archive.h" #include "archive.h"
#include "object-store.h" #include "odb.h"
#include "strbuf.h" #include "strbuf.h"
#include "streaming.h" #include "streaming.h"
#include "run-command.h" #include "run-command.h"

View File

@ -12,7 +12,7 @@
#include "hex.h" #include "hex.h"
#include "streaming.h" #include "streaming.h"
#include "utf8.h" #include "utf8.h"
#include "object-store.h" #include "odb.h"
#include "strbuf.h" #include "strbuf.h"
#include "userdiff.h" #include "userdiff.h"
#include "write-or-die.h" #include "write-or-die.h"

View File

@ -14,7 +14,7 @@
#include "pretty.h" #include "pretty.h"
#include "setup.h" #include "setup.h"
#include "refs.h" #include "refs.h"
#include "object-store.h" #include "odb.h"
#include "commit.h" #include "commit.h"
#include "tree.h" #include "tree.h"
#include "tree-walk.h" #include "tree-walk.h"
@ -98,7 +98,7 @@ static void *object_file_to_archive(const struct archiver_args *args,
(args->tree ? &args->tree->object.oid : NULL), oid); (args->tree ? &args->tree->object.oid : NULL), oid);


path += args->baselen; path += args->baselen;
buffer = repo_read_object_file(the_repository, oid, type, sizep); buffer = odb_read_object(the_repository->objects, oid, type, sizep);
if (buffer && S_ISREG(mode)) { if (buffer && S_ISREG(mode)) {
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;
size_t size = 0; size_t size = 0;
@ -215,7 +215,7 @@ static int write_archive_entry(const struct object_id *oid, const char *base,


/* Stream it? */ /* Stream it? */
if (S_ISREG(mode) && !args->convert && if (S_ISREG(mode) && !args->convert &&
oid_object_info(args->repo, oid, &size) == OBJ_BLOB && odb_read_object_info(args->repo->objects, oid, &size) == OBJ_BLOB &&
size > repo_settings_get_big_file_threshold(the_repository)) size > repo_settings_get_big_file_threshold(the_repository))
return write_entry(args, oid, path.buf, path.len, mode, NULL, size); return write_entry(args, oid, path.buf, path.len, mode, NULL, size);



4
attr.c
View File

@ -22,7 +22,7 @@
#include "read-cache-ll.h" #include "read-cache-ll.h"
#include "refs.h" #include "refs.h"
#include "revision.h" #include "revision.h"
#include "object-store.h" #include "odb.h"
#include "setup.h" #include "setup.h"
#include "thread-utils.h" #include "thread-utils.h"
#include "tree-walk.h" #include "tree-walk.h"
@ -779,7 +779,7 @@ static struct attr_stack *read_attr_from_blob(struct index_state *istate,
if (get_tree_entry(istate->repo, tree_oid, path, &oid, &mode)) if (get_tree_entry(istate->repo, tree_oid, path, &oid, &mode))
return NULL; return NULL;


buf = repo_read_object_file(istate->repo, &oid, &type, &sz); buf = odb_read_object(istate->repo->objects, &oid, &type, &sz);
if (!buf || type != OBJ_BLOB) { if (!buf || type != OBJ_BLOB) {
free(buf); free(buf);
return NULL; return NULL;

View File

@ -20,7 +20,7 @@
#include "commit-slab.h" #include "commit-slab.h"
#include "commit-reach.h" #include "commit-reach.h"
#include "object-name.h" #include "object-name.h"
#include "object-store.h" #include "odb.h"
#include "path.h" #include "path.h"
#include "dir.h" #include "dir.h"


@ -155,9 +155,9 @@ static void show_list(const char *debug, int counted, int nr,
unsigned commit_flags = commit->object.flags; unsigned commit_flags = commit->object.flags;
enum object_type type; enum object_type type;
unsigned long size; unsigned long size;
char *buf = repo_read_object_file(the_repository, char *buf = odb_read_object(the_repository->objects,
&commit->object.oid, &type, &commit->object.oid, &type,
&size); &size);
const char *subject_start; const char *subject_start;
int subject_len; int subject_len;



22
blame.c
View File

@ -3,7 +3,7 @@


#include "git-compat-util.h" #include "git-compat-util.h"
#include "refs.h" #include "refs.h"
#include "object-store.h" #include "odb.h"
#include "cache-tree.h" #include "cache-tree.h"
#include "mergesort.h" #include "mergesort.h"
#include "commit.h" #include "commit.h"
@ -116,7 +116,7 @@ static void verify_working_tree_path(struct repository *r,
unsigned short mode; unsigned short mode;


if (!get_tree_entry(r, commit_oid, path, &blob_oid, &mode) && if (!get_tree_entry(r, commit_oid, path, &blob_oid, &mode) &&
oid_object_info(r, &blob_oid, NULL) == OBJ_BLOB) odb_read_object_info(r->objects, &blob_oid, NULL) == OBJ_BLOB)
return; return;
} }


@ -277,7 +277,8 @@ static struct commit *fake_working_tree_commit(struct repository *r,
convert_to_git(r->index, path, buf.buf, buf.len, &buf, 0); convert_to_git(r->index, path, buf.buf, buf.len, &buf, 0);
origin->file.ptr = buf.buf; origin->file.ptr = buf.buf;
origin->file.size = buf.len; origin->file.size = buf.len;
pretend_object_file(the_repository, buf.buf, buf.len, OBJ_BLOB, &origin->blob_oid); odb_pretend_object(the_repository->objects, buf.buf, buf.len,
OBJ_BLOB, &origin->blob_oid);


/* /*
* Read the current index, replace the path entry with * Read the current index, replace the path entry with
@ -1041,9 +1042,9 @@ static void fill_origin_blob(struct diff_options *opt,
&o->blob_oid, 1, &file->ptr, &file_size)) &o->blob_oid, 1, &file->ptr, &file_size))
; ;
else else
file->ptr = repo_read_object_file(the_repository, file->ptr = odb_read_object(the_repository->objects,
&o->blob_oid, &type, &o->blob_oid, &type,
&file_size); &file_size);
file->size = file_size; file->size = file_size;


if (!file->ptr) if (!file->ptr)
@ -1245,7 +1246,7 @@ static int fill_blob_sha1_and_mode(struct repository *r,
return 0; return 0;
if (get_tree_entry(r, &origin->commit->object.oid, origin->path, &origin->blob_oid, &origin->mode)) if (get_tree_entry(r, &origin->commit->object.oid, origin->path, &origin->blob_oid, &origin->mode))
goto error_out; goto error_out;
if (oid_object_info(r, &origin->blob_oid, NULL) != OBJ_BLOB) if (odb_read_object_info(r->objects, &origin->blob_oid, NULL) != OBJ_BLOB)
goto error_out; goto error_out;
return 0; return 0;
error_out: error_out:
@ -2869,10 +2870,9 @@ void setup_scoreboard(struct blame_scoreboard *sb,
&sb->final_buf_size)) &sb->final_buf_size))
; ;
else else
sb->final_buf = repo_read_object_file(the_repository, sb->final_buf = odb_read_object(the_repository->objects,
&o->blob_oid, &o->blob_oid, &type,
&type, &sb->final_buf_size);
&sb->final_buf_size);


if (!sb->final_buf) if (!sb->final_buf)
die(_("cannot read blob %s for path %s"), die(_("cannot read blob %s for path %s"),

View File

@ -230,7 +230,7 @@ static int inherit_tracking(struct tracking *tracking, const char *orig_ref)
return -1; return -1;
} }


if (branch->merge_nr < 1 || !branch->merge_name || !branch->merge_name[0]) { if (branch->merge_nr < 1 || !branch->merge || !branch->merge[0] || !branch->merge[0]->src) {
warning(_("asked to inherit tracking from '%s', but no merge configuration is set"), warning(_("asked to inherit tracking from '%s', but no merge configuration is set"),
bare_ref); bare_ref);
return -1; return -1;
@ -238,7 +238,7 @@ static int inherit_tracking(struct tracking *tracking, const char *orig_ref)


tracking->remote = branch->remote_name; tracking->remote = branch->remote_name;
for (i = 0; i < branch->merge_nr; i++) for (i = 0; i < branch->merge_nr; i++)
string_list_append(tracking->srcs, branch->merge_name[i]); string_list_append(tracking->srcs, branch->merge[i]->src);
return 0; return 0;
} }



View File

@ -1000,7 +1000,7 @@ static void am_setup(struct am_state *state, enum patch_format patch_format,


if (!patch_format) { if (!patch_format) {
fprintf_ln(stderr, _("Patch format detection failed.")); fprintf_ln(stderr, _("Patch format detection failed."));
exit(128); die(NULL);
} }


if (mkdir(state->dir, 0777) < 0 && errno != EEXIST) if (mkdir(state->dir, 0777) < 0 && errno != EEXIST)
@ -1178,7 +1178,7 @@ static void NORETURN die_user_resolve(const struct am_state *state)
strbuf_release(&sb); strbuf_release(&sb);
} }


exit(128); die(NULL);
} }


/** /**
@ -2406,6 +2406,7 @@ int cmd_am(int argc,
.type = OPTION_CALLBACK, .type = OPTION_CALLBACK,
.long_name = "show-current-patch", .long_name = "show-current-patch",
.value = &resume_mode, .value = &resume_mode,
.precision = sizeof(resume_mode),
.argh = "(diff|raw)", .argh = "(diff|raw)",
.help = N_("show the patch being applied"), .help = N_("show the patch being applied"),
.flags = PARSE_OPT_CMDMODE | PARSE_OPT_OPTARG | PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP, .flags = PARSE_OPT_CMDMODE | PARSE_OPT_OPTARG | PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,

View File

@ -29,7 +29,7 @@ int cmd_apply(int argc,
* cf. https://lore.kernel.org/git/xmqqcypfcmn4.fsf@gitster.g/ * cf. https://lore.kernel.org/git/xmqqcypfcmn4.fsf@gitster.g/
*/ */
if (!the_hash_algo) if (!the_hash_algo)
repo_set_hash_algo(the_repository, GIT_HASH_SHA1); repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT);


argc = apply_parse_options(argc, argv, argc = apply_parse_options(argc, argv,
&state, &force_apply, &options, &state, &force_apply, &options,

View File

@ -13,7 +13,7 @@
#include "tree.h" #include "tree.h"
#include "tree-walk.h" #include "tree-walk.h"
#include "object.h" #include "object.h"
#include "object-store.h" #include "odb.h"
#include "oid-array.h" #include "oid-array.h"
#include "oidset.h" #include "oidset.h"
#include "promisor-remote.h" #include "promisor-remote.h"
@ -67,8 +67,8 @@ static int fill_missing_blobs(const char *path UNUSED,
return 0; return 0;


for (size_t i = 0; i < list->nr; i++) { for (size_t i = 0; i < list->nr; i++) {
if (!has_object(ctx->repo, &list->oid[i], if (!odb_has_object(ctx->repo->objects, &list->oid[i],
OBJECT_INFO_FOR_PREFETCH)) OBJECT_INFO_FOR_PREFETCH))
oid_array_append(&ctx->current_batch, &list->oid[i]); oid_array_append(&ctx->current_batch, &list->oid[i]);
} }



View File

@ -28,7 +28,7 @@
#include "line-log.h" #include "line-log.h"
#include "progress.h" #include "progress.h"
#include "object-name.h" #include "object-name.h"
#include "object-store.h" #include "odb.h"
#include "pager.h" #include "pager.h"
#include "blame.h" #include "blame.h"
#include "refs.h" #include "refs.h"
@ -837,7 +837,7 @@ static int is_a_rev(const char *name)


if (repo_get_oid(the_repository, name, &oid)) if (repo_get_oid(the_repository, name, &oid))
return 0; return 0;
return OBJ_NONE < oid_object_info(the_repository, &oid, NULL); return OBJ_NONE < odb_read_object_info(the_repository->objects, &oid, NULL);
} }


static int peel_to_commit_oid(struct object_id *oid_ret, void *cbdata) static int peel_to_commit_oid(struct object_id *oid_ret, void *cbdata)
@ -848,7 +848,7 @@ static int peel_to_commit_oid(struct object_id *oid_ret, void *cbdata)
oidcpy(&oid, oid_ret); oidcpy(&oid, oid_ret);
while (1) { while (1) {
struct object *obj; struct object *obj;
int kind = oid_object_info(r, &oid, NULL); int kind = odb_read_object_info(r->objects, &oid, NULL);
if (kind == OBJ_COMMIT) { if (kind == OBJ_COMMIT) {
oidcpy(oid_ret, &oid); oidcpy(oid_ret, &oid);
return 0; return 0;

View File

@ -24,7 +24,7 @@
#include "pack-bitmap.h" #include "pack-bitmap.h"
#include "object-file.h" #include "object-file.h"
#include "object-name.h" #include "object-name.h"
#include "object-store.h" #include "odb.h"
#include "replace-object.h" #include "replace-object.h"
#include "promisor-remote.h" #include "promisor-remote.h"
#include "mailmap.h" #include "mailmap.h"
@ -74,7 +74,7 @@ static int filter_object(const char *path, unsigned mode,
{ {
enum object_type type; enum object_type type;


*buf = repo_read_object_file(the_repository, oid, &type, size); *buf = odb_read_object(the_repository->objects, oid, &type, size);
if (!*buf) if (!*buf)
return error(_("cannot read object %s '%s'"), return error(_("cannot read object %s '%s'"),
oid_to_hex(oid), path); oid_to_hex(oid), path);
@ -132,7 +132,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
switch (opt) { switch (opt) {
case 't': case 't':
oi.typep = &type; oi.typep = &type;
if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0) if (odb_read_object_info_extended(the_repository->objects, &oid, &oi, flags) < 0)
die("git cat-file: could not get object info"); die("git cat-file: could not get object info");
printf("%s\n", type_name(type)); printf("%s\n", type_name(type));
ret = 0; ret = 0;
@ -146,7 +146,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
oi.contentp = (void**)&buf; oi.contentp = (void**)&buf;
} }


if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0) if (odb_read_object_info_extended(the_repository->objects, &oid, &oi, flags) < 0)
die("git cat-file: could not get object info"); die("git cat-file: could not get object info");


if (use_mailmap && (type == OBJ_COMMIT || type == OBJ_TAG)) { if (use_mailmap && (type == OBJ_COMMIT || type == OBJ_TAG)) {
@ -160,8 +160,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
goto cleanup; goto cleanup;


case 'e': case 'e':
ret = !has_object(the_repository, &oid, ret = !odb_has_object(the_repository->objects, &oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR); HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR);
goto cleanup; goto cleanup;


case 'w': case 'w':
@ -180,7 +180,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
/* else fallthrough */ /* else fallthrough */


case 'p': case 'p':
type = oid_object_info(the_repository, &oid, NULL); type = odb_read_object_info(the_repository->objects, &oid, NULL);
if (type < 0) if (type < 0)
die("Not a valid object name %s", obj_name); die("Not a valid object name %s", obj_name);


@ -197,8 +197,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
ret = stream_blob(&oid); ret = stream_blob(&oid);
goto cleanup; goto cleanup;
} }
buf = repo_read_object_file(the_repository, &oid, &type, buf = odb_read_object(the_repository->objects, &oid,
&size); &type, &size);
if (!buf) if (!buf)
die("Cannot read object %s", obj_name); die("Cannot read object %s", obj_name);


@ -217,11 +217,10 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)


if (exp_type_id == OBJ_BLOB) { if (exp_type_id == OBJ_BLOB) {
struct object_id blob_oid; struct object_id blob_oid;
if (oid_object_info(the_repository, &oid, NULL) == OBJ_TAG) { if (odb_read_object_info(the_repository->objects,
char *buffer = repo_read_object_file(the_repository, &oid, NULL) == OBJ_TAG) {
&oid, char *buffer = odb_read_object(the_repository->objects,
&type, &oid, &type, &size);
&size);
const char *target; const char *target;


if (!buffer) if (!buffer)
@ -235,7 +234,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
} else } else
oidcpy(&blob_oid, &oid); oidcpy(&blob_oid, &oid);


if (oid_object_info(the_repository, &blob_oid, NULL) == OBJ_BLOB) { if (odb_read_object_info(the_repository->objects,
&blob_oid, NULL) == OBJ_BLOB) {
ret = stream_blob(&blob_oid); ret = stream_blob(&blob_oid);
goto cleanup; goto cleanup;
} }
@ -246,8 +246,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
* fall-back to the usual case. * fall-back to the usual case.
*/ */
} }
buf = read_object_with_reference(the_repository, &oid, buf = odb_read_object_peeled(the_repository->objects, &oid,
exp_type_id, &size, NULL); exp_type_id, &size, NULL);


if (use_mailmap) { if (use_mailmap) {
size_t s = size; size_t s = size;
@ -275,6 +275,7 @@ struct expand_data {
struct object_id oid; struct object_id oid;
enum object_type type; enum object_type type;
unsigned long size; unsigned long size;
unsigned short mode;
off_t disk_size; off_t disk_size;
const char *rest; const char *rest;
struct object_id delta_base_oid; struct object_id delta_base_oid;
@ -294,7 +295,7 @@ struct expand_data {


/* /*
* After a mark_query run, this object_info is set up to be * After a mark_query run, this object_info is set up to be
* passed to oid_object_info_extended. It will point to the data * passed to odb_read_object_info_extended. It will point to the data
* elements above, so you can retrieve the response from there. * elements above, so you can retrieve the response from there.
*/ */
struct object_info info; struct object_info info;
@ -306,6 +307,7 @@ struct expand_data {
*/ */
unsigned skip_object_info : 1; unsigned skip_object_info : 1;
}; };
#define EXPAND_DATA_INIT { .mode = S_IFINVALID }


static int is_atom(const char *atom, const char *s, int slen) static int is_atom(const char *atom, const char *s, int slen)
{ {
@ -345,6 +347,9 @@ static int expand_atom(struct strbuf *sb, const char *atom, int len,
else else
strbuf_addstr(sb, strbuf_addstr(sb,
oid_to_hex(&data->delta_base_oid)); oid_to_hex(&data->delta_base_oid));
} else if (is_atom("objectmode", atom, len)) {
if (!data->mark_query && !(S_IFINVALID == data->mode))
strbuf_addf(sb, "%06o", data->mode);
} else } else
return 0; return 0;
return 1; return 1;
@ -401,10 +406,8 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
if (!textconv_object(the_repository, if (!textconv_object(the_repository,
data->rest, 0100644, oid, data->rest, 0100644, oid,
1, &contents, &size)) 1, &contents, &size))
contents = repo_read_object_file(the_repository, contents = odb_read_object(the_repository->objects,
oid, oid, &type, &size);
&type,
&size);
if (!contents) if (!contents)
die("could not convert '%s' %s", die("could not convert '%s' %s",
oid_to_hex(oid), data->rest); oid_to_hex(oid), data->rest);
@ -421,8 +424,8 @@ static void print_object_or_die(struct batch_options *opt, struct expand_data *d
unsigned long size; unsigned long size;
void *contents; void *contents;


contents = repo_read_object_file(the_repository, oid, &type, contents = odb_read_object(the_repository->objects, oid,
&size); &type, &size);
if (!contents) if (!contents)
die("object %s disappeared", oid_to_hex(oid)); die("object %s disappeared", oid_to_hex(oid));


@ -484,14 +487,17 @@ static void batch_object_write(const char *obj_name,
data->info.sizep = &data->size; data->info.sizep = &data->size;


if (pack) if (pack)
ret = packed_object_info(the_repository, pack, offset, ret = packed_object_info(the_repository, pack,
&data->info); offset, &data->info);
else else
ret = oid_object_info_extended(the_repository, ret = odb_read_object_info_extended(the_repository->objects,
&data->oid, &data->info, &data->oid, &data->info,
OBJECT_INFO_LOOKUP_REPLACE); OBJECT_INFO_LOOKUP_REPLACE);
if (ret < 0) { if (ret < 0) {
report_object_status(opt, obj_name, &data->oid, "missing"); if (data->mode == S_IFGITLINK)
report_object_status(opt, oid_to_hex(&data->oid), &data->oid, "submodule");
else
report_object_status(opt, obj_name, &data->oid, "missing");
return; return;
} }


@ -531,8 +537,8 @@ static void batch_object_write(const char *obj_name,
size_t s = data->size; size_t s = data->size;
char *buf = NULL; char *buf = NULL;


buf = repo_read_object_file(the_repository, &data->oid, &data->type, buf = odb_read_object(the_repository->objects, &data->oid,
&data->size); &data->type, &data->size);
if (!buf) if (!buf)
die(_("unable to read %s"), oid_to_hex(&data->oid)); die(_("unable to read %s"), oid_to_hex(&data->oid));
buf = replace_idents_using_mailmap(buf, &s); buf = replace_idents_using_mailmap(buf, &s);
@ -613,6 +619,7 @@ static void batch_one_object(const char *obj_name,
goto out; goto out;
} }


data->mode = ctx.mode;
batch_object_write(obj_name, scratch, opt, data, NULL, 0); batch_object_write(obj_name, scratch, opt, data, NULL, 0);


out: out:
@ -866,16 +873,15 @@ static int batch_objects(struct batch_options *opt)
{ {
struct strbuf input = STRBUF_INIT; struct strbuf input = STRBUF_INIT;
struct strbuf output = STRBUF_INIT; struct strbuf output = STRBUF_INIT;
struct expand_data data; struct expand_data data = EXPAND_DATA_INIT;
int save_warning; int save_warning;
int retval = 0; int retval = 0;


/* /*
* Expand once with our special mark_query flag, which will prime the * Expand once with our special mark_query flag, which will prime the
* object_info to be handed to oid_object_info_extended for each * object_info to be handed to odb_read_object_info_extended for each
* object. * object.
*/ */
memset(&data, 0, sizeof(data));
data.mark_query = 1; data.mark_query = 1;
expand_format(&output, expand_format(&output,
opt->format ? opt->format : DEFAULT_FORMAT, opt->format ? opt->format : DEFAULT_FORMAT,

View File

@ -20,7 +20,7 @@
#include "merge-ort-wrappers.h" #include "merge-ort-wrappers.h"
#include "object-file.h" #include "object-file.h"
#include "object-name.h" #include "object-name.h"
#include "object-store.h" #include "odb.h"
#include "parse-options.h" #include "parse-options.h"
#include "path.h" #include "path.h"
#include "preload-index.h" #include "preload-index.h"
@ -838,7 +838,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
init_tree_desc(&trees[0], &tree->object.oid, init_tree_desc(&trees[0], &tree->object.oid,
tree->buffer, tree->size); tree->buffer, tree->size);
if (parse_tree(new_tree) < 0) if (parse_tree(new_tree) < 0)
exit(128); die(NULL);
tree = new_tree; tree = new_tree;
init_tree_desc(&trees[1], &tree->object.oid, init_tree_desc(&trees[1], &tree->object.oid,
tree->buffer, tree->size); tree->buffer, tree->size);
@ -913,7 +913,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
work, work,
old_tree); old_tree);
if (ret < 0) if (ret < 0)
exit(128); die(NULL);
ret = reset_tree(new_tree, ret = reset_tree(new_tree,
opts, 0, opts, 0,
writeout_error, new_branch_info); writeout_error, new_branch_info);

View File

@ -25,7 +25,7 @@
#include "refs.h" #include "refs.h"
#include "refspec.h" #include "refspec.h"
#include "object-file.h" #include "object-file.h"
#include "object-store.h" #include "odb.h"
#include "tree.h" #include "tree.h"
#include "tree-walk.h" #include "tree-walk.h"
#include "unpack-trees.h" #include "unpack-trees.h"
@ -171,7 +171,7 @@ static int add_one_reference(struct string_list_item *item, void *cb_data)
} else { } else {
struct strbuf sb = STRBUF_INIT; struct strbuf sb = STRBUF_INIT;
strbuf_addf(&sb, "%s/objects", ref_git); strbuf_addf(&sb, "%s/objects", ref_git);
add_to_alternates_file(sb.buf); odb_add_to_alternates_file(the_repository->objects, sb.buf);
strbuf_release(&sb); strbuf_release(&sb);
} }


@ -212,12 +212,14 @@ static void copy_alternates(struct strbuf *src, const char *src_repo)
if (!line.len || line.buf[0] == '#') if (!line.len || line.buf[0] == '#')
continue; continue;
if (is_absolute_path(line.buf)) { if (is_absolute_path(line.buf)) {
add_to_alternates_file(line.buf); odb_add_to_alternates_file(the_repository->objects,
line.buf);
continue; continue;
} }
abs_path = mkpathdup("%s/objects/%s", src_repo, line.buf); abs_path = mkpathdup("%s/objects/%s", src_repo, line.buf);
if (!normalize_path_copy(abs_path, abs_path)) if (!normalize_path_copy(abs_path, abs_path))
add_to_alternates_file(abs_path); odb_add_to_alternates_file(the_repository->objects,
abs_path);
else else
warning("skipping invalid relative alternate: %s/%s", warning("skipping invalid relative alternate: %s/%s",
src_repo, line.buf); src_repo, line.buf);
@ -352,7 +354,7 @@ static void clone_local(const char *src_repo, const char *dest_repo)
struct strbuf alt = STRBUF_INIT; struct strbuf alt = STRBUF_INIT;
get_common_dir(&alt, src_repo); get_common_dir(&alt, src_repo);
strbuf_addstr(&alt, "/objects"); strbuf_addstr(&alt, "/objects");
add_to_alternates_file(alt.buf); odb_add_to_alternates_file(the_repository->objects, alt.buf);
strbuf_release(&alt); strbuf_release(&alt);
} else { } else {
struct strbuf src = STRBUF_INIT; struct strbuf src = STRBUF_INIT;
@ -504,7 +506,7 @@ static void write_followtags(const struct ref *refs, const char *msg)
continue; continue;
if (ends_with(ref->name, "^{}")) if (ends_with(ref->name, "^{}"))
continue; continue;
if (!has_object(the_repository, &ref->old_oid, 0)) if (!odb_has_object(the_repository->objects, &ref->old_oid, 0))
continue; continue;
refs_update_ref(get_main_ref_store(the_repository), msg, refs_update_ref(get_main_ref_store(the_repository), msg,
ref->name, &ref->old_oid, NULL, 0, ref->name, &ref->old_oid, NULL, 0,

View File

@ -6,7 +6,7 @@
#include "hex.h" #include "hex.h"
#include "parse-options.h" #include "parse-options.h"
#include "commit-graph.h" #include "commit-graph.h"
#include "object-store.h" #include "odb.h"
#include "progress.h" #include "progress.h"
#include "replace-object.h" #include "replace-object.h"
#include "strbuf.h" #include "strbuf.h"
@ -66,7 +66,7 @@ static int graph_verify(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED) struct repository *repo UNUSED)
{ {
struct commit_graph *graph = NULL; struct commit_graph *graph = NULL;
struct object_directory *odb = NULL; struct odb_source *source = NULL;
char *graph_name; char *graph_name;
char *chain_name; char *chain_name;
enum { OPENED_NONE, OPENED_GRAPH, OPENED_CHAIN } opened = OPENED_NONE; enum { OPENED_NONE, OPENED_GRAPH, OPENED_CHAIN } opened = OPENED_NONE;
@ -101,9 +101,9 @@ static int graph_verify(int argc, const char **argv, const char *prefix,
if (opts.progress) if (opts.progress)
flags |= COMMIT_GRAPH_WRITE_PROGRESS; flags |= COMMIT_GRAPH_WRITE_PROGRESS;


odb = find_odb(the_repository, opts.obj_dir); source = odb_find_source(the_repository->objects, opts.obj_dir);
graph_name = get_commit_graph_filename(odb); graph_name = get_commit_graph_filename(source);
chain_name = get_commit_graph_chain_filename(odb); chain_name = get_commit_graph_chain_filename(source);
if (open_commit_graph(graph_name, &fd, &st)) if (open_commit_graph(graph_name, &fd, &st))
opened = OPENED_GRAPH; opened = OPENED_GRAPH;
else if (errno != ENOENT) else if (errno != ENOENT)
@ -120,7 +120,7 @@ static int graph_verify(int argc, const char **argv, const char *prefix,
if (opened == OPENED_NONE) if (opened == OPENED_NONE)
return 0; return 0;
else if (opened == OPENED_GRAPH) else if (opened == OPENED_GRAPH)
graph = load_commit_graph_one_fd_st(the_repository, fd, &st, odb); graph = load_commit_graph_one_fd_st(the_repository, fd, &st, source);
else else
graph = load_commit_graph_chain_fd_st(the_repository, fd, &st, graph = load_commit_graph_chain_fd_st(the_repository, fd, &st,
&incomplete_chain); &incomplete_chain);
@ -221,7 +221,7 @@ static int graph_write(int argc, const char **argv, const char *prefix,
struct string_list pack_indexes = STRING_LIST_INIT_DUP; struct string_list pack_indexes = STRING_LIST_INIT_DUP;
struct strbuf buf = STRBUF_INIT; struct strbuf buf = STRBUF_INIT;
struct oidset commits = OIDSET_INIT; struct oidset commits = OIDSET_INIT;
struct object_directory *odb = NULL; struct odb_source *source = NULL;
int result = 0; int result = 0;
enum commit_graph_write_flags flags = 0; enum commit_graph_write_flags flags = 0;
struct progress *progress = NULL; struct progress *progress = NULL;
@ -289,10 +289,10 @@ static int graph_write(int argc, const char **argv, const char *prefix,
git_env_bool(GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS, 0)) git_env_bool(GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS, 0))
flags |= COMMIT_GRAPH_WRITE_BLOOM_FILTERS; flags |= COMMIT_GRAPH_WRITE_BLOOM_FILTERS;


odb = find_odb(the_repository, opts.obj_dir); source = odb_find_source(the_repository->objects, opts.obj_dir);


if (opts.reachable) { if (opts.reachable) {
if (write_commit_graph_reachable(odb, flags, &write_opts)) if (write_commit_graph_reachable(source, flags, &write_opts))
result = 1; result = 1;
goto cleanup; goto cleanup;
} }
@ -311,6 +311,7 @@ static int graph_write(int argc, const char **argv, const char *prefix,
while (strbuf_getline(&buf, stdin) != EOF) { while (strbuf_getline(&buf, stdin) != EOF) {
if (read_one_commit(&commits, progress, buf.buf)) { if (read_one_commit(&commits, progress, buf.buf)) {
result = 1; result = 1;
stop_progress(&progress);
goto cleanup; goto cleanup;
} }
} }
@ -318,7 +319,7 @@ static int graph_write(int argc, const char **argv, const char *prefix,
stop_progress(&progress); stop_progress(&progress);
} }


if (write_commit_graph(odb, if (write_commit_graph(source,
opts.stdin_packs ? &pack_indexes : NULL, opts.stdin_packs ? &pack_indexes : NULL,
opts.stdin_commits ? &commits : NULL, opts.stdin_commits ? &commits : NULL,
flags, flags,

View File

@ -9,7 +9,7 @@
#include "gettext.h" #include "gettext.h"
#include "hex.h" #include "hex.h"
#include "object-name.h" #include "object-name.h"
#include "object-store.h" #include "odb.h"


#include "commit.h" #include "commit.h"
#include "parse-options.h" #include "parse-options.h"
@ -48,7 +48,7 @@ static int parse_parent_arg_callback(const struct option *opt,
if (repo_get_oid_commit(the_repository, arg, &oid)) if (repo_get_oid_commit(the_repository, arg, &oid))
die(_("not a valid object name %s"), arg); die(_("not a valid object name %s"), arg);


assert_oid_type(&oid, OBJ_COMMIT); odb_assert_oid_type(the_repository->objects, &oid, OBJ_COMMIT);
new_parent(lookup_commit(the_repository, &oid), parents); new_parent(lookup_commit(the_repository, &oid), parents);
return 0; return 0;
} }

View File

@ -17,9 +17,9 @@


static const char *const builtin_config_usage[] = { static const char *const builtin_config_usage[] = {
N_("git config list [<file-option>] [<display-option>] [--includes]"), N_("git config list [<file-option>] [<display-option>] [--includes]"),
N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"), N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<pattern>] [--fixed-value] [--default=<default>] [--url=<url>] <name>"),
N_("git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--fixed-value] <name> <value>"), N_("git config set [<file-option>] [--type=<type>] [--all] [--value=<pattern>] [--fixed-value] <name> <value>"),
N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name>"), N_("git config unset [<file-option>] [--all] [--value=<pattern>] [--fixed-value] <name>"),
N_("git config rename-section [<file-option>] <old-name> <new-name>"), N_("git config rename-section [<file-option>] <old-name> <new-name>"),
N_("git config remove-section [<file-option>] <name>"), N_("git config remove-section [<file-option>] <name>"),
N_("git config edit [<file-option>]"), N_("git config edit [<file-option>]"),
@ -33,17 +33,17 @@ static const char *const builtin_config_list_usage[] = {
}; };


static const char *const builtin_config_get_usage[] = { static const char *const builtin_config_get_usage[] = {
N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] <name>"), N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp=<regexp>] [--value=<pattern>] [--fixed-value] [--default=<default>] <name>"),
NULL NULL
}; };


static const char *const builtin_config_set_usage[] = { static const char *const builtin_config_set_usage[] = {
N_("git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] [--value=<value>] [--fixed-value] <name> <value>"), N_("git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] [--value=<pattern>] [--fixed-value] <name> <value>"),
NULL NULL
}; };


static const char *const builtin_config_unset_usage[] = { static const char *const builtin_config_unset_usage[] = {
N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name>"), N_("git config unset [<file-option>] [--all] [--value=<pattern>] [--fixed-value] <name>"),
NULL NULL
}; };



View File

@ -80,10 +80,10 @@ static int count_cruft(const char *basename UNUSED, const char *path,
return 0; return 0;
} }


static int print_alternate(struct object_directory *odb, void *data UNUSED) static int print_alternate(struct odb_source *alternate, void *data UNUSED)
{ {
printf("alternate: "); printf("alternate: ");
quote_c_style(odb->path, NULL, stdout, 0); quote_c_style(alternate->path, NULL, stdout, 0);
putchar('\n'); putchar('\n');
return 0; return 0;
} }
@ -159,7 +159,7 @@ int cmd_count_objects(int argc,
printf("prune-packable: %lu\n", packed_loose); printf("prune-packable: %lu\n", packed_loose);
printf("garbage: %lu\n", garbage); printf("garbage: %lu\n", garbage);
printf("size-garbage: %s\n", garbage_buf.buf); printf("size-garbage: %s\n", garbage_buf.buf);
foreach_alt_odb(print_alternate, NULL); odb_for_each_alternate(the_repository->objects, print_alternate, NULL);
strbuf_release(&loose_buf); strbuf_release(&loose_buf);
strbuf_release(&pack_buf); strbuf_release(&pack_buf);
strbuf_release(&garbage_buf); strbuf_release(&garbage_buf);

View File

@ -19,7 +19,7 @@
#include "setup.h" #include "setup.h"
#include "strvec.h" #include "strvec.h"
#include "run-command.h" #include "run-command.h"
#include "object-store.h" #include "odb.h"
#include "list-objects.h" #include "list-objects.h"
#include "commit-slab.h" #include "commit-slab.h"
#include "wildmatch.h" #include "wildmatch.h"
@ -552,7 +552,8 @@ static void describe(const char *arg, int last_one)


if (cmit) if (cmit)
describe_commit(&oid, &sb); describe_commit(&oid, &sb);
else if (oid_object_info(the_repository, &oid, NULL) == OBJ_BLOB) else if (odb_read_object_info(the_repository->objects,
&oid, NULL) == OBJ_BLOB)
describe_blob(oid, &sb); describe_blob(oid, &sb);
else else
die(_("%s is neither a commit nor blob"), arg); die(_("%s is neither a commit nor blob"), arg);

View File

@ -35,7 +35,7 @@ static const char builtin_diff_usage[] =
" or: git diff [<options>] [--merge-base] <commit> [<commit>...] <commit> [--] [<path>...]\n" " or: git diff [<options>] [--merge-base] <commit> [<commit>...] <commit> [--] [<path>...]\n"
" or: git diff [<options>] <commit>...<commit> [--] [<path>...]\n" " or: git diff [<options>] <commit>...<commit> [--] [<path>...]\n"
" or: git diff [<options>] <blob> <blob>\n" " or: git diff [<options>] <blob> <blob>\n"
" or: git diff [<options>] --no-index [--] <path> <path>" " or: git diff [<options>] --no-index [--] <path> <path> [<pathspec>...]"
"\n" "\n"
COMMON_DIFF_OPTIONS_HELP; COMMON_DIFF_OPTIONS_HELP;


@ -483,7 +483,7 @@ int cmd_diff(int argc,
* configurable via a command line option. * configurable via a command line option.
*/ */
if (nongit) if (nongit)
repo_set_hash_algo(the_repository, GIT_HASH_SHA1); repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT);


init_diff_ui_defaults(); init_diff_ui_defaults();
git_config(git_diff_ui_config, NULL); git_config(git_diff_ui_config, NULL);

View File

@ -30,7 +30,7 @@
#include "strbuf.h" #include "strbuf.h"
#include "lockfile.h" #include "lockfile.h"
#include "object-file.h" #include "object-file.h"
#include "object-store.h" #include "odb.h"
#include "dir.h" #include "dir.h"
#include "entry.h" #include "entry.h"
#include "setup.h" #include "setup.h"
@ -320,7 +320,7 @@ static char *get_symlink(struct repository *repo,
} else { } else {
enum object_type type; enum object_type type;
unsigned long size; unsigned long size;
data = repo_read_object_file(repo, oid, &type, &size); data = odb_read_object(repo->objects, oid, &type, &size);
if (!data) if (!data)
die(_("could not read object %s for symlink %s"), die(_("could not read object %s for symlink %s"),
oid_to_hex(oid), path); oid_to_hex(oid), path);

View File

@ -14,7 +14,7 @@
#include "refs.h" #include "refs.h"
#include "refspec.h" #include "refspec.h"
#include "object-file.h" #include "object-file.h"
#include "object-store.h" #include "odb.h"
#include "commit.h" #include "commit.h"
#include "object.h" #include "object.h"
#include "tag.h" #include "tag.h"
@ -323,7 +323,7 @@ static void export_blob(const struct object_id *oid)
object = (struct object *)lookup_blob(the_repository, oid); object = (struct object *)lookup_blob(the_repository, oid);
eaten = 0; eaten = 0;
} else { } else {
buf = repo_read_object_file(the_repository, oid, &type, &size); buf = odb_read_object(the_repository->objects, oid, &type, &size);
if (!buf) if (!buf)
die("could not read blob %s", oid_to_hex(oid)); die("could not read blob %s", oid_to_hex(oid));
if (check_object_signature(the_repository, oid, buf, size, if (check_object_signature(the_repository, oid, buf, size,
@ -869,8 +869,8 @@ static void handle_tag(const char *name, struct tag *tag)
return; return;
} }


buf = repo_read_object_file(the_repository, &tag->object.oid, &type, buf = odb_read_object(the_repository->objects, &tag->object.oid,
&size); &type, &size);
if (!buf) if (!buf)
die("could not read tag %s", oid_to_hex(&tag->object.oid)); die("could not read tag %s", oid_to_hex(&tag->object.oid));
message = memmem(buf, size, "\n\n", 2); message = memmem(buf, size, "\n\n", 2);
@ -1200,7 +1200,7 @@ static void import_marks(char *input_file, int check_exists)
if (last_idnum < mark) if (last_idnum < mark)
last_idnum = mark; last_idnum = mark;


type = oid_object_info(the_repository, &oid, NULL); type = odb_read_object_info(the_repository->objects, &oid, NULL);
if (type < 0) if (type < 0)
die("object not found: %s", oid_to_hex(&oid)); die("object not found: %s", oid_to_hex(&oid));



View File

@ -24,7 +24,7 @@
#include "packfile.h" #include "packfile.h"
#include "object-file.h" #include "object-file.h"
#include "object-name.h" #include "object-name.h"
#include "object-store.h" #include "odb.h"
#include "mem-pool.h" #include "mem-pool.h"
#include "commit-reach.h" #include "commit-reach.h"
#include "khash.h" #include "khash.h"
@ -763,7 +763,8 @@ static void start_packfile(void)
struct packed_git *p; struct packed_git *p;
int pack_fd; int pack_fd;


pack_fd = odb_mkstemp(&tmp_file, "pack/tmp_pack_XXXXXX"); pack_fd = odb_mkstemp(the_repository->objects, &tmp_file,
"pack/tmp_pack_XXXXXX");
FLEX_ALLOC_STR(p, pack_name, tmp_file.buf); FLEX_ALLOC_STR(p, pack_name, tmp_file.buf);
strbuf_release(&tmp_file); strbuf_release(&tmp_file);


@ -1264,7 +1265,7 @@ static void load_tree(struct tree_entry *root)
die("Can't load tree %s", oid_to_hex(oid)); die("Can't load tree %s", oid_to_hex(oid));
} else { } else {
enum object_type type; enum object_type type;
buf = repo_read_object_file(the_repository, oid, &type, &size); buf = odb_read_object(the_repository->objects, oid, &type, &size);
if (!buf || type != OBJ_TREE) if (!buf || type != OBJ_TREE)
die("Can't load tree %s", oid_to_hex(oid)); die("Can't load tree %s", oid_to_hex(oid));
} }
@ -1755,8 +1756,8 @@ static void insert_object_entry(struct mark_set **s, struct object_id *oid, uint
struct object_entry *e; struct object_entry *e;
e = find_object(oid); e = find_object(oid);
if (!e) { if (!e) {
enum object_type type = oid_object_info(the_repository, enum object_type type = odb_read_object_info(the_repository->objects,
oid, NULL); oid, NULL);
if (type < 0) if (type < 0)
die("object not found: %s", oid_to_hex(oid)); die("object not found: %s", oid_to_hex(oid));
e = insert_object(oid); e = insert_object(oid);
@ -2415,8 +2416,8 @@ static void file_change_m(const char *p, struct branch *b)
enum object_type expected = S_ISDIR(mode) ? enum object_type expected = S_ISDIR(mode) ?
OBJ_TREE: OBJ_BLOB; OBJ_TREE: OBJ_BLOB;
enum object_type type = oe ? oe->type : enum object_type type = oe ? oe->type :
oid_object_info(the_repository, &oid, odb_read_object_info(the_repository->objects,
NULL); &oid, NULL);
if (type < 0) if (type < 0)
die("%s not found: %s", die("%s not found: %s",
S_ISDIR(mode) ? "Tree" : "Blob", S_ISDIR(mode) ? "Tree" : "Blob",
@ -2534,10 +2535,9 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa
oidcpy(&commit_oid, &commit_oe->idx.oid); oidcpy(&commit_oid, &commit_oe->idx.oid);
} else if (!repo_get_oid(the_repository, p, &commit_oid)) { } else if (!repo_get_oid(the_repository, p, &commit_oid)) {
unsigned long size; unsigned long size;
char *buf = read_object_with_reference(the_repository, char *buf = odb_read_object_peeled(the_repository->objects,
&commit_oid, &commit_oid, OBJ_COMMIT, &size,
OBJ_COMMIT, &size, &commit_oid);
&commit_oid);
if (!buf || size < the_hash_algo->hexsz + 6) if (!buf || size < the_hash_algo->hexsz + 6)
die("Not a valid commit: %s", p); die("Not a valid commit: %s", p);
free(buf); free(buf);
@ -2552,7 +2552,7 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa
die("Not a blob (actually a %s): %s", die("Not a blob (actually a %s): %s",
type_name(oe->type), command_buf.buf); type_name(oe->type), command_buf.buf);
} else if (!is_null_oid(&oid)) { } else if (!is_null_oid(&oid)) {
enum object_type type = oid_object_info(the_repository, &oid, enum object_type type = odb_read_object_info(the_repository->objects, &oid,
NULL); NULL);
if (type < 0) if (type < 0)
die("Blob not found: %s", command_buf.buf); die("Blob not found: %s", command_buf.buf);
@ -2603,9 +2603,8 @@ static void parse_from_existing(struct branch *b)
unsigned long size; unsigned long size;
char *buf; char *buf;


buf = read_object_with_reference(the_repository, buf = odb_read_object_peeled(the_repository->objects, &b->oid,
&b->oid, OBJ_COMMIT, &size, OBJ_COMMIT, &size, &b->oid);
&b->oid);
parse_from_commit(b, buf, size); parse_from_commit(b, buf, size);
free(buf); free(buf);
} }
@ -2698,10 +2697,9 @@ static struct hash_list *parse_merge(unsigned int *count)
oidcpy(&n->oid, &oe->idx.oid); oidcpy(&n->oid, &oe->idx.oid);
} else if (!repo_get_oid(the_repository, from, &n->oid)) { } else if (!repo_get_oid(the_repository, from, &n->oid)) {
unsigned long size; unsigned long size;
char *buf = read_object_with_reference(the_repository, char *buf = odb_read_object_peeled(the_repository->objects,
&n->oid, &n->oid, OBJ_COMMIT,
OBJ_COMMIT, &size, &n->oid);
&size, &n->oid);
if (!buf || size < the_hash_algo->hexsz + 6) if (!buf || size < the_hash_algo->hexsz + 6)
die("Not a valid commit: %s", from); die("Not a valid commit: %s", from);
free(buf); free(buf);
@ -2894,7 +2892,8 @@ static void parse_new_tag(const char *arg)
} else if (!repo_get_oid(the_repository, from, &oid)) { } else if (!repo_get_oid(the_repository, from, &oid)) {
struct object_entry *oe = find_object(&oid); struct object_entry *oe = find_object(&oid);
if (!oe) { if (!oe) {
type = oid_object_info(the_repository, &oid, NULL); type = odb_read_object_info(the_repository->objects,
&oid, NULL);
if (type < 0) if (type < 0)
die("Not a valid object: %s", from); die("Not a valid object: %s", from);
} else } else
@ -3000,7 +2999,7 @@ static void cat_blob(struct object_entry *oe, struct object_id *oid)
char *buf; char *buf;


if (!oe || oe->pack_id == MAX_PACK_ID) { if (!oe || oe->pack_id == MAX_PACK_ID) {
buf = repo_read_object_file(the_repository, oid, &type, &size); buf = odb_read_object(the_repository->objects, oid, &type, &size);
} else { } else {
type = oe->type; type = oe->type;
buf = gfi_unpack_entry(oe, &size); buf = gfi_unpack_entry(oe, &size);
@ -3084,8 +3083,8 @@ static struct object_entry *dereference(struct object_entry *oe,
const unsigned hexsz = the_hash_algo->hexsz; const unsigned hexsz = the_hash_algo->hexsz;


if (!oe) { if (!oe) {
enum object_type type = oid_object_info(the_repository, oid, enum object_type type = odb_read_object_info(the_repository->objects,
NULL); oid, NULL);
if (type < 0) if (type < 0)
die("object not found: %s", oid_to_hex(oid)); die("object not found: %s", oid_to_hex(oid));
/* cache it! */ /* cache it! */
@ -3108,8 +3107,8 @@ static struct object_entry *dereference(struct object_entry *oe,
buf = gfi_unpack_entry(oe, &size); buf = gfi_unpack_entry(oe, &size);
} else { } else {
enum object_type unused; enum object_type unused;
buf = repo_read_object_file(the_repository, oid, &unused, buf = odb_read_object(the_repository->objects, oid,
&size); &unused, &size);
} }
if (!buf) if (!buf)
die("Can't load object %s", oid_to_hex(oid)); die("Can't load object %s", oid_to_hex(oid));

View File

@ -274,8 +274,10 @@ int cmd_fetch_pack(int argc,
} }
close(fd[0]); close(fd[0]);
close(fd[1]); close(fd[1]);
if (finish_connect(conn)) if (finish_connect(conn)) {
return 1; ret = 1;
goto cleanup;
}


ret = !fetched_refs; ret = !fetched_refs;


@ -291,6 +293,7 @@ int cmd_fetch_pack(int argc,
printf("%s %s\n", printf("%s %s\n",
oid_to_hex(&ref->old_oid), ref->name); oid_to_hex(&ref->old_oid), ref->name);


cleanup:
for (size_t i = 0; i < nr_sought; i++) for (size_t i = 0; i < nr_sought; i++)
free_one_ref(sought_to_free[i]); free_one_ref(sought_to_free[i]);
free(sought_to_free); free(sought_to_free);

View File

@ -14,7 +14,7 @@
#include "refs.h" #include "refs.h"
#include "refspec.h" #include "refspec.h"
#include "object-name.h" #include "object-name.h"
#include "object-store.h" #include "odb.h"
#include "oidset.h" #include "oidset.h"
#include "oid-array.h" #include "oid-array.h"
#include "commit.h" #include "commit.h"
@ -366,9 +366,9 @@ static void find_non_local_tags(const struct ref *refs,
*/ */
if (ends_with(ref->name, "^{}")) { if (ends_with(ref->name, "^{}")) {
if (item && if (item &&
!has_object(the_repository, &ref->old_oid, 0) && !odb_has_object(the_repository->objects, &ref->old_oid, 0) &&
!oidset_contains(&fetch_oids, &ref->old_oid) && !oidset_contains(&fetch_oids, &ref->old_oid) &&
!has_object(the_repository, &item->oid, 0) && !odb_has_object(the_repository->objects, &item->oid, 0) &&
!oidset_contains(&fetch_oids, &item->oid)) !oidset_contains(&fetch_oids, &item->oid))
clear_item(item); clear_item(item);
item = NULL; item = NULL;
@ -382,7 +382,7 @@ static void find_non_local_tags(const struct ref *refs,
* fetch. * fetch.
*/ */
if (item && if (item &&
!has_object(the_repository, &item->oid, 0) && !odb_has_object(the_repository->objects, &item->oid, 0) &&
!oidset_contains(&fetch_oids, &item->oid)) !oidset_contains(&fetch_oids, &item->oid))
clear_item(item); clear_item(item);


@ -403,7 +403,7 @@ static void find_non_local_tags(const struct ref *refs,
* checked to see if it needs fetching. * checked to see if it needs fetching.
*/ */
if (item && if (item &&
!has_object(the_repository, &item->oid, 0) && !odb_has_object(the_repository->objects, &item->oid, 0) &&
!oidset_contains(&fetch_oids, &item->oid)) !oidset_contains(&fetch_oids, &item->oid))
clear_item(item); clear_item(item);


@ -640,9 +640,6 @@ static struct ref *get_ref_map(struct remote *remote,
return ref_map; return ref_map;
} }


#define STORE_REF_ERROR_OTHER 1
#define STORE_REF_ERROR_DF_CONFLICT 2

static int s_update_ref(const char *action, static int s_update_ref(const char *action,
struct ref *ref, struct ref *ref,
struct ref_transaction *transaction, struct ref_transaction *transaction,
@ -650,7 +647,6 @@ static int s_update_ref(const char *action,
{ {
char *msg; char *msg;
char *rla = getenv("GIT_REFLOG_ACTION"); char *rla = getenv("GIT_REFLOG_ACTION");
struct ref_transaction *our_transaction = NULL;
struct strbuf err = STRBUF_INIT; struct strbuf err = STRBUF_INIT;
int ret; int ret;


@ -660,43 +656,10 @@ static int s_update_ref(const char *action,
rla = default_rla.buf; rla = default_rla.buf;
msg = xstrfmt("%s: %s", rla, action); msg = xstrfmt("%s: %s", rla, action);


/*
* If no transaction was passed to us, we manage the transaction
* ourselves. Otherwise, we trust the caller to handle the transaction
* lifecycle.
*/
if (!transaction) {
transaction = our_transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
0, &err);
if (!transaction) {
ret = STORE_REF_ERROR_OTHER;
goto out;
}
}

ret = ref_transaction_update(transaction, ref->name, &ref->new_oid, ret = ref_transaction_update(transaction, ref->name, &ref->new_oid,
check_old ? &ref->old_oid : NULL, check_old ? &ref->old_oid : NULL,
NULL, NULL, 0, msg, &err); NULL, NULL, 0, msg, &err);
if (ret) {
ret = STORE_REF_ERROR_OTHER;
goto out;
}


if (our_transaction) {
switch (ref_transaction_commit(our_transaction, &err)) {
case 0:
break;
case REF_TRANSACTION_ERROR_NAME_CONFLICT:
ret = STORE_REF_ERROR_DF_CONFLICT;
goto out;
default:
ret = STORE_REF_ERROR_OTHER;
goto out;
}
}

out:
ref_transaction_free(our_transaction);
if (ret) if (ret)
error("%s", err.buf); error("%s", err.buf);
strbuf_release(&err); strbuf_release(&err);
@ -910,8 +873,8 @@ static int update_local_ref(struct ref *ref,
struct commit *current = NULL, *updated; struct commit *current = NULL, *updated;
int fast_forward = 0; int fast_forward = 0;


if (!has_object(the_repository, &ref->new_oid, if (!odb_has_object(the_repository->objects, &ref->new_oid,
HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR)) HAS_OBJECT_RECHECK_PACKED | HAS_OBJECT_FETCH_PROMISOR))
die(_("object %s not found"), oid_to_hex(&ref->new_oid)); die(_("object %s not found"), oid_to_hex(&ref->new_oid));


if (oideq(&ref->old_oid, &ref->new_oid)) { if (oideq(&ref->old_oid, &ref->new_oid)) {
@ -992,7 +955,7 @@ static int update_local_ref(struct ref *ref,
fast_forward = repo_in_merge_bases(the_repository, current, fast_forward = repo_in_merge_bases(the_repository, current,
updated); updated);
if (fast_forward < 0) if (fast_forward < 0)
exit(128); die(NULL);
forced_updates_ms += (getnanotime() - t_before) / 1000000; forced_updates_ms += (getnanotime() - t_before) / 1000000;
} else { } else {
fast_forward = 1; fast_forward = 1;
@ -1139,7 +1102,6 @@ N_("it took %.2f seconds to check forced updates; you can use\n"
"to avoid this check\n"); "to avoid this check\n");


static int store_updated_refs(struct display_state *display_state, static int store_updated_refs(struct display_state *display_state,
const char *remote_name,
int connectivity_checked, int connectivity_checked,
struct ref_transaction *transaction, struct ref *ref_map, struct ref_transaction *transaction, struct ref *ref_map,
struct fetch_head *fetch_head, struct fetch_head *fetch_head,
@ -1277,11 +1239,6 @@ static int store_updated_refs(struct display_state *display_state,
} }
} }


if (rc & STORE_REF_ERROR_DF_CONFLICT)
error(_("some local refs could not be updated; try running\n"
" 'git remote prune %s' to remove any old, conflicting "
"branches"), remote_name);

if (advice_enabled(ADVICE_FETCH_SHOW_FORCED_UPDATES)) { if (advice_enabled(ADVICE_FETCH_SHOW_FORCED_UPDATES)) {
if (!config->show_forced_updates) { if (!config->show_forced_updates) {
warning(_(warn_show_forced_updates)); warning(_(warn_show_forced_updates));
@ -1330,7 +1287,8 @@ static int check_exist_and_connected(struct ref *ref_map)
* we need all direct targets to exist. * we need all direct targets to exist.
*/ */
for (r = rm; r; r = r->next) { for (r = rm; r; r = r->next) {
if (!has_object(the_repository, &r->old_oid, HAS_OBJECT_RECHECK_PACKED)) if (!odb_has_object(the_repository->objects, &r->old_oid,
HAS_OBJECT_RECHECK_PACKED))
return -1; return -1;
} }


@ -1365,9 +1323,8 @@ static int fetch_and_consume_refs(struct display_state *display_state,
} }


trace2_region_enter("fetch", "consume_refs", the_repository); trace2_region_enter("fetch", "consume_refs", the_repository);
ret = store_updated_refs(display_state, transport->remote->name, ret = store_updated_refs(display_state, connectivity_checked,
connectivity_checked, transaction, ref_map, transaction, ref_map, fetch_head, config);
fetch_head, config);
trace2_region_leave("fetch", "consume_refs", the_repository); trace2_region_leave("fetch", "consume_refs", the_repository);


out: out:
@ -1383,9 +1340,10 @@ static int prune_refs(struct display_state *display_state,
int result = 0; int result = 0;
struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map); struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map);
struct strbuf err = STRBUF_INIT; struct strbuf err = STRBUF_INIT;
const char *dangling_msg = dry_run struct string_list refnames = STRING_LIST_INIT_NODUP;
? _(" (%s will become dangling)")
: _(" (%s has become dangling)"); for (ref = stale_refs; ref; ref = ref->next)
string_list_append(&refnames, ref->name);


if (!dry_run) { if (!dry_run) {
if (transaction) { if (transaction) {
@ -1396,15 +1354,9 @@ static int prune_refs(struct display_state *display_state,
goto cleanup; goto cleanup;
} }
} else { } else {
struct string_list refnames = STRING_LIST_INIT_NODUP;

for (ref = stale_refs; ref; ref = ref->next)
string_list_append(&refnames, ref->name);

result = refs_delete_refs(get_main_ref_store(the_repository), result = refs_delete_refs(get_main_ref_store(the_repository),
"fetch: prune", &refnames, "fetch: prune", &refnames,
0); 0);
string_list_clear(&refnames, 0);
} }
} }


@ -1416,12 +1368,14 @@ static int prune_refs(struct display_state *display_state,
_("(none)"), ref->name, _("(none)"), ref->name,
&ref->new_oid, &ref->old_oid, &ref->new_oid, &ref->old_oid,
summary_width); summary_width);
refs_warn_dangling_symref(get_main_ref_store(the_repository),
stderr, dangling_msg, ref->name);
} }
string_list_sort(&refnames);
refs_warn_dangling_symrefs(get_main_ref_store(the_repository),
stderr, " ", dry_run, &refnames);
} }


cleanup: cleanup:
string_list_clear(&refnames, 0);
strbuf_release(&err); strbuf_release(&err);
free_refs(stale_refs); free_refs(stale_refs);
return result; return result;
@ -1485,7 +1439,7 @@ static void add_negotiation_tips(struct git_transport_options *smart_options)
struct object_id oid; struct object_id oid;
if (repo_get_oid(the_repository, s, &oid)) if (repo_get_oid(the_repository, s, &oid))
die(_("%s is not a valid object"), s); die(_("%s is not a valid object"), s);
if (!has_object(the_repository, &oid, 0)) if (!odb_has_object(the_repository->objects, &oid, 0))
die(_("the object %s does not exist"), s); die(_("the object %s does not exist"), s);
oid_array_append(oids, &oid); oid_array_append(oids, &oid);
continue; continue;
@ -1687,6 +1641,36 @@ cleanup:
return result; return result;
} }


struct ref_rejection_data {
int *retcode;
int conflict_msg_shown;
const char *remote_name;
};

static void ref_transaction_rejection_handler(const char *refname,
const struct object_id *old_oid UNUSED,
const struct object_id *new_oid UNUSED,
const char *old_target UNUSED,
const char *new_target UNUSED,
enum ref_transaction_error err,
void *cb_data)
{
struct ref_rejection_data *data = cb_data;

if (err == REF_TRANSACTION_ERROR_NAME_CONFLICT && !data->conflict_msg_shown) {
error(_("some local refs could not be updated; try running\n"
" 'git remote prune %s' to remove any old, conflicting "
"branches"), data->remote_name);
data->conflict_msg_shown = 1;
} else {
const char *reason = ref_transaction_error_msg(err);

error(_("fetching ref %s failed: %s"), refname, reason);
}

*data->retcode = 1;
}

static int do_fetch(struct transport *transport, static int do_fetch(struct transport *transport,
struct refspec *rs, struct refspec *rs,
const struct fetch_config *config) const struct fetch_config *config)
@ -1807,6 +1791,24 @@ static int do_fetch(struct transport *transport,
retcode = 1; retcode = 1;
} }


/*
* If not atomic, we can still use batched updates, which would be much
* more performant. We don't initiate the transaction before pruning,
* since pruning must be an independent step, to avoid F/D conflicts.
*
* TODO: if reference transactions gain logical conflict resolution, we
* can delete and create refs (with F/D conflicts) in the same transaction
* and this can be moved above the 'prune_refs()' block.
*/
if (!transaction) {
transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
REF_TRANSACTION_ALLOW_FAILURE, &err);
if (!transaction) {
retcode = -1;
goto cleanup;
}
}

if (fetch_and_consume_refs(&display_state, transport, transaction, ref_map, if (fetch_and_consume_refs(&display_state, transport, transaction, ref_map,
&fetch_head, config)) { &fetch_head, config)) {
retcode = 1; retcode = 1;
@ -1838,16 +1840,31 @@ static int do_fetch(struct transport *transport,
free_refs(tags_ref_map); free_refs(tags_ref_map);
} }


if (transaction) { if (retcode)
if (retcode) goto cleanup;
goto cleanup;


retcode = ref_transaction_commit(transaction, &err); retcode = ref_transaction_commit(transaction, &err);
if (retcode) {
/*
* Explicitly handle transaction cleanup to avoid
* aborting an already closed transaction.
*/
ref_transaction_free(transaction);
transaction = NULL;
goto cleanup;
}

if (!atomic_fetch) {
struct ref_rejection_data data = {
.retcode = &retcode,
.conflict_msg_shown = 0,
.remote_name = transport->remote->name,
};

ref_transaction_for_each_rejected_update(transaction,
ref_transaction_rejection_handler,
&data);
if (retcode) { if (retcode) {
/*
* Explicitly handle transaction cleanup to avoid
* aborting an already closed transaction.
*/
ref_transaction_free(transaction); ref_transaction_free(transaction);
transaction = NULL; transaction = NULL;
goto cleanup; goto cleanup;
@ -2653,7 +2670,7 @@ int cmd_fetch(int argc,
commit_graph_flags |= COMMIT_GRAPH_WRITE_PROGRESS; commit_graph_flags |= COMMIT_GRAPH_WRITE_PROGRESS;


trace2_region_enter("fetch", "write-commit-graph", the_repository); trace2_region_enter("fetch", "write-commit-graph", the_repository);
write_commit_graph_reachable(the_repository->objects->odb, write_commit_graph_reachable(the_repository->objects->sources,
commit_graph_flags, commit_graph_flags,
NULL); NULL);
trace2_region_leave("fetch", "write-commit-graph", the_repository); trace2_region_leave("fetch", "write-commit-graph", the_repository);

View File

@ -17,7 +17,7 @@
#include "packfile.h" #include "packfile.h"
#include "object-file.h" #include "object-file.h"
#include "object-name.h" #include "object-name.h"
#include "object-store.h" #include "odb.h"
#include "path.h" #include "path.h"
#include "read-cache-ll.h" #include "read-cache-ll.h"
#include "replace-object.h" #include "replace-object.h"
@ -71,7 +71,8 @@ static const char *printable_type(const struct object_id *oid,
const char *ret; const char *ret;


if (type == OBJ_NONE) if (type == OBJ_NONE)
type = oid_object_info(the_repository, oid, NULL); type = odb_read_object_info(the_repository->objects,
oid, NULL);


ret = type_name(type); ret = type_name(type);
if (!ret) if (!ret)
@ -160,7 +161,7 @@ static int mark_object(struct object *obj, enum object_type type,
return 0; return 0;


if (!(obj->flags & HAS_OBJ)) { if (!(obj->flags & HAS_OBJ)) {
if (parent && !has_object(the_repository, &obj->oid, 1)) { if (parent && !odb_has_object(the_repository->objects, &obj->oid, 1)) {
printf_ln(_("broken link from %7s %s\n" printf_ln(_("broken link from %7s %s\n"
" to %7s %s"), " to %7s %s"),
printable_type(&parent->oid, parent->type), printable_type(&parent->oid, parent->type),
@ -232,8 +233,8 @@ static void mark_unreachable_referents(const struct object_id *oid)
* (and we want to avoid parsing blobs). * (and we want to avoid parsing blobs).
*/ */
if (obj->type == OBJ_NONE) { if (obj->type == OBJ_NONE) {
enum object_type type = oid_object_info(the_repository, enum object_type type = odb_read_object_info(the_repository->objects,
&obj->oid, NULL); &obj->oid, NULL);
if (type > 0) if (type > 0)
object_as_type(obj, type, 0); object_as_type(obj, type, 0);
} }
@ -956,7 +957,7 @@ int cmd_fsck(int argc,
struct repository *repo UNUSED) struct repository *repo UNUSED)
{ {
int i; int i;
struct object_directory *odb; struct odb_source *source;


/* fsck knows how to handle missing promisor objects */ /* fsck knows how to handle missing promisor objects */
fetch_if_missing = 0; fetch_if_missing = 0;
@ -997,9 +998,9 @@ int cmd_fsck(int argc,
for_each_packed_object(the_repository, for_each_packed_object(the_repository,
mark_packed_for_connectivity, NULL, 0); mark_packed_for_connectivity, NULL, 0);
} else { } else {
prepare_alt_odb(the_repository); odb_prepare_alternates(the_repository->objects);
for (odb = the_repository->objects->odb; odb; odb = odb->next) for (source = the_repository->objects->sources; source; source = source->next)
fsck_object_dir(odb->path); fsck_object_dir(source->path);


if (check_full) { if (check_full) {
struct packed_git *p; struct packed_git *p;
@ -1108,12 +1109,12 @@ int cmd_fsck(int argc,
if (the_repository->settings.core_commit_graph) { if (the_repository->settings.core_commit_graph) {
struct child_process commit_graph_verify = CHILD_PROCESS_INIT; struct child_process commit_graph_verify = CHILD_PROCESS_INIT;


prepare_alt_odb(the_repository); odb_prepare_alternates(the_repository->objects);
for (odb = the_repository->objects->odb; odb; odb = odb->next) { for (source = the_repository->objects->sources; source; source = source->next) {
child_process_init(&commit_graph_verify); child_process_init(&commit_graph_verify);
commit_graph_verify.git_cmd = 1; commit_graph_verify.git_cmd = 1;
strvec_pushl(&commit_graph_verify.args, "commit-graph", strvec_pushl(&commit_graph_verify.args, "commit-graph",
"verify", "--object-dir", odb->path, NULL); "verify", "--object-dir", source->path, NULL);
if (show_progress) if (show_progress)
strvec_push(&commit_graph_verify.args, "--progress"); strvec_push(&commit_graph_verify.args, "--progress");
else else
@ -1126,12 +1127,12 @@ int cmd_fsck(int argc,
if (the_repository->settings.core_multi_pack_index) { if (the_repository->settings.core_multi_pack_index) {
struct child_process midx_verify = CHILD_PROCESS_INIT; struct child_process midx_verify = CHILD_PROCESS_INIT;


prepare_alt_odb(the_repository); odb_prepare_alternates(the_repository->objects);
for (odb = the_repository->objects->odb; odb; odb = odb->next) { for (source = the_repository->objects->sources; source; source = source->next) {
child_process_init(&midx_verify); child_process_init(&midx_verify);
midx_verify.git_cmd = 1; midx_verify.git_cmd = 1;
strvec_pushl(&midx_verify.args, "multi-pack-index", strvec_pushl(&midx_verify.args, "multi-pack-index",
"verify", "--object-dir", odb->path, NULL); "verify", "--object-dir", source->path, NULL);
if (show_progress) if (show_progress)
strvec_push(&midx_verify.args, "--progress"); strvec_push(&midx_verify.args, "--progress");
else else

View File

@ -251,7 +251,24 @@ static enum schedule_priority parse_schedule(const char *value)
return SCHEDULE_NONE; return SCHEDULE_NONE;
} }


enum maintenance_task_label {
TASK_PREFETCH,
TASK_LOOSE_OBJECTS,
TASK_INCREMENTAL_REPACK,
TASK_GC,
TASK_COMMIT_GRAPH,
TASK_PACK_REFS,
TASK_REFLOG_EXPIRE,
TASK_WORKTREE_PRUNE,
TASK_RERERE_GC,

/* Leave as final value */
TASK__COUNT
};

struct maintenance_run_opts { struct maintenance_run_opts {
enum maintenance_task_label *tasks;
size_t tasks_nr, tasks_alloc;
int auto_flag; int auto_flag;
int detach; int detach;
int quiet; int quiet;
@ -261,6 +278,11 @@ struct maintenance_run_opts {
.detach = -1, \ .detach = -1, \
} }


static void maintenance_run_opts_release(struct maintenance_run_opts *opts)
{
free(opts->tasks);
}

static int pack_refs_condition(UNUSED struct gc_config *cfg) static int pack_refs_condition(UNUSED struct gc_config *cfg)
{ {
/* /*
@ -517,7 +539,7 @@ static uint64_t total_ram(void)
return total; return total;
} }
#elif defined(HAVE_BSD_SYSCTL) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM) || defined(HW_PHYSMEM64)) #elif defined(HAVE_BSD_SYSCTL) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM) || defined(HW_PHYSMEM64))
int64_t physical_memory; uint64_t physical_memory;
int mib[2]; int mib[2];
size_t length; size_t length;


@ -529,9 +551,16 @@ static uint64_t total_ram(void)
# else # else
mib[1] = HW_PHYSMEM; mib[1] = HW_PHYSMEM;
# endif # endif
length = sizeof(int64_t); length = sizeof(physical_memory);
if (!sysctl(mib, 2, &physical_memory, &length, NULL, 0)) if (!sysctl(mib, 2, &physical_memory, &length, NULL, 0)) {
if (length == 4) {
uint32_t mem;

if (!sysctl(mib, 2, &mem, &length, NULL, 0))
physical_memory = mem;
}
return physical_memory; return physical_memory;
}
#elif defined(GIT_WINDOWS_NATIVE) #elif defined(GIT_WINDOWS_NATIVE)
MEMORYSTATUSEX memInfo; MEMORYSTATUSEX memInfo;


@ -796,22 +825,14 @@ done:
return ret; return ret;
} }


static void gc_before_repack(struct maintenance_run_opts *opts, static int gc_foreground_tasks(struct maintenance_run_opts *opts,
struct gc_config *cfg) struct gc_config *cfg)
{ {
/*
* We may be called twice, as both the pre- and
* post-daemonized phases will call us, but running these
* commands more than once is pointless and wasteful.
*/
static int done = 0;
if (done++)
return;

if (cfg->pack_refs && maintenance_task_pack_refs(opts, cfg)) if (cfg->pack_refs && maintenance_task_pack_refs(opts, cfg))
die(FAILED_RUN, "pack-refs"); return error(FAILED_RUN, "pack-refs");
if (cfg->prune_reflogs && maintenance_task_reflog_expire(opts, cfg)) if (cfg->prune_reflogs && maintenance_task_reflog_expire(opts, cfg))
die(FAILED_RUN, "reflog"); return error(FAILED_RUN, "reflog");
return 0;
} }


int cmd_gc(int argc, int cmd_gc(int argc,
@ -820,12 +841,12 @@ int cmd_gc(int argc,
struct repository *repo UNUSED) struct repository *repo UNUSED)
{ {
int aggressive = 0; int aggressive = 0;
int quiet = 0;
int force = 0; int force = 0;
const char *name; const char *name;
pid_t pid; pid_t pid;
int daemonized = 0; int daemonized = 0;
int keep_largest_pack = -1; int keep_largest_pack = -1;
int skip_foreground_tasks = 0;
timestamp_t dummy; timestamp_t dummy;
struct maintenance_run_opts opts = MAINTENANCE_RUN_OPTS_INIT; struct maintenance_run_opts opts = MAINTENANCE_RUN_OPTS_INIT;
struct gc_config cfg = GC_CONFIG_INIT; struct gc_config cfg = GC_CONFIG_INIT;
@ -833,7 +854,7 @@ int cmd_gc(int argc,
const char *prune_expire_arg = prune_expire_sentinel; const char *prune_expire_arg = prune_expire_sentinel;
int ret; int ret;
struct option builtin_gc_options[] = { struct option builtin_gc_options[] = {
OPT__QUIET(&quiet, N_("suppress progress reporting")), OPT__QUIET(&opts.quiet, N_("suppress progress reporting")),
{ {
.type = OPTION_STRING, .type = OPTION_STRING,
.long_name = "prune", .long_name = "prune",
@ -858,6 +879,8 @@ int cmd_gc(int argc,
N_("repack all other packs except the largest pack")), N_("repack all other packs except the largest pack")),
OPT_STRING(0, "expire-to", &cfg.repack_expire_to, N_("dir"), OPT_STRING(0, "expire-to", &cfg.repack_expire_to, N_("dir"),
N_("pack prefix to store a pack containing pruned objects")), N_("pack prefix to store a pack containing pruned objects")),
OPT_HIDDEN_BOOL(0, "skip-foreground-tasks", &skip_foreground_tasks,
N_("skip maintenance tasks typically done in the foreground")),
OPT_END() OPT_END()
}; };


@ -893,7 +916,7 @@ int cmd_gc(int argc,
if (cfg.aggressive_window > 0) if (cfg.aggressive_window > 0)
strvec_pushf(&repack, "--window=%d", cfg.aggressive_window); strvec_pushf(&repack, "--window=%d", cfg.aggressive_window);
} }
if (quiet) if (opts.quiet)
strvec_push(&repack, "-q"); strvec_push(&repack, "-q");


if (opts.auto_flag) { if (opts.auto_flag) {
@ -908,7 +931,7 @@ int cmd_gc(int argc,
goto out; goto out;
} }


if (!quiet) { if (!opts.quiet) {
if (opts.detach > 0) if (opts.detach > 0)
fprintf(stderr, _("Auto packing the repository in background for optimum performance.\n")); fprintf(stderr, _("Auto packing the repository in background for optimum performance.\n"));
else else
@ -941,13 +964,16 @@ int cmd_gc(int argc,
goto out; goto out;
} }


if (lock_repo_for_gc(force, &pid)) { if (!skip_foreground_tasks) {
ret = 0; if (lock_repo_for_gc(force, &pid)) {
goto out; ret = 0;
} goto out;
}


gc_before_repack(&opts, &cfg); /* dies on failure */ if (gc_foreground_tasks(&opts, &cfg) < 0)
delete_tempfile(&pidfile); die(NULL);
delete_tempfile(&pidfile);
}


/* /*
* failure to daemonize is ok, we'll continue * failure to daemonize is ok, we'll continue
@ -976,9 +1002,10 @@ int cmd_gc(int argc,
free(path); free(path);
} }


gc_before_repack(&opts, &cfg); if (opts.detach <= 0 && !skip_foreground_tasks)
gc_foreground_tasks(&opts, &cfg);


if (!repository_format_precious_objects) { if (!the_repository->repository_format_precious_objects) {
struct child_process repack_cmd = CHILD_PROCESS_INIT; struct child_process repack_cmd = CHILD_PROCESS_INIT;


repack_cmd.git_cmd = 1; repack_cmd.git_cmd = 1;
@ -993,7 +1020,7 @@ int cmd_gc(int argc,
strvec_pushl(&prune_cmd.args, "prune", "--expire", NULL); strvec_pushl(&prune_cmd.args, "prune", "--expire", NULL);
/* run `git prune` even if using cruft packs */ /* run `git prune` even if using cruft packs */
strvec_push(&prune_cmd.args, cfg.prune_expire); strvec_push(&prune_cmd.args, cfg.prune_expire);
if (quiet) if (opts.quiet)
strvec_push(&prune_cmd.args, "--no-progress"); strvec_push(&prune_cmd.args, "--no-progress");
if (repo_has_promisor_remote(the_repository)) if (repo_has_promisor_remote(the_repository))
strvec_push(&prune_cmd.args, strvec_push(&prune_cmd.args,
@ -1020,8 +1047,8 @@ int cmd_gc(int argc,
} }


if (the_repository->settings.gc_write_commit_graph == 1) if (the_repository->settings.gc_write_commit_graph == 1)
write_commit_graph_reachable(the_repository->objects->odb, write_commit_graph_reachable(the_repository->objects->sources,
!quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0, !opts.quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
NULL); NULL);


if (opts.auto_flag && too_many_loose_objects(&cfg)) if (opts.auto_flag && too_many_loose_objects(&cfg))
@ -1035,6 +1062,7 @@ int cmd_gc(int argc,
} }


out: out:
maintenance_run_opts_release(&opts);
gc_config_release(&cfg); gc_config_release(&cfg);
return 0; return 0;
} }
@ -1082,7 +1110,7 @@ static int dfs_on_ref(const char *refname UNUSED,


if (!peel_iterated_oid(the_repository, oid, &peeled)) if (!peel_iterated_oid(the_repository, oid, &peeled))
oid = &peeled; oid = &peeled;
if (oid_object_info(the_repository, oid, NULL) != OBJ_COMMIT) if (odb_read_object_info(the_repository->objects, oid, NULL) != OBJ_COMMIT)
return 0; return 0;


commit = lookup_commit(the_repository, oid); commit = lookup_commit(the_repository, oid);
@ -1211,8 +1239,14 @@ static int maintenance_task_prefetch(struct maintenance_run_opts *opts,
return 0; return 0;
} }


static int maintenance_task_gc(struct maintenance_run_opts *opts, static int maintenance_task_gc_foreground(struct maintenance_run_opts *opts,
struct gc_config *cfg UNUSED) struct gc_config *cfg)
{
return gc_foreground_tasks(opts, cfg);
}

static int maintenance_task_gc_background(struct maintenance_run_opts *opts,
struct gc_config *cfg UNUSED)
{ {
struct child_process child = CHILD_PROCESS_INIT; struct child_process child = CHILD_PROCESS_INIT;


@ -1226,6 +1260,7 @@ static int maintenance_task_gc(struct maintenance_run_opts *opts,
else else
strvec_push(&child.args, "--no-quiet"); strvec_push(&child.args, "--no-quiet");
strvec_push(&child.args, "--no-detach"); strvec_push(&child.args, "--no-detach");
strvec_push(&child.args, "--skip-foreground-tasks");


return run_command(&child); return run_command(&child);
} }
@ -1273,7 +1308,7 @@ static int loose_object_auto_condition(struct gc_config *cfg UNUSED)
if (loose_object_auto_limit < 0) if (loose_object_auto_limit < 0)
return 1; return 1;


return for_each_loose_file_in_objdir(the_repository->objects->odb->path, return for_each_loose_file_in_objdir(the_repository->objects->sources->path,
loose_object_count, loose_object_count,
NULL, NULL, &count); NULL, NULL, &count);
} }
@ -1308,7 +1343,7 @@ static int pack_loose(struct maintenance_run_opts *opts)
* Do not start pack-objects process * Do not start pack-objects process
* if there are no loose objects. * if there are no loose objects.
*/ */
if (!for_each_loose_file_in_objdir(r->objects->odb->path, if (!for_each_loose_file_in_objdir(r->objects->sources->path,
bail_on_loose, bail_on_loose,
NULL, NULL, NULL)) NULL, NULL, NULL))
return 0; return 0;
@ -1320,7 +1355,7 @@ static int pack_loose(struct maintenance_run_opts *opts)
strvec_push(&pack_proc.args, "--quiet"); strvec_push(&pack_proc.args, "--quiet");
else else
strvec_push(&pack_proc.args, "--no-quiet"); strvec_push(&pack_proc.args, "--no-quiet");
strvec_pushf(&pack_proc.args, "%s/pack/loose", r->objects->odb->path); strvec_pushf(&pack_proc.args, "%s/pack/loose", r->objects->sources->path);


pack_proc.in = -1; pack_proc.in = -1;


@ -1348,7 +1383,7 @@ static int pack_loose(struct maintenance_run_opts *opts)
else if (data.batch_size > 0) else if (data.batch_size > 0)
data.batch_size--; /* Decrease for equality on limit. */ data.batch_size--; /* Decrease for equality on limit. */


for_each_loose_file_in_objdir(r->objects->odb->path, for_each_loose_file_in_objdir(r->objects->sources->path,
write_loose_object_to_stdin, write_loose_object_to_stdin,
NULL, NULL,
NULL, NULL,
@ -1513,107 +1548,120 @@ static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts
return 0; return 0;
} }


typedef int maintenance_task_fn(struct maintenance_run_opts *opts, typedef int (*maintenance_task_fn)(struct maintenance_run_opts *opts,
struct gc_config *cfg); struct gc_config *cfg);

typedef int (*maintenance_auto_fn)(struct gc_config *cfg);
/*
* An auto condition function returns 1 if the task should run
* and 0 if the task should NOT run. See needs_to_gc() for an
* example.
*/
typedef int maintenance_auto_fn(struct gc_config *cfg);


struct maintenance_task { struct maintenance_task {
const char *name; const char *name;
maintenance_task_fn *fn;
maintenance_auto_fn *auto_condition;
unsigned enabled:1;


enum schedule_priority schedule; /*
* Work that will be executed before detaching. This should not include
* tasks that may run for an extended amount of time as it does cause
* auto-maintenance to block until foreground tasks have been run.
*/
maintenance_task_fn foreground;


/* -1 if not selected. */ /*
int selected_order; * Work that will be executed after detaching. When not detaching the
* work will be run in the foreground, as well.
*/
maintenance_task_fn background;

/*
* An auto condition function returns 1 if the task should run and 0 if
* the task should NOT run. See needs_to_gc() for an example.
*/
maintenance_auto_fn auto_condition;
}; };


enum maintenance_task_label { static const struct maintenance_task tasks[] = {
TASK_PREFETCH,
TASK_LOOSE_OBJECTS,
TASK_INCREMENTAL_REPACK,
TASK_GC,
TASK_COMMIT_GRAPH,
TASK_PACK_REFS,
TASK_REFLOG_EXPIRE,
TASK_WORKTREE_PRUNE,
TASK_RERERE_GC,

/* Leave as final value */
TASK__COUNT
};

static struct maintenance_task tasks[] = {
[TASK_PREFETCH] = { [TASK_PREFETCH] = {
"prefetch", .name = "prefetch",
maintenance_task_prefetch, .background = maintenance_task_prefetch,
}, },
[TASK_LOOSE_OBJECTS] = { [TASK_LOOSE_OBJECTS] = {
"loose-objects", .name = "loose-objects",
maintenance_task_loose_objects, .background = maintenance_task_loose_objects,
loose_object_auto_condition, .auto_condition = loose_object_auto_condition,
}, },
[TASK_INCREMENTAL_REPACK] = { [TASK_INCREMENTAL_REPACK] = {
"incremental-repack", .name = "incremental-repack",
maintenance_task_incremental_repack, .background = maintenance_task_incremental_repack,
incremental_repack_auto_condition, .auto_condition = incremental_repack_auto_condition,
}, },
[TASK_GC] = { [TASK_GC] = {
"gc", .name = "gc",
maintenance_task_gc, .foreground = maintenance_task_gc_foreground,
need_to_gc, .background = maintenance_task_gc_background,
1, .auto_condition = need_to_gc,
}, },
[TASK_COMMIT_GRAPH] = { [TASK_COMMIT_GRAPH] = {
"commit-graph", .name = "commit-graph",
maintenance_task_commit_graph, .background = maintenance_task_commit_graph,
should_write_commit_graph, .auto_condition = should_write_commit_graph,
}, },
[TASK_PACK_REFS] = { [TASK_PACK_REFS] = {
"pack-refs", .name = "pack-refs",
maintenance_task_pack_refs, .foreground = maintenance_task_pack_refs,
pack_refs_condition, .auto_condition = pack_refs_condition,
}, },
[TASK_REFLOG_EXPIRE] = { [TASK_REFLOG_EXPIRE] = {
"reflog-expire", .name = "reflog-expire",
maintenance_task_reflog_expire, .foreground = maintenance_task_reflog_expire,
reflog_expire_condition, .auto_condition = reflog_expire_condition,
}, },
[TASK_WORKTREE_PRUNE] = { [TASK_WORKTREE_PRUNE] = {
"worktree-prune", .name = "worktree-prune",
maintenance_task_worktree_prune, .background = maintenance_task_worktree_prune,
worktree_prune_condition, .auto_condition = worktree_prune_condition,
}, },
[TASK_RERERE_GC] = { [TASK_RERERE_GC] = {
"rerere-gc", .name = "rerere-gc",
maintenance_task_rerere_gc, .background = maintenance_task_rerere_gc,
rerere_gc_condition, .auto_condition = rerere_gc_condition,
}, },
}; };


static int compare_tasks_by_selection(const void *a_, const void *b_) enum task_phase {
{ TASK_PHASE_FOREGROUND,
const struct maintenance_task *a = a_; TASK_PHASE_BACKGROUND,
const struct maintenance_task *b = b_; };


return b->selected_order - a->selected_order; static int maybe_run_task(const struct maintenance_task *task,
struct repository *repo,
struct maintenance_run_opts *opts,
struct gc_config *cfg,
enum task_phase phase)
{
int foreground = (phase == TASK_PHASE_FOREGROUND);
maintenance_task_fn fn = foreground ? task->foreground : task->background;
const char *region = foreground ? "maintenance foreground" : "maintenance";
int ret = 0;

if (!fn)
return 0;
if (opts->auto_flag &&
(!task->auto_condition || !task->auto_condition(cfg)))
return 0;

trace2_region_enter(region, task->name, repo);
if (fn(opts, cfg)) {
error(_("task '%s' failed"), task->name);
ret = 1;
}
trace2_region_leave(region, task->name, repo);

return ret;
} }


static int maintenance_run_tasks(struct maintenance_run_opts *opts, static int maintenance_run_tasks(struct maintenance_run_opts *opts,
struct gc_config *cfg) struct gc_config *cfg)
{ {
int i, found_selected = 0;
int result = 0; int result = 0;
struct lock_file lk; struct lock_file lk;
struct repository *r = the_repository; struct repository *r = the_repository;
char *lock_path = xstrfmt("%s/maintenance", r->objects->odb->path); char *lock_path = xstrfmt("%s/maintenance", r->objects->sources->path);


if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) { if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) {
/* /*
@ -1631,6 +1679,11 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts,
} }
free(lock_path); free(lock_path);


for (size_t i = 0; i < opts->tasks_nr; i++)
if (maybe_run_task(&tasks[opts->tasks[i]], r, opts, cfg,
TASK_PHASE_FOREGROUND))
result = 1;

/* Failure to daemonize is ok, we'll continue in foreground. */ /* Failure to daemonize is ok, we'll continue in foreground. */
if (opts->detach > 0) { if (opts->detach > 0) {
trace2_region_enter("maintenance", "detach", the_repository); trace2_region_enter("maintenance", "detach", the_repository);
@ -1638,120 +1691,138 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts,
trace2_region_leave("maintenance", "detach", the_repository); trace2_region_leave("maintenance", "detach", the_repository);
} }


for (i = 0; !found_selected && i < TASK__COUNT; i++) for (size_t i = 0; i < opts->tasks_nr; i++)
found_selected = tasks[i].selected_order >= 0; if (maybe_run_task(&tasks[opts->tasks[i]], r, opts, cfg,

TASK_PHASE_BACKGROUND))
if (found_selected)
QSORT(tasks, TASK__COUNT, compare_tasks_by_selection);

for (i = 0; i < TASK__COUNT; i++) {
if (found_selected && tasks[i].selected_order < 0)
continue;

if (!found_selected && !tasks[i].enabled)
continue;

if (opts->auto_flag &&
(!tasks[i].auto_condition ||
!tasks[i].auto_condition(cfg)))
continue;

if (opts->schedule && tasks[i].schedule < opts->schedule)
continue;

trace2_region_enter("maintenance", tasks[i].name, r);
if (tasks[i].fn(opts, cfg)) {
error(_("task '%s' failed"), tasks[i].name);
result = 1; result = 1;
}
trace2_region_leave("maintenance", tasks[i].name, r);
}


rollback_lock_file(&lk); rollback_lock_file(&lk);
return result; return result;
} }


static void initialize_maintenance_strategy(void) struct maintenance_strategy {
struct {
int enabled;
enum schedule_priority schedule;
} tasks[TASK__COUNT];
};

static const struct maintenance_strategy none_strategy = { 0 };
static const struct maintenance_strategy default_strategy = {
.tasks = {
[TASK_GC].enabled = 1,
},
};
static const struct maintenance_strategy incremental_strategy = {
.tasks = {
[TASK_COMMIT_GRAPH].enabled = 1,
[TASK_COMMIT_GRAPH].schedule = SCHEDULE_HOURLY,
[TASK_PREFETCH].enabled = 1,
[TASK_PREFETCH].schedule = SCHEDULE_HOURLY,
[TASK_INCREMENTAL_REPACK].enabled = 1,
[TASK_INCREMENTAL_REPACK].schedule = SCHEDULE_DAILY,
[TASK_LOOSE_OBJECTS].enabled = 1,
[TASK_LOOSE_OBJECTS].schedule = SCHEDULE_DAILY,
[TASK_PACK_REFS].enabled = 1,
[TASK_PACK_REFS].schedule = SCHEDULE_WEEKLY,
},
};

static void initialize_task_config(struct maintenance_run_opts *opts,
const struct string_list *selected_tasks)
{ {
struct strbuf config_name = STRBUF_INIT;
struct maintenance_strategy strategy;
const char *config_str; const char *config_str;


if (git_config_get_string_tmp("maintenance.strategy", &config_str)) /*
* In case the user has asked us to run tasks explicitly we only use
* those specified tasks. Specifically, we do _not_ want to consult the
* config or maintenance strategy.
*/
if (selected_tasks->nr) {
for (size_t i = 0; i < selected_tasks->nr; i++) {
enum maintenance_task_label label = (intptr_t)selected_tasks->items[i].util;;
ALLOC_GROW(opts->tasks, opts->tasks_nr + 1, opts->tasks_alloc);
opts->tasks[opts->tasks_nr++] = label;
}

return; return;

if (!strcasecmp(config_str, "incremental")) {
tasks[TASK_GC].schedule = SCHEDULE_NONE;
tasks[TASK_COMMIT_GRAPH].enabled = 1;
tasks[TASK_COMMIT_GRAPH].schedule = SCHEDULE_HOURLY;
tasks[TASK_PREFETCH].enabled = 1;
tasks[TASK_PREFETCH].schedule = SCHEDULE_HOURLY;
tasks[TASK_INCREMENTAL_REPACK].enabled = 1;
tasks[TASK_INCREMENTAL_REPACK].schedule = SCHEDULE_DAILY;
tasks[TASK_LOOSE_OBJECTS].enabled = 1;
tasks[TASK_LOOSE_OBJECTS].schedule = SCHEDULE_DAILY;
tasks[TASK_PACK_REFS].enabled = 1;
tasks[TASK_PACK_REFS].schedule = SCHEDULE_WEEKLY;
} }
}


static void initialize_task_config(int schedule) /*
{ * Otherwise, the strategy depends on whether we run as part of a
int i; * scheduled job or not:
struct strbuf config_name = STRBUF_INIT; *
* - Scheduled maintenance does not perform any housekeeping by
* default, but requires the user to pick a maintenance strategy.
*
* - Unscheduled maintenance uses our default strategy.
*
* Both of these are affected by the gitconfig though, which may
* override specific aspects of our strategy.
*/
if (opts->schedule) {
strategy = none_strategy;


if (schedule) if (!git_config_get_string_tmp("maintenance.strategy", &config_str)) {
initialize_maintenance_strategy(); if (!strcasecmp(config_str, "incremental"))
strategy = incremental_strategy;
}
} else {
strategy = default_strategy;
}


for (i = 0; i < TASK__COUNT; i++) { for (size_t i = 0; i < TASK__COUNT; i++) {
int config_value; int config_value;
char *config_str;


strbuf_reset(&config_name); strbuf_reset(&config_name);
strbuf_addf(&config_name, "maintenance.%s.enabled", strbuf_addf(&config_name, "maintenance.%s.enabled",
tasks[i].name); tasks[i].name);

if (!git_config_get_bool(config_name.buf, &config_value)) if (!git_config_get_bool(config_name.buf, &config_value))
tasks[i].enabled = config_value; strategy.tasks[i].enabled = config_value;
if (!strategy.tasks[i].enabled)
continue;


strbuf_reset(&config_name); if (opts->schedule) {
strbuf_addf(&config_name, "maintenance.%s.schedule", strbuf_reset(&config_name);
tasks[i].name); strbuf_addf(&config_name, "maintenance.%s.schedule",

tasks[i].name);
if (!git_config_get_string(config_name.buf, &config_str)) { if (!git_config_get_string_tmp(config_name.buf, &config_str))
tasks[i].schedule = parse_schedule(config_str); strategy.tasks[i].schedule = parse_schedule(config_str);
free(config_str); if (strategy.tasks[i].schedule < opts->schedule)
continue;
} }

ALLOC_GROW(opts->tasks, opts->tasks_nr + 1, opts->tasks_alloc);
opts->tasks[opts->tasks_nr++] = i;
} }


strbuf_release(&config_name); strbuf_release(&config_name);
} }


static int task_option_parse(const struct option *opt UNUSED, static int task_option_parse(const struct option *opt,
const char *arg, int unset) const char *arg, int unset)
{ {
int i, num_selected = 0; struct string_list *selected_tasks = opt->value;
struct maintenance_task *task = NULL; size_t i;


BUG_ON_OPT_NEG(unset); BUG_ON_OPT_NEG(unset);


for (i = 0; i < TASK__COUNT; i++) { for (i = 0; i < TASK__COUNT; i++)
if (tasks[i].selected_order >= 0) if (!strcasecmp(tasks[i].name, arg))
num_selected++; break;
if (!strcasecmp(tasks[i].name, arg)) { if (i >= TASK__COUNT) {
task = &tasks[i];
}
}

if (!task) {
error(_("'%s' is not a valid task"), arg); error(_("'%s' is not a valid task"), arg);
return 1; return 1;
} }


if (task->selected_order >= 0) { if (unsorted_string_list_has_string(selected_tasks, arg)) {
error(_("task '%s' cannot be selected multiple times"), arg); error(_("task '%s' cannot be selected multiple times"), arg);
return 1; return 1;
} }


task->selected_order = num_selected + 1; string_list_append(selected_tasks, arg)->util = (void *)(intptr_t)i;


return 0; return 0;
} }
@ -1759,8 +1830,8 @@ static int task_option_parse(const struct option *opt UNUSED,
static int maintenance_run(int argc, const char **argv, const char *prefix, static int maintenance_run(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED) struct repository *repo UNUSED)
{ {
int i;
struct maintenance_run_opts opts = MAINTENANCE_RUN_OPTS_INIT; struct maintenance_run_opts opts = MAINTENANCE_RUN_OPTS_INIT;
struct string_list selected_tasks = STRING_LIST_INIT_DUP;
struct gc_config cfg = GC_CONFIG_INIT; struct gc_config cfg = GC_CONFIG_INIT;
struct option builtin_maintenance_run_options[] = { struct option builtin_maintenance_run_options[] = {
OPT_BOOL(0, "auto", &opts.auto_flag, OPT_BOOL(0, "auto", &opts.auto_flag,
@ -1772,7 +1843,7 @@ static int maintenance_run(int argc, const char **argv, const char *prefix,
maintenance_opt_schedule), maintenance_opt_schedule),
OPT_BOOL(0, "quiet", &opts.quiet, OPT_BOOL(0, "quiet", &opts.quiet,
N_("do not report progress or other information over stderr")), N_("do not report progress or other information over stderr")),
OPT_CALLBACK_F(0, "task", NULL, N_("task"), OPT_CALLBACK_F(0, "task", &selected_tasks, N_("task"),
N_("run a specific task"), N_("run a specific task"),
PARSE_OPT_NONEG, task_option_parse), PARSE_OPT_NONEG, task_option_parse),
OPT_END() OPT_END()
@ -1781,25 +1852,27 @@ static int maintenance_run(int argc, const char **argv, const char *prefix,


opts.quiet = !isatty(2); opts.quiet = !isatty(2);


for (i = 0; i < TASK__COUNT; i++)
tasks[i].selected_order = -1;

argc = parse_options(argc, argv, prefix, argc = parse_options(argc, argv, prefix,
builtin_maintenance_run_options, builtin_maintenance_run_options,
builtin_maintenance_run_usage, builtin_maintenance_run_usage,
PARSE_OPT_STOP_AT_NON_OPTION); PARSE_OPT_STOP_AT_NON_OPTION);


if (opts.auto_flag && opts.schedule) die_for_incompatible_opt2(opts.auto_flag, "--auto",
die(_("use at most one of --auto and --schedule=<frequency>")); opts.schedule, "--schedule=");
die_for_incompatible_opt2(selected_tasks.nr, "--task=",
opts.schedule, "--schedule=");


gc_config(&cfg); gc_config(&cfg);
initialize_task_config(opts.schedule); initialize_task_config(&opts, &selected_tasks);


if (argc != 0) if (argc != 0)
usage_with_options(builtin_maintenance_run_usage, usage_with_options(builtin_maintenance_run_usage,
builtin_maintenance_run_options); builtin_maintenance_run_options);


ret = maintenance_run_tasks(&opts, &cfg); ret = maintenance_run_tasks(&opts, &cfg);

string_list_clear(&selected_tasks, 0);
maintenance_run_opts_release(&opts);
gc_config_release(&cfg); gc_config_release(&cfg);
return ret; return ret;
} }
@ -3085,7 +3158,7 @@ static int update_background_schedule(const struct maintenance_start_opts *opts,
unsigned int i; unsigned int i;
int result = 0; int result = 0;
struct lock_file lk; struct lock_file lk;
char *lock_path = xstrfmt("%s/schedule", the_repository->objects->odb->path); char *lock_path = xstrfmt("%s/schedule", the_repository->objects->sources->path);


if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) { if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) {
if (errno == EEXIST) if (errno == EEXIST)

View File

@ -26,7 +26,7 @@
#include "submodule-config.h" #include "submodule-config.h"
#include "object-file.h" #include "object-file.h"
#include "object-name.h" #include "object-name.h"
#include "object-store.h" #include "odb.h"
#include "packfile.h" #include "packfile.h"
#include "pager.h" #include "pager.h"
#include "path.h" #include "path.h"
@ -462,7 +462,7 @@ static int grep_submodule(struct grep_opt *opt,


/* /*
* NEEDSWORK: repo_read_gitmodules() might call * NEEDSWORK: repo_read_gitmodules() might call
* add_to_alternates_memory() via config_from_gitmodules(). This * odb_add_to_alternates_memory() via config_from_gitmodules(). This
* operation causes a race condition with concurrent object readings * operation causes a race condition with concurrent object readings
* performed by the worker threads. That's why we need obj_read_lock() * performed by the worker threads. That's why we need obj_read_lock()
* here. It should be removed once it's no longer necessary to add the * here. It should be removed once it's no longer necessary to add the
@ -505,7 +505,8 @@ static int grep_submodule(struct grep_opt *opt,
* lazily registered as alternates when needed (and except in an * lazily registered as alternates when needed (and except in an
* unexpected code interaction, it won't be needed). * unexpected code interaction, it won't be needed).
*/ */
add_submodule_odb_by_path(subrepo->objects->odb->path); odb_add_submodule_source_by_path(the_repository->objects,
subrepo->objects->sources->path);
obj_read_unlock(); obj_read_unlock();


memcpy(&subopt, opt, sizeof(subopt)); memcpy(&subopt, opt, sizeof(subopt));
@ -519,11 +520,9 @@ static int grep_submodule(struct grep_opt *opt,
struct strbuf base = STRBUF_INIT; struct strbuf base = STRBUF_INIT;


obj_read_lock(); obj_read_lock();
object_type = oid_object_info(subrepo, oid, NULL); object_type = odb_read_object_info(subrepo->objects, oid, NULL);
obj_read_unlock(); obj_read_unlock();
data = read_object_with_reference(subrepo, data = odb_read_object_peeled(subrepo->objects, oid, OBJ_TREE, &size, NULL);
oid, OBJ_TREE,
&size, NULL);
if (!data) if (!data)
die(_("unable to read tree (%s)"), oid_to_hex(oid)); die(_("unable to read tree (%s)"), oid_to_hex(oid));


@ -572,8 +571,8 @@ static int grep_cache(struct grep_opt *opt,
void *data; void *data;
unsigned long size; unsigned long size;


data = repo_read_object_file(the_repository, &ce->oid, data = odb_read_object(the_repository->objects, &ce->oid,
&type, &size); &type, &size);
if (!data) if (!data)
die(_("unable to read tree %s"), oid_to_hex(&ce->oid)); die(_("unable to read tree %s"), oid_to_hex(&ce->oid));
init_tree_desc(&tree, &ce->oid, data, size); init_tree_desc(&tree, &ce->oid, data, size);
@ -665,8 +664,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
void *data; void *data;
unsigned long size; unsigned long size;


data = repo_read_object_file(the_repository, data = odb_read_object(the_repository->objects,
&entry.oid, &type, &size); &entry.oid, &type, &size);
if (!data) if (!data)
die(_("unable to read tree (%s)"), die(_("unable to read tree (%s)"),
oid_to_hex(&entry.oid)); oid_to_hex(&entry.oid));
@ -704,9 +703,8 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
struct strbuf base; struct strbuf base;
int hit, len; int hit, len;


data = read_object_with_reference(opt->repo, data = odb_read_object_peeled(opt->repo->objects, &obj->oid,
&obj->oid, OBJ_TREE, OBJ_TREE, &size, NULL);
&size, NULL);
if (!data) if (!data)
die(_("unable to read tree (%s)"), oid_to_hex(&obj->oid)); die(_("unable to read tree (%s)"), oid_to_hex(&obj->oid));



View File

@ -11,7 +11,7 @@
#include "gettext.h" #include "gettext.h"
#include "hex.h" #include "hex.h"
#include "object-file.h" #include "object-file.h"
#include "object-store.h" #include "odb.h"
#include "blob.h" #include "blob.h"
#include "quote.h" #include "quote.h"
#include "parse-options.h" #include "parse-options.h"
@ -104,7 +104,7 @@ int cmd_hash_object(int argc,
prefix = setup_git_directory_gently(&nongit); prefix = setup_git_directory_gently(&nongit);


if (nongit && !the_hash_algo) if (nongit && !the_hash_algo)
repo_set_hash_algo(the_repository, GIT_HASH_SHA1); repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT);


if (vpath && prefix) { if (vpath && prefix) {
vpath_free = prefix_filename(prefix, vpath); vpath_free = prefix_filename(prefix, vpath);

View File

@ -21,7 +21,7 @@
#include "packfile.h" #include "packfile.h"
#include "pack-revindex.h" #include "pack-revindex.h"
#include "object-file.h" #include "object-file.h"
#include "object-store.h" #include "odb.h"
#include "oid-array.h" #include "oid-array.h"
#include "oidset.h" #include "oidset.h"
#include "path.h" #include "path.h"
@ -260,7 +260,8 @@ static unsigned check_object(struct object *obj)


if (!(obj->flags & FLAG_CHECKED)) { if (!(obj->flags & FLAG_CHECKED)) {
unsigned long size; unsigned long size;
int type = oid_object_info(the_repository, &obj->oid, &size); int type = odb_read_object_info(the_repository->objects,
&obj->oid, &size);
if (type <= 0) if (type <= 0)
die(_("did not receive expected object %s"), die(_("did not receive expected object %s"),
oid_to_hex(&obj->oid)); oid_to_hex(&obj->oid));
@ -362,7 +363,7 @@ static const char *open_pack_file(const char *pack_name)
input_fd = 0; input_fd = 0;
if (!pack_name) { if (!pack_name) {
struct strbuf tmp_file = STRBUF_INIT; struct strbuf tmp_file = STRBUF_INIT;
output_fd = odb_mkstemp(&tmp_file, output_fd = odb_mkstemp(the_repository->objects, &tmp_file,
"pack/tmp_pack_XXXXXX"); "pack/tmp_pack_XXXXXX");
pack_name = strbuf_detach(&tmp_file, NULL); pack_name = strbuf_detach(&tmp_file, NULL);
} else { } else {
@ -892,8 +893,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,


if (startup_info->have_repository) { if (startup_info->have_repository) {
read_lock(); read_lock();
collision_test_needed = has_object(the_repository, oid, collision_test_needed = odb_has_object(the_repository->objects, oid,
HAS_OBJECT_FETCH_PROMISOR); HAS_OBJECT_FETCH_PROMISOR);
read_unlock(); read_unlock();
} }


@ -908,13 +909,13 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,
enum object_type has_type; enum object_type has_type;
unsigned long has_size; unsigned long has_size;
read_lock(); read_lock();
has_type = oid_object_info(the_repository, oid, &has_size); has_type = odb_read_object_info(the_repository->objects, oid, &has_size);
if (has_type < 0) if (has_type < 0)
die(_("cannot read existing object info %s"), oid_to_hex(oid)); die(_("cannot read existing object info %s"), oid_to_hex(oid));
if (has_type != type || has_size != size) if (has_type != type || has_size != size)
die(_("SHA1 COLLISION FOUND WITH %s !"), oid_to_hex(oid)); die(_("SHA1 COLLISION FOUND WITH %s !"), oid_to_hex(oid));
has_data = repo_read_object_file(the_repository, oid, has_data = odb_read_object(the_repository->objects, oid,
&has_type, &has_size); &has_type, &has_size);
read_unlock(); read_unlock();
if (!data) if (!data)
data = new_data = get_data_from_pack(obj_entry); data = new_data = get_data_from_pack(obj_entry);
@ -1501,9 +1502,9 @@ static void fix_unresolved_deltas(struct hashfile *f)
struct oid_array to_fetch = OID_ARRAY_INIT; struct oid_array to_fetch = OID_ARRAY_INIT;
for (i = 0; i < nr_ref_deltas; i++) { for (i = 0; i < nr_ref_deltas; i++) {
struct ref_delta_entry *d = sorted_by_pos[i]; struct ref_delta_entry *d = sorted_by_pos[i];
if (!oid_object_info_extended(the_repository, &d->oid, if (!odb_read_object_info_extended(the_repository->objects,
NULL, &d->oid, NULL,
OBJECT_INFO_FOR_PREFETCH)) OBJECT_INFO_FOR_PREFETCH))
continue; continue;
oid_array_append(&to_fetch, &d->oid); oid_array_append(&to_fetch, &d->oid);
} }
@ -1520,8 +1521,8 @@ static void fix_unresolved_deltas(struct hashfile *f)


if (objects[d->obj_no].real_type != OBJ_REF_DELTA) if (objects[d->obj_no].real_type != OBJ_REF_DELTA)
continue; continue;
data = repo_read_object_file(the_repository, &d->oid, &type, data = odb_read_object(the_repository->objects, &d->oid,
&size); &type, &size);
if (!data) if (!data)
continue; continue;


@ -1829,7 +1830,7 @@ static void repack_local_links(void)
oidset_iter_init(&outgoing_links, &iter); oidset_iter_init(&outgoing_links, &iter);
while ((oid = oidset_iter_next(&iter))) { while ((oid = oidset_iter_next(&iter))) {
struct object_info info = OBJECT_INFO_INIT; struct object_info info = OBJECT_INFO_INIT;
if (oid_object_info_extended(the_repository, oid, &info, 0)) if (odb_read_object_info_extended(the_repository->objects, oid, &info, 0))
/* Missing; assume it is a promisor object */ /* Missing; assume it is a promisor object */
continue; continue;
if (info.whence == OI_PACKED && info.u.packed.pack->pack_promisor) if (info.whence == OI_PACKED && info.u.packed.pack->pack_promisor)
@ -2034,7 +2035,7 @@ int cmd_index_pack(int argc,
* choice but to guess the object hash. * choice but to guess the object hash.
*/ */
if (!the_repository->hash_algo) if (!the_repository->hash_algo)
repo_set_hash_algo(the_repository, GIT_HASH_SHA1); repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT);


opts.flags &= ~(WRITE_REV | WRITE_REV_VERIFY); opts.flags &= ~(WRITE_REV | WRITE_REV_VERIFY);
if (rev_index) { if (rev_index) {

View File

@ -15,7 +15,7 @@
#include "hex.h" #include "hex.h"
#include "refs.h" #include "refs.h"
#include "object-name.h" #include "object-name.h"
#include "object-store.h" #include "odb.h"
#include "pager.h" #include "pager.h"
#include "color.h" #include "color.h"
#include "commit.h" #include "commit.h"
@ -113,6 +113,15 @@ struct log_config {
int fmt_patch_name_max; int fmt_patch_name_max;
char *fmt_pretty; char *fmt_pretty;
char *default_date_mode; char *default_date_mode;

#ifndef WITH_BREAKING_CHANGES
/*
* Note: git_log_config() does not touch this member and that
* is very deliberate. This member is only to be used to
* resurrect whatchanged that is deprecated.
*/
int i_still_use_this;
#endif
}; };


static void log_config_init(struct log_config *cfg) static void log_config_init(struct log_config *cfg)
@ -267,6 +276,10 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
OPT__QUIET(&quiet, N_("suppress diff output")), OPT__QUIET(&quiet, N_("suppress diff output")),
OPT_BOOL(0, "source", &source, N_("show source")), OPT_BOOL(0, "source", &source, N_("show source")),
OPT_BOOL(0, "use-mailmap", &mailmap, N_("use mail map file")), OPT_BOOL(0, "use-mailmap", &mailmap, N_("use mail map file")),
#ifndef WITH_BREAKING_CHANGES
OPT_HIDDEN_BOOL(0, "i-still-use-this", &cfg->i_still_use_this,
"<use this deprecated command>"),
#endif
OPT_ALIAS(0, "mailmap", "use-mailmap"), OPT_ALIAS(0, "mailmap", "use-mailmap"),
OPT_CALLBACK_F(0, "clear-decorations", NULL, NULL, OPT_CALLBACK_F(0, "clear-decorations", NULL, NULL,
N_("clear all previously-defined decoration filters"), N_("clear all previously-defined decoration filters"),
@ -633,6 +646,7 @@ static int git_log_config(const char *var, const char *value,
return git_diff_ui_config(var, value, ctx, cb); return git_diff_ui_config(var, value, ctx, cb);
} }


#ifndef WITH_BREAKING_CHANGES
int cmd_whatchanged(int argc, int cmd_whatchanged(int argc,
const char **argv, const char **argv,
const char *prefix, const char *prefix,
@ -656,6 +670,10 @@ int cmd_whatchanged(int argc,
opt.def = "HEAD"; opt.def = "HEAD";
opt.revarg_opt = REVARG_COMMITTISH; opt.revarg_opt = REVARG_COMMITTISH;
cmd_log_init(argc, argv, prefix, &rev, &opt, &cfg); cmd_log_init(argc, argv, prefix, &rev, &opt, &cfg);

if (!cfg.i_still_use_this)
you_still_use_that("git whatchanged");

if (!rev.diffopt.output_format) if (!rev.diffopt.output_format)
rev.diffopt.output_format = DIFF_FORMAT_RAW; rev.diffopt.output_format = DIFF_FORMAT_RAW;


@ -665,6 +683,7 @@ int cmd_whatchanged(int argc,
log_config_release(&cfg); log_config_release(&cfg);
return ret; return ret;
} }
#endif


static void show_tagger(const char *buf, struct rev_info *rev) static void show_tagger(const char *buf, struct rev_info *rev)
{ {
@ -714,7 +733,7 @@ static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
{ {
unsigned long size; unsigned long size;
enum object_type type; enum object_type type;
char *buf = repo_read_object_file(the_repository, oid, &type, &size); char *buf = odb_read_object(the_repository->objects, oid, &type, &size);
unsigned long offset = 0; unsigned long offset = 0;


if (!buf) if (!buf)

Some files were not shown because too many files have changed in this diff Show More