Merge branch 'kk/streaming-walk-pqueue' into kk/no-walk-pathspec-fix

* kk/streaming-walk-pqueue: (280 commits)
  revision: use priority queue for non-limited streaming walks
  revision: introduce rev_walk_mode to clarify get_revision_1()
  pack-objects: call release_revisions() after cruft traversal
  The 9th batch
  The 8th batch
  The 7th batch
  Start preparing for 2.54.1
  The 6th batch
  send-pack: pass negotiation config in push
  remote: add remote.*.negotiationInclude config
  fetch: add --negotiation-include option for negotiation
  negotiator: add have_sent() interface
  remote: add remote.*.negotiationRestrict config
  transport: rename negotiation_tips
  fetch: add --negotiation-restrict option
  t5516: fix test order flakiness
  repack: allow `--write-midx=incremental` without `--geometric`
  repack: introduce `--write-midx=incremental`
  repack: implement incremental MIDX repacking
  packfile: ensure `close_pack_revindex()` frees in-memory revindex
  ...
main
Junio C Hamano 2026-07-16 10:53:00 -07:00
commit bd2943265e
387 changed files with 12555 additions and 9551 deletions

View File

@ -20,7 +20,7 @@ jobs:
jobname: ClangFormat
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
fetch-depth: 0


View File

@ -19,7 +19,7 @@ jobs:
check-whitespace:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
fetch-depth: 0


View File

@ -38,10 +38,10 @@ jobs:
COVERITY_LANGUAGE: cxx
COVERITY_PLATFORM: overridden-below
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: install minimal Git for Windows SDK
if: contains(matrix.os, 'windows')
uses: git-for-windows/setup-git-for-windows-sdk@v1
uses: git-for-windows/setup-git-for-windows-sdk@v2
- run: ci/install-dependencies.sh
if: contains(matrix.os, 'ubuntu') || contains(matrix.os, 'macos')
env:

View File

@ -92,7 +92,7 @@ jobs:
cat git-po-helper.out
exit $exit_code
- name: Create comment in pull request for report
uses: mshick/add-pr-comment@v2
uses: mshick/add-pr-comment@v3
if: >-
always() &&
github.event_name == 'pull_request_target' &&

View File

@ -63,7 +63,7 @@ jobs:
echo "skip_concurrent=$skip_concurrent" >>$GITHUB_OUTPUT
- name: skip if the commit or tree was already tested
id: skip-if-redundant
uses: actions/github-script@v8
uses: actions/github-script@v9
if: steps.check-ref.outputs.enabled == 'yes'
with:
github-token: ${{secrets.GITHUB_TOKEN}}
@ -112,8 +112,8 @@ jobs:
group: windows-build-${{ github.ref }}
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
steps:
- uses: actions/checkout@v5
- uses: git-for-windows/setup-git-for-windows-sdk@v1
- uses: actions/checkout@v6
- uses: git-for-windows/setup-git-for-windows-sdk@v2
- name: build
shell: bash
env:
@ -123,7 +123,7 @@ jobs:
- name: zip up tracked files
run: git archive -o artifacts/tracked.tar.gz HEAD
- name: upload tracked files and build artifacts
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v7
with:
name: windows-artifacts
path: artifacts
@ -140,14 +140,14 @@ jobs:
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
steps:
- name: download tracked files and build artifacts
uses: actions/download-artifact@v6
uses: actions/download-artifact@v8
with:
name: windows-artifacts
path: ${{github.workspace}}
- name: extract tracked files and build artifacts
shell: bash
run: tar xf artifacts.tar.gz && tar xf tracked.tar.gz
- uses: git-for-windows/setup-git-for-windows-sdk@v1
- uses: git-for-windows/setup-git-for-windows-sdk@v2
- name: test
shell: bash
run: . /etc/profile && ci/run-test-slice.sh $((${{matrix.nr}} + 1)) 10
@ -157,7 +157,7 @@ jobs:
run: ci/print-test-failures.sh
- name: Upload failed tests' directories
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v7
with:
name: failed-tests-windows-${{ matrix.nr }}
path: ${{env.FAILED_TEST_ARTIFACTS}}
@ -173,10 +173,10 @@ jobs:
group: vs-build-${{ github.ref }}
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
steps:
- uses: actions/checkout@v5
- uses: git-for-windows/setup-git-for-windows-sdk@v1
- uses: actions/checkout@v6
- uses: git-for-windows/setup-git-for-windows-sdk@v2
- name: initialize vcpkg
uses: actions/checkout@v5
uses: actions/checkout@v6
with:
repository: 'microsoft/vcpkg'
path: 'compat/vcbuild/vcpkg'
@ -186,7 +186,7 @@ jobs:
repository: git/git
definitionId: 9
- name: add msbuild to PATH
uses: microsoft/setup-msbuild@v2
uses: microsoft/setup-msbuild@v3
- name: copy dlls to root
shell: cmd
run: compat\vcbuild\vcpkg_copy_dlls.bat release
@ -208,7 +208,7 @@ jobs:
- name: zip up tracked files
run: git archive -o artifacts/tracked.tar.gz HEAD
- name: upload tracked files and build artifacts
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v7
with:
name: vs-artifacts
path: artifacts
@ -224,9 +224,9 @@ jobs:
group: vs-test-${{ matrix.nr }}-${{ github.ref }}
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
steps:
- uses: git-for-windows/setup-git-for-windows-sdk@v1
- uses: git-for-windows/setup-git-for-windows-sdk@v2
- name: download tracked files and build artifacts
uses: actions/download-artifact@v6
uses: actions/download-artifact@v8
with:
name: vs-artifacts
path: ${{github.workspace}}
@ -244,7 +244,7 @@ jobs:
run: ci/print-test-failures.sh
- name: Upload failed tests' directories
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v7
with:
name: failed-tests-windows-vs-${{ matrix.nr }}
path: ${{env.FAILED_TEST_ARTIFACTS}}
@ -258,7 +258,7 @@ jobs:
group: windows-meson-build-${{ github.ref }}
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
- name: Set up dependencies
shell: pwsh
@ -270,7 +270,7 @@ jobs:
shell: pwsh
run: meson compile -C build
- name: Upload build artifacts
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v7
with:
name: windows-meson-artifacts
path: build
@ -286,13 +286,13 @@ jobs:
group: windows-meson-test-${{ matrix.nr }}-${{ github.ref }}
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
- name: Set up dependencies
shell: pwsh
run: pip install meson ninja
- name: Download build artifacts
uses: actions/download-artifact@v6
uses: actions/download-artifact@v8
with:
name: windows-meson-artifacts
path: build
@ -305,7 +305,7 @@ jobs:
run: ci/print-test-failures.sh
- name: Upload failed tests' directories
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: failed-tests-windows-meson-${{ matrix.nr }}
path: ${{env.FAILED_TEST_ARTIFACTS}}
@ -341,7 +341,7 @@ jobs:
TEST_OUTPUT_DIRECTORY: ${{github.workspace}}/t
runs-on: ${{matrix.vector.pool}}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- run: ci/install-dependencies.sh
- run: ci/run-build-and-tests.sh
- name: print test failures
@ -349,7 +349,7 @@ jobs:
run: ci/print-test-failures.sh
- name: Upload failed tests' directories
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v7
with:
name: failed-tests-${{matrix.vector.jobname}}
path: ${{env.FAILED_TEST_ARTIFACTS}}
@ -362,7 +362,7 @@ jobs:
CI_JOB_IMAGE: ubuntu-latest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- run: ci/install-dependencies.sh
- run: ci/run-build-and-minimal-fuzzers.sh
dockerized:
@ -439,7 +439,7 @@ jobs:
else
apt-get -q update && apt-get -q -y install git
fi
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- run: ci/install-dependencies.sh
- run: useradd builder --create-home
- run: chown -R builder .
@ -449,7 +449,7 @@ jobs:
run: sudo --preserve-env --set-home --user=builder ci/print-test-failures.sh
- name: Upload failed tests' directories
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
uses: actions/upload-artifact@v5
uses: actions/upload-artifact@v7
with:
name: failed-tests-${{matrix.vector.jobname}}
path: ${{env.FAILED_TEST_ARTIFACTS}}
@ -464,7 +464,7 @@ jobs:
group: static-analysis-${{ github.ref }}
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- run: ci/install-dependencies.sh
- run: ci/run-static-analysis.sh
- run: ci/check-directional-formatting.bash
@ -480,7 +480,7 @@ jobs:
group: rust-analysis-${{ github.ref }}
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- run: ci/install-dependencies.sh
- run: ci/run-rust-checks.sh
sparse:
@ -494,7 +494,7 @@ jobs:
group: sparse-${{ github.ref }}
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- name: Install other dependencies
run: ci/install-dependencies.sh
- run: make sparse
@ -510,6 +510,6 @@ jobs:
CI_JOB_IMAGE: ubuntu-latest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- run: ci/install-dependencies.sh
- run: ci/test-documentation.sh

2
.gitignore vendored
View File

@ -71,6 +71,7 @@
/git-for-each-ref
/git-for-each-repo
/git-format-patch
/git-format-rev
/git-fsck
/git-fsck-objects
/git-fsmonitor--daemon
@ -182,6 +183,7 @@
/git-update-server-info
/git-upload-archive
/git-upload-pack
/git-url-parse
/git-var
/git-verify-commit
/git-verify-pack

View File

@ -216,6 +216,30 @@ would be significant, we may decide to defer this change to a subsequent minor
release. This evaluation will also take into account our own experience with
how painful it is to keep Rust an optional component.

* The default value of `safe.bareRepository` will change from `all` to
`explicit`. It is all too easy for an attacker to trick a user into cloning a
repository that contains an embedded bare repository with malicious hooks
configured. If the user enters that subdirectory and runs any Git command, Git
discovers the bare repository and the hooks fire. The user does not even need
to run a Git command explicitly: many shell prompts run `git status` in the
background to display branch and dirty state information, and `git status` in
turn may invoke the fsmonitor hook if so configured, making the user
vulnerable the moment they `cd` into the directory. The `safe.bareRepository`
configuration variable was introduced in 8959555cee (setup_git_directory():
add an owner check for the top-level directory, 2022-03-02) with a default of
`all` to preserve backwards compatibility.
+
Changing the default to `explicit` means that Git will refuse to work with bare
repositories that are discovered implicitly by walking up the directory tree.
Bare repositories specified explicitly via the `--git-dir` command-line option
or the `GIT_DIR` environment variable continue to work regardless of this
setting. Repositories that look like a `.git` directory, a worktree, or a
submodule directory are also unaffected.
+
Users who rely on implicit discovery of bare repositories can restore the
previous behavior by setting `safe.bareRepository=all` in their global or
system configuration.

=== Removals

* Support for grafting commits has long been superseded by git-replace(1).

View File

@ -693,6 +693,12 @@ For C programs:
char *dogs[] = ...;
walk_all_dogs(dogs);

- For file timestamps, do not use "st_mtim" (and other timestamp
members in "struct stat") unconditionally; not everybody is POSIX
(grep for USE_ST_TIMESPEC). If you only need a timestamp in whole
second resolution, "st_mtime" should work fine everywhere.


For Perl programs:

- Most of the C guidelines above apply.

View File

@ -0,0 +1,29 @@
Git v2.54.1 Release Notes
=========================

This release is primarily to merge fixes accumulated on the 'master'
front to prepare for 2.55 release that are still relevant to 2.54.x
maintenance track.

Fixes since v2.54
-----------------

* Headers from glibc 2.43 when used with clang does not allow
disabling C11 language features, causing build failures..

* Revert a recent change that introduced a regression to help mksh users.

* Update various GitHub Actions versions.

* Avoid hitting the pathname limit for socks proxy socket during the
test.

* To help Windows 10 installations, avoid removing files whose
contents are still mmap()'ed.

* Stop using unmaintained custom allocator in Windows build which was
the last user of the code.

* Further update to the i18n alias support to avoid regressions.

Also contains minor documentation updates and code clean-ups.

View File

@ -0,0 +1,226 @@
Git v2.55 Release Notes
=======================

UI, Workflows & Features
------------------------

* Hook scripts defined via the configuration system can now be
configured to run in parallel.

* The userdiff driver for the Scheme language has been extended to
cover other Lisp dialects.

* Terminal control sequences coming over the sideband while talking
to a remote repository are mostly disabled by default, except for
ANSI color escape sequences.

* "ort" merge backend improvements.

* "git checkout -m another-branch" was invented to deal with local
changes to paths that are different between the current and the new
branch, but it gave only one chance to resolve conflicts. The command
was taught to create a stash to save the local changes.

* A new builtin "git format-rev" is introduced for pretty formatting
one revision expression per line or commit object names found in
running text.

* "git history" learned "fixup" command.

* The internal URL parsing logic has been made accessible via a new
subcommand "git url-parse".

* Misspelt proxy URL (e.g., httt://...) did not trigger any warning
or failure, which has been corrected.

* Document the fact that .git/info/exclude is shared across worktrees
linked to the same repository.

* The command line parser for "git diff" learned a few options take
only non-negative integers.


Performance, Internal Implementation, Development Support etc.
--------------------------------------------------------------

* Promisor remote handling has been refactored and fixed in
preparation for auto-configuration of advertised remotes.

* Rust support is enabled by default (but still allows opting out) in
some future version of Git.

* Preparation of the xdiff/ codebase to work with Rust.

* Use a larger buffer size in the code paths to ingest pack stream.

* Refactor service routines in the ref subsystem backends.

* Shrink wasted memory in Myers diff that does not account for common
prefix and suffix removal.

* Enable expensive tests to catch topics that may cause breakages on
integration branches closer to their origin in the contributor PR
builds.

* "git merge-base" optimization.

* The limit_list() function that is one of the core part of the
revision traversal infrastructure has been optimized by replacing
its use of linear list with priority queue.

* In a lazy clone, "git cherry" and "git grep" often fetch necessary
blob objects one by one from promisor remotes. It has been corrected
to collect necessary object names and fetch them in bulk to gain
reasonable performance.

* The logic to determine that branches in an octopus merge are
independent has been optimized.

* The consistency checks for the files reference backend have been updated
to skip lock files earlier, avoiding unnecessary parsing of
intermediate files.

* The negotiation tip options in "git fetch" have been reworked to
allow requiring certain refs to be sent as "have" lines, and to
restrict negotiation to a specific set of refs.

* The repacking code has been refactored and compaction of MIDX layers
have been implemented, and incremental strategy that does not require
all-into-one repacking has been introduced.

* ODB transaction interface is being reworked to explicitly handle
object writes.

* Add a new odb "in-memory" source that is meant to only hold
tentative objects (like the virtual blob object that represents the
working tree file used by "git blame").

* Many uses of the_repository has been updated to use a more
appropriate struct repository instance in setup.c codepath.


Fixes since v2.54
-----------------

* Code clean-up to use the right instance of a repository instance in
calls inside refs subsystem.
(merge 57c590feb9 sp/refs-reduce-the-repository later to maint).

* The check that implements the logic to see if an in-core cache-tree
is fully ready to write out a tree object was broken, which has
been corrected.
(merge 521731213c dl/cache-tree-fully-valid-fix later to maint).

* The test suite harness and many individual test scripts have been
updated to work correctly when 'set -e' is in effect, which helps
detect misspelled test commands.
(merge ffe8005b9d ps/test-set-e-clean later to maint).

* Revert a recent change that introduced a regression to help mksh users.

* Update various GitHub Actions versions.

* Avoid hitting the pathname limit for socks proxy socket during the
test..

* To help Windows 10 installations, avoid removing files whose
contents are still mmap()'ed.

* The 'git backfill' command now rejects revision-limiting options that
are incompatible with its operation, uses standard documentation for
revision ranges, and includes blobs from boundary commits by default
to improve performance of subsequent operations.
(merge a1ad4a0fca en/backfill-fixes-and-edges later to maint).

* "git grep" update.
(merge 9ff4b5ab1b rs/grep-column-only-match-fix later to maint).

* Headers from glibc 2.43 when used with clang does not allow
disabling C11 language features, causing build failures..

* The 'http.emptyAuth=auto' configuration now correctly attempts
Negotiate authentication before falling back to manual credentials.
This allows seamless Kerberos ticket-based authentication without
requiring users to explicitly set 'http.emptyAuth=true'.
(merge 4919938d28 mc/http-emptyauth-negotiate-fix later to maint).

* Ramifications of turning off commit-graph has been documented a bit
more clearly.
(merge 48c855bb8f kh/doc-commit-graph later to maint).

* "git rebase --update-refs", when used with an rebase.instructionFormat
with "%d" (describe) in it, tried to update local branch HEAD by
mistake, which has been corrected.
(merge 106b6885c7 ag/rebase-update-refs-limit-to-branches later to maint).

* Tweak the way how sideband messages from remote are printed while
we talk with a remote repository to avoid tickling terminal
emulator glitches.
(merge 31e8fcabd8 rs/sideband-clear-line-before-print later to maint).

* The configuration variable submodule.fetchJobs was not read correctly,
which has been corrected.
(merge aa45a5902f sj/submodule-update-clone-config-fix later to maint).

* Update code paths that assumed "unsigned long" was long enough for
"size_t".
(merge 7a094d68a2 js/objects-larger-than-4gb-on-windows later to maint).

* Stop using unmaintained custom allocator in Windows build which was
the last user of the code.

* The computation to shorten the filenames shown in diffstat measured
width of individual UTF-8 characters to add up, but forgot to take
into account error cases (e.g., an invalid UTF-8 sequence, or a
control character).
(merge 09d86a3b98 en/diffstat-utf8-truncation-fix later to maint).

* Some tests assume that bare repository accesses are by default
allowed; rewrite some of them to avoid the assumption, rewrite
others to explicitly set safe.bareRepository to allow them.
(merge 985b38ca6c js/adjust-tests-to-explicitly-access-bare-repo later to maint).

* Signing commit with custom encoding was passing the data to be
signed at a wrong stage in the pipeline, which has been corrected.
(merge 7735d7eee3 bc/sign-commit-with-custom-encoding later to maint).

* Further update to the i18n alias support to avoid regressions.

* "git fetch --deepen=<n>" in a full clone truncated the history to <n>
commits deep, which has been corrected to be a no-op instead.
(merge 2431f5e0e5 sp/shallow-deepen-on-non-shallow-repo-fix later to maint).

* "git maintenance" that goes background did not use the lockfile to
prevent multiple maintenance processes from running at the same
time, which has been corrected.
(merge 29364f1624 ps/maintenance-daemonize-lockfix later to maint).

* Remove ineffective strbuf presizing that would have computed an
allocation that would not have fit in the available memory anyway,
or too small due to integer wraparound to cause immediate automatic
growing.
(merge a9ce8526dc jk/pretty-no-strbuf-presizing later to maint).

* The HTTP walker misinterpreted the alternates file that gives an
absolute path when the server URL does not have the final slash
(i.e., "https://example.com" not "https://example.com/").
(merge b92387cd55 jk/dumb-http-alternate-fix later to maint).

* Other code cleanup, docfix, build fix, etc.
(merge 80f4b802e9 ja/doc-difftool-synopsis-style later to maint).
(merge b96490241e jc/doc-timestamps-in-stat later to maint).
(merge ef85286e51 ss/t7004-unhide-git-failures later to maint).
(merge 7584d10bc2 mf/format-patch-cover-letter-format-docfix later to maint).
(merge 8547908eb3 pw/rename-to-get-current-worktree later to maint).
(merge 890229b3f3 sg/t6112-unwanted-tilde-expansion-fix later to maint).
(merge ab9753e7bc kh/doc-restore-double-underscores-fix later to maint).
(merge 4a9e097228 za/t2000-modernise-more later to maint).
(merge b635fd0725 kh/doc-log-decorate-list later to maint).
(merge 65ea197dca jk/commit-sign-overflow-fix later to maint).
(merge 3ccb16052a jk/apply-leakfix later to maint).
(merge 5e6e8dc786 tb/pseudo-merge-bugfixes later to maint).
(merge 6d09e798bc pb/doc-diff-format-updates later to maint).
(merge 34a891a2d3 rs/trailer-fold-optim later to maint).
(merge 499f9048e0 ps/t3903-cover-stash-include-untracked later to maint).
(merge b56ab270aa jk/sq-dequote-cleanup later to maint).
(merge 29d9fdcf10 rs/use-builtin-add-overflow-explicitly-on-clang later to maint).

View File

@ -523,6 +523,8 @@ include::config/sequencer.adoc[]

include::config/showbranch.adoc[]

include::config/sideband.adoc[]

include::config/sparse.adoc[]

include::config/splitindex.adoc[]

View File

@ -47,8 +47,8 @@ will be updated more often than a reference pointing at an old commit.
bitmapPseudoMerge.<name>.sampleRate::
Determines the proportion of non-bitmapped commits (among
reference tips) which are selected for inclusion in an
unstable pseudo-merge bitmap. Must be between `0` and `1`
(inclusive). The default is `1`.
unstable pseudo-merge bitmap. Must be greater than `0` and
less than or equal to `1`. The default is `1`.

bitmapPseudoMerge.<name>.threshold::
Determines the minimum age of non-bitmapped commits (among

View File

@ -1,43 +1,43 @@
diff.tool::
`diff.tool`::
Controls which diff tool is used by linkgit:git-difftool[1].
This variable overrides the value configured in `merge.tool`.
The list below shows the valid built-in values.
Any other value is treated as a custom diff tool and requires
that a corresponding difftool.<tool>.cmd variable is defined.
that a corresponding `difftool.<tool>.cmd` variable is defined.

diff.guitool::
`diff.guitool`::
Controls which diff tool is used by linkgit:git-difftool[1] when
the -g/--gui flag is specified. This variable overrides the value
the `-g`/`--gui` flag is specified. This variable overrides the value
configured in `merge.guitool`. The list below shows the valid
built-in values. Any other value is treated as a custom diff tool
and requires that a corresponding difftool.<guitool>.cmd variable
and requires that a corresponding `difftool.<guitool>.cmd` variable
is defined.

include::{build_dir}/mergetools-diff.adoc[]

difftool.<tool>.cmd::
`difftool.<tool>.cmd`::
Specify the command to invoke the specified diff tool.
The specified command is evaluated in shell with the following
variables available: 'LOCAL' is set to the name of the temporary
file containing the contents of the diff pre-image and 'REMOTE'
variables available: `LOCAL` is set to the name of the temporary
file containing the contents of the diff pre-image and `REMOTE`
is set to the name of the temporary file containing the contents
of the diff post-image.
+
See the `--tool=<tool>` option in linkgit:git-difftool[1] for more details.

difftool.<tool>.path::
`difftool.<tool>.path`::
Override the path for the given tool. This is useful in case
your tool is not in the PATH.

difftool.trustExitCode::
`difftool.trustExitCode`::
Exit difftool if the invoked diff tool returns a non-zero exit status.
+
See the `--trust-exit-code` option in linkgit:git-difftool[1] for more details.

difftool.prompt::
`difftool.prompt`::
Prompt before each invocation of the diff tool.

difftool.guiDefault::
`difftool.guiDefault`::
Set `true` to use the `diff.guitool` by default (equivalent to specifying
the `--gui` argument), or `auto` to select `diff.guitool` or `diff.tool`
depending on the presence of a `DISPLAY` environment variable value. The

View File

@ -76,7 +76,7 @@
default is `skipping`. Unknown values will cause `git fetch` to
error out.
+
See also the `--negotiate-only` and `--negotiation-tip` options to
See also the `--negotiate-only` and `--negotiation-restrict` options to
linkgit:git-fetch[1].

`fetch.showForcedUpdates`::

View File

@ -102,7 +102,7 @@ format.coverLetter::
Default is false.

format.commitListFormat::
When the `--cover-letter-format` option is not given, `format-patch`
When the `--commit-list-format` option is not given, `format-patch`
uses the value of this variable to decide how to format the entry of
each commit. Defaults to `shortlog`.


View File

@ -15,6 +15,12 @@ hook.<friendly-name>.event::
events, specify the key more than once. An empty value resets
the list of events, clearing any previously defined events for
`hook.<friendly-name>`. See linkgit:git-hook[1].
+
The `<friendly-name>` must not be the same as a known hook event name
(e.g. do not use `hook.pre-commit.event`). Using a known event name as
a friendly-name is a fatal error because it creates an ambiguity with
`hook.<event>.enabled` and `hook.<event>.jobs`. For unknown event names,
a warning is issued when `<friendly-name>` matches the event value.

hook.<friendly-name>.enabled::
Whether the hook `hook.<friendly-name>` is enabled. Defaults to `true`.
@ -22,3 +28,73 @@ hook.<friendly-name>.enabled::
configuration. This is particularly useful when a hook is defined
in a system or global config file and needs to be disabled for a
specific repository. See linkgit:git-hook[1].

hook.<friendly-name>.parallel::
Whether the hook `hook.<friendly-name>` may run in parallel with other hooks
for the same event. Defaults to `false`. Set to `true` only when the
hook script is safe to run concurrently with other hooks for the same
event. If any hook for an event does not have this set to `true`,
all hooks for that event run sequentially regardless of `hook.jobs`.
Only configured (named) hooks need to declare this. Traditional hooks
found in the hooks directory do not need to, and run in parallel when
the effective job count is greater than 1. See linkgit:git-hook[1].

hook.<event>.enabled::
Switch to enable or disable all hooks for the `<event>` hook event.
When set to `false`, no hooks fire for that event, regardless of any
per-hook `hook.<friendly-name>.enabled` settings. Defaults to `true`.
See linkgit:git-hook[1].
+
Note on naming: `<event>` must be the event name (e.g. `pre-commit`),
not a hook friendly-name. Since using a known event name as a
friendly-name is disallowed (see `hook.<friendly-name>.event` above),
there is no ambiguity between event-level and per-hook `.enabled`
settings for known events. For unknown events, if a friendly-name
matches the event name despite the warning, `.enabled` is treated
as per-hook only.

hook.<event>.jobs::
Specifies how many hooks can be run simultaneously for the `<event>`
hook event (e.g. `hook.post-receive.jobs = 4`). Overrides `hook.jobs`
for this specific event. The same parallelism restrictions apply: this
setting has no effect unless all configured hooks for the event have
`hook.<friendly-name>.parallel` set to `true`. Set to `-1` to use the
number of available CPU cores. Must be a positive integer or `-1`;
zero is rejected with a warning. See linkgit:git-hook[1].
+
Note on naming: although this key resembles `hook.<friendly-name>.*`
(a per-hook setting), `<event>` must be the event name, not a hook
friendly name. The key component is stored literally and looked up by
event name at runtime with no translation between the two namespaces.
A key like `hook.my-hook.jobs` is stored under `"my-hook"` but the
lookup at runtime uses the event name (e.g. `"post-receive"`), so
`hook.my-hook.jobs` is silently ignored even when `my-hook` is
registered for that event. Use `hook.post-receive.jobs` or any other
valid event name when setting `hook.<event>.jobs`.

hook.jobs::
Specifies how many hooks can be run simultaneously during parallelized
hook execution. If unspecified, defaults to 1 (serial execution).
Set to `-1` to use the number of available CPU cores.
Can be overridden on a per-event basis with `hook.<event>.jobs`.
Some hooks always run sequentially regardless of this setting because
they operate on shared data and cannot safely be parallelized:
+
--
`applypatch-msg`;;
`prepare-commit-msg`;;
`commit-msg`;;
Receive a commit message file and may rewrite it in place.
`pre-commit`;;
`post-checkout`;;
`push-to-checkout`;;
`post-commit`;;
Access the working tree, index, or repository state.
--
+
This setting has no effect unless all configured hooks for the event have
`hook.<friendly-name>.parallel` set to `true`.
+
For `pre-push` hooks, which normally keep stdout and stderr separate,
setting this to a value greater than 1 (or passing `-j`) will merge stdout
into stderr to allow correct de-interleaving of parallel output.

View File

@ -59,7 +59,18 @@ http.emptyAuth::
Attempt authentication without seeking a username or password. This
can be used to attempt GSS-Negotiate authentication without specifying
a username in the URL, as libcurl normally requires a username for
authentication.
authentication. Possible values are:
+
--
* `auto` (default) - Send empty credentials only if the server's 401 response
advertises an authentication mechanism that requires them (such as
GSS-Negotiate); otherwise fall back to prompting via the credential helper.
* `true` - Always send empty credentials on the very first request, before
receiving any 401 response from the server.
* `false` - Never send empty credentials. Mechanisms that require
empty credentials or an explicit username, such as GSS-Negotiate, will not
work.
--

http.proactiveAuth::
Attempt authentication without first making an unauthenticated attempt and

View File

@ -52,13 +52,13 @@
if `merge.tool` is configured as _<variant>_), Git will consult
`mergetool.<variant>.layout` to determine the tool's layout. If the
variant-specific configuration is not available, `vimdiff` ' s is used as
fallback. If that too is not available, a default layout with 4 windows
will be used. To configure the layout, see the 'BACKEND SPECIFIC HINTS'
fallback. If that too is not available, a default layout with 4 windows
will be used.
ifdef::git-mergetool[]
section.
To configure the layout, see the 'BACKEND SPECIFIC HINTS' section.
endif::[]
ifndef::git-mergetool[]
section in linkgit:git-mergetool[1].
To configure the layout, see the 'BACKEND SPECIFIC HINTS' section in linkgit:git-mergetool[1].
endif::[]

`mergetool.hideResolved`::

View File

@ -107,6 +107,55 @@ priority configuration file (e.g. `.git/config` in a repository) to clear
the values inherited from a lower priority configuration files (e.g.
`$HOME/.gitconfig`).

remote.<name>.negotiationRestrict::
When negotiating with this remote during `git fetch`, restrict the
commits advertised as "have" lines to only those reachable from refs
matching the given patterns. This multi-valued config option behaves
like `--negotiation-restrict` on the command line.
+
Each value is either an exact ref name (e.g. `refs/heads/release`) or a
glob pattern (e.g. `refs/heads/release/*`). The pattern syntax is the
same as for `--negotiation-restrict`.
+
These config values are used as defaults for the `--negotiation-restrict`
command-line option. If `--negotiation-restrict` (or its synonym
`--negotiation-tip`) is specified on the command line, then the config
values are not used.
+
These values also influence negotiation during `git push` if
`push.negotiate` is enabled.
+
Blank values signal to ignore all previous values, allowing a reset of
the list from broader config scenarios.

remote.<name>.negotiationInclude::
When negotiating with this remote during `git fetch`, the client
advertises a list of commits that exist locally. In repos with
many references, this list of "haves" can be truncated. Depending
on data shape, dropping certain references may be expensive. This
multi-valued config option specifies references, commit hashes,
or ref pattern globs whose tips should always be sent as "have"
commits during fetch negotiation with this remote.
+
Each value is either an exact ref name (e.g. `refs/heads/release`), a
commit hash, or a glob pattern (e.g. `refs/heads/release/*`). The
pattern syntax is the same as for `--negotiation-include`.
+
These config values are used as defaults for the `--negotiation-include`
command-line option. If `--negotiation-include` is specified on the
command line, then the config values are not used.
+
This option is additive with the normal negotiation process: the
negotiation algorithm still runs and advertises its own selected commits,
but the refs matching `remote.<name>.negotiationInclude` are sent
unconditionally on top of those heuristically selected commits.
+
These values also influence negotiation during `git push` if
`push.negotiate` is enabled.
+
Blank values signal to ignore all previous values, allowing a reset of
the list from broader config scenarios.

remote.<name>.followRemoteHEAD::
How linkgit:git-fetch[1] should handle updates to `remotes/<name>/HEAD`
when fetching using the configured refspecs of a remote.

View File

@ -46,3 +46,21 @@ repack.midxMustContainCruft::
`--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.

repack.midxSplitFactor::
The factor used in the geometric merging condition when
compacting incremental MIDX layers during `git repack` when
invoked with the `--write-midx=incremental` option.
+
Adjacent layers are merged when the accumulated object count of the
newer layer exceeds `1/<N>` of the object count of the next deeper
layer. Must be at least 2. Defaults to 2.

repack.midxNewLayerThreshold::
The minimum number of packs in the tip MIDX layer before those
packs are considered as candidates for geometric repacking
during `git repack --write-midx=incremental`.
+
When the tip layer has fewer packs than this threshold, those packs are
excluded from the geometric repack entirely, and are thus left
unmodified. Must be at least 1. Defaults to 8.

View File

@ -2,10 +2,12 @@ safe.bareRepository::
Specifies which bare repositories Git will work with. The currently
supported values are:
+
* `all`: Git works with all bare repositories. This is the default.
* `all`: Git works with all bare repositories. This is the default in
Git 2.x.
* `explicit`: Git only works with bare repositories specified via
the top-level `--git-dir` command-line option, or the `GIT_DIR`
environment variable (see linkgit:git[1]).
environment variable (see linkgit:git[1]). This will be the default
in Git 3.0.
+
If you do not use bare repositories in your workflow, then it may be
beneficial to set `safe.bareRepository` to `explicit` in your global
@ -13,6 +15,10 @@ config. This will protect you from attacks that involve cloning a
repository that contains a bare repository and running a Git command
within that directory.
+
If you use bare repositories regularly and want to preserve the current
behavior after upgrading to Git 3.0, set `safe.bareRepository` to `all`
in your global or system config.
+
This config setting is only respected in protected configuration (see
<<SCOPES>>). This prevents untrusted repositories from tampering with
this value.

View File

@ -0,0 +1,27 @@
sideband.allowControlCharacters::
By default, control characters that are delivered via the sideband
are masked, except ANSI color sequences. This prevents potentially
unwanted ANSI escape sequences from being sent to the terminal. Use
this config setting to override this behavior (the value can be
a comma-separated list of the following keywords):
+
--
`color`::
Allow ANSI color sequences, line feeds and horizontal tabs,
but mask all other control characters. This is the default.
`cursor:`:
Allow control sequences that move the cursor. This is
disabled by default.
`erase`::
Allow control sequences that erase charactrs. This is
disabled by default.
`false`::
Mask all control characters other than line feeds and
horizontal tabs.
`true`::
Allow all control characters to be sent to the terminal.
--

sideband.<url>.*::
Apply the `sideband.*` option selectively to specific URLs. The
same URL matching logic applies as for `http.<url>.*` settings.

View File

@ -19,9 +19,9 @@ compared differs:
`git-diff-files [<pattern>...]`::
compares the index and the files on the filesystem.

The `git-diff-tree` command begins its output by printing the hash of
what is being compared. After that, all the commands print one output
line per changed file.
All the commands print one output line per changed file,
except `git diff-files` in the case of an unmerged file, which prints
both an "unmerged" and an "in-place edit" line.

An output line is formatted this way:

@ -37,13 +37,13 @@ unmerged :000000 000000 0000000 0000000 U file6
That is, from the left to the right:

. a colon.
. mode for "src"; 000000 if creation or unmerged.
. mode for "src"; 000000 if creation, or if "src" is from the index and is unmerged.
. a space.
. mode for "dst"; 000000 if deletion or unmerged.
. mode for "dst"; 000000 if deletion, or if "dst" is from the index and is unmerged.
. a space.
. sha1 for "src"; 0\{40\} if creation or unmerged.
. sha1 for "src"; 0\{40\} if creation, or if "src" is from the index and is unmerged.
. a space.
. sha1 for "dst"; 0\{40\} if deletion, unmerged or "work tree out of sync with the index".
. sha1 for "dst"; 0\{40\} if deletion, if "dst" is from the index and is unmerged, or if "dst" is from the work tree and is out of sync with the index.
. a space.
. status, followed by optional "score" number.
. a tab or a NUL when `-z` option is used.

View File

@ -49,6 +49,7 @@ the current repository has the same history as the source repository.
`.git/shallow`. This option updates `.git/shallow` and accepts such
refs.

`--negotiation-restrict=(<commit>|<glob>)`::
`--negotiation-tip=(<commit>|<glob>)`::
By default, Git will report, to the server, commits reachable
from all local refs to find common commits in an attempt to
@ -58,6 +59,9 @@ the current repository has the same history as the source repository.
local ref is likely to have commits in common with the
upstream ref being fetched.
+
`--negotiation-restrict` is the preferred name for this option;
`--negotiation-tip` is accepted as a synonym.
+
This option may be specified more than once; if so, Git will report
commits reachable from any of the given commits.
+
@ -69,9 +73,32 @@ See also the `fetch.negotiationAlgorithm` and `push.negotiate`
configuration variables documented in linkgit:git-config[1], and the
`--negotiate-only` option below.

`--negotiation-include=(<commit>|<glob>)`::
Ensure that the commits at the given tips are always sent as "have"
lines during fetch negotiation, regardless of what the negotiation
algorithm selects. This is useful to guarantee that common
history reachable from specific refs is always considered, even
when `--negotiation-restrict` restricts the set of tips or when
the negotiation algorithm would otherwise skip them.
+
This option may be specified more than once; if so, each commit is sent
unconditionally.
+
The argument may be an exact ref name (e.g. `refs/heads/release`), an
object hash, or a glob pattern (e.g. `refs/heads/release/{asterisk}`).
The pattern syntax is the same as for `--negotiation-restrict`.
+
If `--negotiation-restrict` is used, the have set is first restricted by
that option and then increased to include the tips specified by
`--negotiation-include`.
+
If this option is not specified on the command line, then any
`remote.<name>.negotiationInclude` config values for the current remote
are used instead.

`--negotiate-only`::
Do not fetch anything from the server, and instead print the
ancestors of the provided `--negotiation-tip=` arguments,
ancestors of the provided `--negotiation-restrict=` arguments,
which we have in common with the server.
+
This is incompatible with `--recurse-submodules=(yes|on-demand)`.

View File

@ -9,7 +9,7 @@ git-backfill - Download missing objects in a partial clone
SYNOPSIS
--------
[synopsis]
git backfill [--min-batch-size=<n>] [--[no-]sparse]
git backfill [--min-batch-size=<n>] [--[no-]sparse] [--[no-]include-edges] [<revision-range>]

DESCRIPTION
-----------
@ -43,7 +43,7 @@ smaller network calls than downloading the entire repository at clone
time.

By default, `git backfill` downloads all blobs reachable from the `HEAD`
commit. This set can be restricted or expanded using various options.
commit. This set can be restricted or expanded using various options below.

THIS COMMAND IS EXPERIMENTAL. ITS BEHAVIOR MAY CHANGE IN THE FUTURE.

@ -63,7 +63,23 @@ OPTIONS
current sparse-checkout. If the sparse-checkout feature is enabled,
then `--sparse` is assumed and can be disabled with `--no-sparse`.

You may also specify the commit limiting options from linkgit:git-rev-list[1].
`--include-edges`::
`--no-include-edges`::
Include blobs from boundary commits in the backfill. Useful in
preparation for commands like `git log -p A..B` or `git replay
--onto TARGET A..B`, where A..B normally excludes A but you need
the blobs from A as well. `--include-edges` is the default.

`<revision-range>`::
Backfill only blobs reachable from commits in the specified
revision range. When no _<revision-range>_ is specified, it
defaults to `HEAD` (i.e. the whole history leading to the
current commit). For a complete list of ways to spell
_<revision-range>_, see the "Specifying Ranges" section of
linkgit:gitrevisions[7].
+
You may also use commit-limiting options understood by
linkgit:git-rev-list[1] such as `--first-parent`, `--since`, or pathspecs.

SEE ALSO
--------

View File

@ -251,20 +251,19 @@ working tree, by copying them from elsewhere, extracting a tarball, etc.
are different between the current branch and the branch to
which you are switching, the command refuses to switch
branches in order to preserve your modifications in context.
However, with this option, a three-way merge between the current
branch, your working tree contents, and the new branch
is done, and you will be on the new branch.
+
When a merge conflict happens, the index entries for conflicting
paths are left unmerged, and you need to resolve the conflicts
and mark the resolved paths with `git add` (or `git rm` if the merge
should result in deletion of the path).
With this option, the conflicting local changes are
automatically stashed before the switch and reapplied
afterwards. If the local changes do not overlap with the
differences between branches, the switch proceeds without
stashing. If reapplying the stash results in conflicts, the
entry is saved to the stash list. Resolve the conflicts
and run `git stash drop` when done, or clear the working
tree (e.g. with `git reset --hard`) before running `git stash
pop` later to re-apply your changes.
+
When checking out paths from the index, this option lets you recreate
the conflicted merge in the specified paths. This option cannot be
used when checking out paths from a tree-ish.
+
When switching branches with `--merge`, staged changes may be lost.

`--conflict=<style>`::
The same as `--merge` option above, but changes the way the
@ -578,38 +577,36 @@ $ git checkout mytopic
error: You have local changes to 'frotz'; not switching branches.
------------

You can give the `-m` flag to the command, which would try a
three-way merge:
You can give the `-m` flag to the command, which will carry your local
changes to the new branch:

------------
$ git checkout -m mytopic
Auto-merging frotz
Applied autostash.
Switched to branch 'mytopic'
The following paths have local changes:
M frotz
------------

After this three-way merge, the local modifications are _not_
After the switch, the local modifications are reapplied and are _not_
registered in your index file, so `git diff` would show you what
changes you made since the tip of the new branch.

=== 3. Merge conflict

When a merge conflict happens during switching branches with
the `-m` option, you would see something like this:
When the `--merge` (`-m`) option is given and the local changes
overlap with the changes in the branch we're switching to, the
changes are stashed and reapplied after the switch. If this
process results in conflicts, the stash entry is saved and a
message is printed:

------------
$ git checkout -m mytopic
Auto-merging frotz
ERROR: Merge conflict in frotz
fatal: merge program failed
------------

At this point, `git diff` shows the changes cleanly merged as in
the previous example, as well as the changes in the conflicted
files. Edit and resolve the conflict and mark it resolved with
`git add` as usual:

------------
$ edit frotz
$ git add frotz
Your local changes are stashed, however applying them
resulted in conflicts. You can either resolve the conflicts
and then discard the stash with "git stash drop", or, if you
do not want to resolve them now, run "git reset --hard" and
apply the local changes later by running "git stash pop".
------------

CONFIGURATION

View File

@ -146,6 +146,12 @@ $ git show-ref -s | git commit-graph write --stdin-commits
$ git rev-parse HEAD | git commit-graph write --stdin-commits --append
------------------------------------------------

CAVEATS
-------

The existence of replace objects or commit grafts turns off reading or
writing to the commit-graph. See linkgit:git-replace[1].

CONFIGURATION
-------------


View File

@ -7,10 +7,10 @@ git-describe - Give an object a human readable name based on an available ref

SYNOPSIS
--------
[verse]
'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] [<commit-ish>...]
'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]
'git describe' <blob>
[synopsis]
git describe [--all] [--tags] [--contains] [--abbrev=<n>] [<commit-ish>...]
git describe [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]
git describe <blob>

DESCRIPTION
-----------
@ -22,70 +22,70 @@ abbreviated object name of the most recent commit. The result
is a "human-readable" object name which can also be used to
identify the commit to other git commands.

By default (without --all or --tags) `git describe` only shows
By default (without `--all` or `--tags`) `git describe` only shows
annotated tags. For more information about creating annotated tags
see the -a and -s options to linkgit:git-tag[1].
see the `-a` and `-s` options to linkgit:git-tag[1].

If the given object refers to a blob, it will be described
as `<commit-ish>:<path>`, such that the blob can be found
at `<path>` in the `<commit-ish>`, which itself describes the
at _<path>_ in the _<commit-ish>_, which itself describes the
first commit in which this blob occurs in a reverse revision walk
from HEAD.
from `HEAD`.

OPTIONS
-------
<commit-ish>...::
Commit-ish object names to describe. Defaults to HEAD if omitted.
`<commit-ish>...`::
Commit-ish object names to describe. Defaults to `HEAD` if omitted.

--dirty[=<mark>]::
--broken[=<mark>]::
`--dirty[=<mark>]`::
`--broken[=<mark>]`::
Describe the state of the working tree. When the working
tree matches HEAD, the output is the same as "git describe
HEAD". If the working tree has local modification "-dirty"
tree matches `HEAD`, the output is the same as `git describe HEAD`.
If the working tree has local modification, `-dirty`
is appended to it. If a repository is corrupt and Git
cannot determine if there is local modification, Git will
error out, unless `--broken' is given, which appends
the suffix "-broken" instead.
error out, unless `--broken` is given, which appends
the suffix `-broken` instead.

--all::
`--all`::
Instead of using only the annotated tags, use any ref
found in `refs/` namespace. This option enables matching
any known branch, remote-tracking branch, or lightweight tag.

--tags::
`--tags`::
Instead of using only the annotated tags, use any tag
found in `refs/tags` namespace. This option enables matching
a lightweight (non-annotated) tag.

--contains::
`--contains`::
Instead of finding the tag that predates the commit, find
the tag that comes after the commit, and thus contains it.
Automatically implies --tags.
Automatically implies `--tags`.

--abbrev=<n>::
`--abbrev=<n>`::
Instead of using the default number of hexadecimal digits (which
will vary according to the number of objects in the repository with
a default of 7) of the abbreviated object name, use <n> digits, or
as many digits as needed to form a unique object name. An <n> of 0
a default of 7) of the abbreviated object name, use _<n>_ digits, or
as many digits as needed to form a unique object name. An _<n>_ of 0
will suppress long format, only showing the closest tag.

--candidates=<n>::
`--candidates=<n>`::
Instead of considering only the 10 most recent tags as
candidates to describe the input commit-ish consider
up to <n> candidates. Increasing <n> above 10 will take
up to _<n>_ candidates. Increasing _<n>_ above 10 will take
slightly longer but may produce a more accurate result.
An <n> of 0 will cause only exact matches to be output.
An _<n>_ of 0 will cause only exact matches to be output.

--exact-match::
`--exact-match`::
Only output exact matches (a tag directly references the
supplied commit). This is a synonym for --candidates=0.
supplied commit). This is a synonym for `--candidates=0`.

--debug::
`--debug`::
Verbosely display information about the searching strategy
being employed to standard error. The tag name will still
be printed to standard out.

--long::
`--long`::
Always output the long format (the tag, the number of commits
and the abbreviated commit name) even when it matches a tag.
This is useful when you want to see parts of the commit object name
@ -94,8 +94,8 @@ OPTIONS
describe such a commit as v1.2-0-gdeadbee (0th commit since tag v1.2
that points at object deadbee....).

--match <pattern>::
Only consider tags matching the given `glob(7)` pattern,
`--match <pattern>`::
Only consider tags matching the given `glob`(7) pattern,
excluding the "refs/tags/" prefix. If used with `--all`, it also
considers local branches and remote-tracking references matching the
pattern, excluding respectively "refs/heads/" and "refs/remotes/"
@ -104,22 +104,22 @@ OPTIONS
matching any of the patterns will be considered. Use `--no-match` to
clear and reset the list of patterns.

--exclude <pattern>::
Do not consider tags matching the given `glob(7)` pattern, excluding
`--exclude <pattern>`::
Do not consider tags matching the given `glob`(7) pattern, excluding
the "refs/tags/" prefix. If used with `--all`, it also does not consider
local branches and remote-tracking references matching the pattern,
excluding respectively "refs/heads/" and "refs/remotes/" prefix;
excluding respectively "`refs/heads/`" and "`refs/remotes/`" prefix;
references of other types are never considered. If given multiple times,
a list of patterns will be accumulated and tags matching any of the
patterns will be excluded. When combined with --match a tag will be
considered when it matches at least one --match pattern and does not
match any of the --exclude patterns. Use `--no-exclude` to clear and
patterns will be excluded. When combined with `--match` a tag will be
considered when it matches at least one `--match` pattern and does not
match any of the `--exclude` patterns. Use `--no-exclude` to clear and
reset the list of patterns.

--always::
`--always`::
Show uniquely abbreviated commit object as fallback.

--first-parent::
`--first-parent`::
Follow only the first parent commit upon seeing a merge commit.
This is useful when you wish to not match tags on branches merged
in the history of the target commit.
@ -139,8 +139,8 @@ an abbreviated object name for the commit itself ("2414721")
at the end.

The number of additional commits is the number
of commits which would be displayed by "git log v1.0.4..parent".
The hash suffix is "-g" + an unambiguous abbreviation for the tip commit
of commits which would be displayed by `git log v1.0.4..parent`.
The hash suffix is "`-g`" + an unambiguous abbreviation for the tip commit
of parent (which was `2414721b194453f058079d897d13c4e377f92dc6`). The
length of the abbreviation scales as the repository grows, using the
approximate number of objects in the repository and a bit of math
@ -149,12 +149,12 @@ The "g" prefix stands for "git" and is used to allow describing the version of
a software depending on the SCM the software is managed with. This is useful
in an environment where people may use different SCMs.

Doing a 'git describe' on a tag-name will just show the tag name:
Doing a `git describe` on a tag-name will just show the tag name:

[torvalds@g5 git]$ git describe v1.0.4
v1.0.4

With --all, the command can use branch heads as references, so
With `--all`, the command can use branch heads as references, so
the output shows the reference path as well:

[torvalds@g5 git]$ git describe --all --abbrev=4 v1.0.5^2
@ -163,7 +163,7 @@ the output shows the reference path as well:
[torvalds@g5 git]$ git describe --all --abbrev=4 HEAD^
heads/lt/describe-7-g975b

With --abbrev set to 0, the command can be used to find the
With `--abbrev` set to 0, the command can be used to find the
closest tagname without any suffix:

[torvalds@g5 git]$ git describe --abbrev=0 v1.0.5^2
@ -179,13 +179,13 @@ be sufficient to disambiguate these commits.
SEARCH STRATEGY
---------------

For each commit-ish supplied, 'git describe' will first look for
For each commit-ish supplied, `git describe` will first look for
a tag which tags exactly that commit. Annotated tags will always
be preferred over lightweight tags, and tags with newer dates will
always be preferred over tags with older dates. If an exact match
is found, its name will be output and searching will stop.

If an exact match was not found, 'git describe' will walk back
If an exact match was not found, `git describe` will walk back
through the commit history to locate an ancestor commit which
has been tagged. The ancestor's tag will be output along with an
abbreviation of the input commit-ish's SHA-1. If `--first-parent` was
@ -203,7 +203,7 @@ BUGS

Tree objects as well as tag objects not pointing at commits, cannot be described.
When describing blobs, the lightweight tags pointing at blobs are ignored,
but the blob is still described as <commit-ish>:<path> despite the lightweight
but the blob is still described as `<commit-ish>:<path>` despite the lightweight
tag being favorable.

GIT

View File

@ -7,64 +7,64 @@ git-difftool - Show changes using common diff tools

SYNOPSIS
--------
[verse]
'git difftool' [<options>] [<commit> [<commit>]] [--] [<path>...]
[synopsis]
git difftool [<options>] [<commit> [<commit>]] [--] [<path>...]

DESCRIPTION
-----------
'git difftool' is a Git command that allows you to compare and edit files
between revisions using common diff tools. 'git difftool' is a frontend
to 'git diff' and accepts the same options and arguments. See
`git difftool` is a Git command that allows you to compare and edit files
between revisions using common diff tools. `git difftool` is a frontend
to `git diff` and accepts the same options and arguments. See
linkgit:git-diff[1].

OPTIONS
-------
-d::
--dir-diff::
`-d`::
`--dir-diff`::
Copy the modified files to a temporary location and perform
a directory diff on them. This mode never prompts before
launching the diff tool.

-y::
--no-prompt::
`-y`::
`--no-prompt`::
Do not prompt before launching a diff tool.

--prompt::
`--prompt`::
Prompt before each invocation of the diff tool.
This is the default behaviour; the option is provided to
override any configuration settings.

--rotate-to=<file>::
Start showing the diff for the given path,
`--rotate-to=<file>`::
Start showing the diff for _<file>_,
the paths before it will move to the end and output.

--skip-to=<file>::
Start showing the diff for the given path, skipping all
`--skip-to=<file>`::
Start showing the diff for _<file>_, skipping all
the paths before it.

-t <tool>::
--tool=<tool>::
Use the diff tool specified by <tool>. Valid values include
`-t <tool>`::
`--tool=<tool>`::
Use the diff tool specified by _<tool>_. Valid values include
emerge, kompare, meld, and vimdiff. Run `git difftool --tool-help`
for the list of valid <tool> settings.
for the list of valid _<tool>_ settings.
+
If a diff tool is not specified, 'git difftool'
If a diff tool is not specified, `git difftool`
will use the configuration variable `diff.tool`. If the
configuration variable `diff.tool` is not set, 'git difftool'
configuration variable `diff.tool` is not set, `git difftool`
will pick a suitable default.
+
You can explicitly provide a full path to the tool by setting the
configuration variable `difftool.<tool>.path`. For example, you
can configure the absolute path to kdiff3 by setting
`difftool.kdiff3.path`. Otherwise, 'git difftool' assumes the
`difftool.kdiff3.path`. Otherwise, `git difftool` assumes the
tool is available in PATH.
+
Instead of running one of the known diff tools,
'git difftool' can be customized to run an alternative program
`git difftool` can be customized to run an alternative program
by specifying the command line to invoke in a configuration
variable `difftool.<tool>.cmd`.
+
When 'git difftool' is invoked with this tool (either through the
When `git difftool` is invoked with this tool (either through the
`-t` or `--tool` option or the `diff.tool` configuration variable)
the configured command line will be invoked with the following
variables available: `$LOCAL` is set to the name of the temporary
@ -74,30 +74,30 @@ of the diff post-image. `$MERGED` is the name of the file which is
being compared. `$BASE` is provided for compatibility
with custom merge tool commands and has the same value as `$MERGED`.

--tool-help::
`--tool-help`::
Print a list of diff tools that may be used with `--tool`.

--symlinks::
--no-symlinks::
'git difftool''s default behavior is to create symlinks to the
`--symlinks`::
`--no-symlinks`::
`git difftool`'s default behavior is to create symlinks to the
working tree when run in `--dir-diff` mode and the right-hand
side of the comparison yields the same content as the file in
the working tree.
+
Specifying `--no-symlinks` instructs 'git difftool' to create copies
Specifying `--no-symlinks` instructs `git difftool` to create copies
instead. `--no-symlinks` is the default on Windows.

-x <command>::
--extcmd=<command>::
`-x <command>`::
`--extcmd=<command>`::
Specify a custom command for viewing diffs.
'git-difftool' ignores the configured defaults and runs
`git-difftool` ignores the configured defaults and runs
`<command> $LOCAL $REMOTE` when this option is specified.
Additionally, `$BASE` is set in the environment.

-g::
--gui::
--no-gui::
When 'git-difftool' is invoked with the `-g` or `--gui` option
`-g`::
`--gui`::
`--no-gui`::
When `git-difftool` is invoked with the `-g` or `--gui` option
the default diff tool will be read from the configured
`diff.guitool` variable instead of `diff.tool`. This may be
selected automatically using the configuration variable
@ -106,20 +106,20 @@ instead. `--no-symlinks` is the default on Windows.
fallback in the order of `merge.guitool`, `diff.tool`,
`merge.tool` until a tool is found.

--trust-exit-code::
--no-trust-exit-code::
`--trust-exit-code`::
`--no-trust-exit-code`::
Errors reported by the diff tool are ignored by default.
Use `--trust-exit-code` to make 'git-difftool' exit when an
Use `--trust-exit-code` to make `git-difftool` exit when an
invoked diff tool returns a non-zero exit code.
+
'git-difftool' will forward the exit code of the invoked tool when
`git-difftool` will forward the exit code of the invoked tool when
`--trust-exit-code` is used.

See linkgit:git-diff[1] for the full list of supported options.

CONFIGURATION
-------------
'git difftool' falls back to 'git mergetool' config variables when the
`git difftool` falls back to `git mergetool` config variables when the
difftool equivalents have not been defined.

include::includes/cmd-config-section-rest.adoc[]

View File

@ -0,0 +1,215 @@
git-format-rev(1)
=================

NAME
----
git-format-rev - EXPERIMENTAL: Pretty format revisions on demand


SYNOPSIS
--------
[synopsis]
(EXPERIMENTAL!) git format-rev --stdin-mode=<mode> --format=<pretty> [--[no-]notes=<ref>] [-z] [--[no-]null-output] [--[no-]null-input]

DESCRIPTION
-----------

Pretty format revisions from standard input.

THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.

OPTIONS
-------

`--stdin-mode=<mode>`::
How to interpret standard input data:
+
--
`revs`;; Each line or record (see the <<io,INPUT AND OUTPUT FORMATS>>
section) is interpreted as a commit. Any kind of revision
expression can be used (see linkgit:gitrevisions[7]). Annotated
tags are peeled (see linkgit:gitglossary[7]).
+
The argument `rev` is also accepted.

`text`;; Formats all commit object names found in freeform text. These
must the full object names, i.e. abbreviated hexidecimal object
names will not be interpreted.
+
Anything that is parsed as an object name but that is not found to be a
commit object name is left alone (echoed).
--

`--format=<pretty>`::
Pretty format string.

`--notes=<ref>`::
`--no-notes`::
Custom notes ref. Notes are displayed when using the `%N`
atom. See linkgit:git-notes[1].

`-z`::
`--null`::
Use _NUL_ character to terminate both input and output instead
of newline. This option cannot be negated.
+
This is useful if both the input and output could contain newlines or if
the input to this command also uses _NUL_ character termination; see the
<<io,INPUT AND OUTPUT FORMATS>> section below.
+
The mode `--stdin-mode=text` can have use for this option when it needs
to process input like for example `git last-modified -z`; see the
<<examples,EXAMPLES>> section below.

`--null-output`::
`--no-null-output`::
Use _NUL_ character to terminate output instead of newline. The
default is `--no-null-output`.
+
This is useful if the output could contain newlines, for example if the
`%n` (newline) atom is used.

`--null-input`::
`--no-null-input`::
Use _NUL_ character to terminate input instead of newline. The
default is `--no-null-input`.
+
This is useful if the input revision expressions could contain newlines.

[[io]]
INPUT AND OUTPUT FORMAT
-----------------------

The command uses newlines for both input and output termination by
default. See the `-z`, `--null-output`, and `--null-input` options for
using _NUL_ character as the terminator.

The mode `--stdin-mode=revs` outputs one formatted commit followed by
the terminator. This could either be called a _line_ or a _record_ in
case "line" is too suggestive of newline termination.

Note that this means that the terminator character (newline or _NUL_)
acts as a _terminator_, not a _separator_. In other words, the final
line or record is also terminated by the terminator character.

The mode `--stdin-mode=text` replaces each object name with the
formatted commit, i.e. the format `%s` would transform some commit
object name to `<subject>` without any termination. Like this:

----
Did we not fix this in "<subject>"?
----

It is safe to interactively read and write from this command since each
record is immediately flushed.

[[examples]]
EXAMPLES
--------

The command linkgit:git-last-modified[1] shows the commit that each file
was last modified in.

----
$ git last-modified -- README.md Makefile
7798034171030be0909c56377a4e0e10e6d2df93 Makefile
c50fbb2dd225e7e82abba4380423ae105089f4d7 README.md
----

We can pipe the result to this command in order to replace the object
name with the commit author.

----
$ git last-modified -- README.md Makefile |
git format-rev --stdin-mode=text --format=%an
Junio C Hamano Makefile
Todd Zullinger README.md
----

Another example is _formatting commits in commit messages_. Given this commit message:

----
Fix off-by-one error

Fix off-by-one error introduced in
e83c5163316f89bfbde7d9ab23ca2e25604af290.

We thought we fixed this in 5569bf9bbedd63a00780fc5c110e0cfab3aa97b9 but
that only covered 1/3 of the faulty cases.
----

We can format the commits and use par(1) to reflow the text, say in a
`commit-msg` hook:

----
$ git config set hook.reference-commits.event commit-msg
$ git config set hook.reference-commits.command reference-commits
$ cat $(which reference-commits)
#/bin/sh

msg="$1"
rewritten=$(mktemp)
git format-rev --stdin-mode=text --format=reference <"$msg" |
par >"$rewritten"
mv "$rewritten" "$msg"
----

Which will produce something like this:

----
Fix off-by-one error

Fix off-by-one error introduced in e83c5163316 (Implement better memory
allocator, 2005-04-07).

We thought we fixed this in 5569bf9bbed (Fix memory allocator,
2005-06-22) but that only covered 1/3 of the faulty cases.
----

DISCUSSION
----------

This command lets you format any number of revisions in any order
through one command invocation. Consider the
linkgit:git-last-modified[1] case from the <<examples,EXAMPLES>> section
above:

1. There might be hundreds of files
2. Commits can be repeated, i.e. two or more files were last modified in
the same commit

Two widely-used commands which pretty formats commits are
linkgit:git-log[1] and linkgit:git-show[1]. It turns out that they are
not a good fit for the above use case.

- The output of linkgit:git-last-modified[1] would have to be processed
in stages since you need to transform the first column separately and
then link the author to the filename. But this is surmountable.
- You can feed each commit to `git show` or `git log --no-walk -1`. But
that means that you need to create a process for each line.
- Lets say that you want to use one process, not one per line. So you
want to feed all the commits to the command. Now you face the problem
that you have to feed all the commits to the commands before you get
any output (this is also the case for the `--stdin` modes). In other
words, you cannot loop through each line, get the author for the
commit, and output the author and the filename. You need to feed all
the commits, get back all the output, and match the output with the
filename.
- But the next problem is that commands will deduplicate the input and
only output one commit one single time only. Thus you cannot make the
output order match the input order, since a commit could have been
repeated in the original input.

In short, it is straightforward to use these two commands if you use one
process per line. It is much more work if you just want to use one
process, but still doable. In contrast, this problem is solved with just
another shell pipeline with this command.

SEE ALSO
--------
linkgit:git-name-rev[1],
linkgit:git-log[1].

GIT
---
Part of the linkgit:git[1] suite

View File

@ -8,6 +8,7 @@ git-history - EXPERIMENTAL: Rewrite history
SYNOPSIS
--------
[synopsis]
git history fixup <commit> [--dry-run] [--update-refs=(branches|head)] [--reedit-message] [--empty=(drop|keep|abort)]
git history reword <commit> [--dry-run] [--update-refs=(branches|head)]
git history split <commit> [--dry-run] [--update-refs=(branches|head)] [--] [<pathspec>...]

@ -22,8 +23,9 @@ THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
This command is related to linkgit:git-rebase[1] in that both commands can be
used to rewrite history. There are a couple of major differences though:

* linkgit:git-history[1] can work in a bare repository as it does not need to
touch either the index or the worktree.
* Most subcommands of linkgit:git-history[1] can work in a bare repository as
they do not need to touch either the index or the worktree. The `fixup`
subcommand is an exception to this, as it reads staged changes from the index.
* linkgit:git-history[1] does not execute any linkgit:githooks[5] at the
current point in time. This may change in the future.
* linkgit:git-history[1] by default updates all branches that are descendants
@ -48,11 +50,28 @@ conflicts. This limitation is by design as history rewrites are not intended to
be stateful operations. The limitation can be lifted once (if) Git learns about
first-class conflicts.

When using `fixup` with `--empty=drop`, dropping the root commit is not yet
supported.

COMMANDS
--------

The following commands are available to rewrite history in different ways:

`fixup <commit>`::
Apply the currently staged changes to the specified commit. This is
similar in nature to `git commit --fixup=<commit>` followed by `git
rebase --autosquash <commit>~`. Changes are applied to the target
commit by performing a three-way merge between the HEAD commit, the
target commit and the tree generated from staged changes.
+
The commit message and authorship of the target commit are preserved by
default, unless you specify `--reedit-message`.
+
If applying the staged changes would result in a conflict, the command
aborts with an error. All branches that are descendants of the original
commit are updated to point to the rewritten history.

`reword <commit>`::
Rewrite the commit message of the specified commit. All the other
details of this commit remain unchanged. This command will spawn an
@ -87,6 +106,31 @@ OPTIONS
objects will be written into the repository, so applying these printed
ref updates is generally safe.

`--reedit-message`::
Open an editor to modify the target commit's message.

`--empty=(drop|keep|abort)`::
Control what happens when a commit becomes empty as a result of the
fixup. This can happen in two situations:
+
--
* The fixup target itself becomes empty because the staged changes exactly
cancel out all changes introduced by that commit.

* A descendant commit becomes empty during replay because it introduced the
same change that was just fixed up into an ancestor.
--
+
With `drop` (the default), empty commits are removed from the rewritten
history. Descendants of a dropped target commit are replayed directly onto
the target's parent. Note that dropping the root commit is not supported;
see LIMITATIONS.
+
With `keep`, empty commits are retained in the rewritten history as-is.
+
With `abort`, the command stops with an error if any commit would become
empty.

`--update-refs=(branches|head)`::
Control which references will be updated by the command, if any. With
`branches`, all local branches that point to commits which are
@ -96,6 +140,36 @@ OPTIONS
EXAMPLES
--------

Fixup a commit
~~~~~~~~~~~~~~

----------
$ git log --oneline --stat
abc1234 (HEAD -> main) third
third.txt | 1 +
def5678 second
second.txt | 1 +
ghi9012 first
first.txt | 1 +

$ echo "change" >>unrelated.txt
$ git add unrelated.txt
$ git history fixup ghi9012

$ git log --oneline --stat
jkl3456 (HEAD -> main) third
third.txt | 1 +
mno7890 second
second.txt | 1 +
pqr1234 first
first.txt | 1 +
unrelated.txt | 1 +
----------

The staged addition of `unrelated.txt` has been incorporated into the `first`
commit. All descendant commits have been replayed on top of the rewritten
history.

Split a commit
~~~~~~~~~~~~~~


View File

@ -8,7 +8,8 @@ git-hook - Run git hooks
SYNOPSIS
--------
[verse]
'git hook' run [--allow-unknown-hook-name] [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-args>]
'git hook' run [--allow-unknown-hook-name] [--ignore-missing] [--to-stdin=<path>] [(-j|--jobs) <n>]
<hook-name> [-- <hook-args>]
'git hook' list [--allow-unknown-hook-name] [-z] [--show-scope] <hook-name>

DESCRIPTION
@ -147,6 +148,23 @@ OPTIONS
mirroring the output style of `git config --show-scope`. Traditional
hooks from the hookdir are unaffected.

-j::
--jobs::
Only valid for `run`.
+
Specify how many hooks to run simultaneously. If this flag is not specified,
the value of the `hook.jobs` config is used, see linkgit:git-config[1]. If
neither is specified, defaults to 1 (serial execution).
+
When greater than 1, it overrides the per-hook `hook.<friendly-name>.parallel`
setting, allowing all hooks for the event to run concurrently, even if they
are not individually marked as parallel.
+
Some hooks always run sequentially regardless of this flag or the
`hook.jobs` config, because git knows they cannot safely run in parallel:
`applypatch-msg`, `pre-commit`, `prepare-commit-msg`, `commit-msg`,
`post-commit`, `post-checkout`, and `push-to-checkout`.

WRAPPERS
--------

@ -169,7 +187,8 @@ running:
git hook run --allow-unknown-hook-name mywrapper-start-tests \
# providing something to stdin
--stdin some-tempfile-123 \
# execute hooks in serial
# execute multiple hooks in parallel
--jobs 3 \
# plus some arguments of your own...
-- \
--testname bar \

View File

@ -36,14 +36,14 @@ OPTIONS
Print out the ref names of any commits that are shown. Possible values
are:
+
----
--
`short`;; the ref name prefixes `refs/heads/`, `refs/tags/` and
`refs/remotes/` are not printed.
`full`;; the full ref name (including prefix) is printed.
`auto`:: if the output is going to a terminal, the ref names
`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.
----
--
+
The option `--decorate` is short-hand for `--decorate=short`. Default to
configuration value of `log.decorate` if configured, otherwise, `auto`.

View File

@ -331,7 +331,7 @@ can give `--exclude-per-directory=.gitignore`, and then specify:
1. The file specified by the `core.excludesfile` configuration
variable, if exists, or the `$XDG_CONFIG_HOME/git/ignore` file.

2. The `$GIT_DIR/info/exclude` file.
2. The `$GIT_COMMON_DIR/info/exclude` file.

via the `--exclude-from=` option.


View File

@ -11,9 +11,11 @@ SYNOPSIS
[verse]
'git multi-pack-index' [<options>] write [--preferred-pack=<pack>]
[--[no-]bitmap] [--[no-]incremental] [--[no-]stdin-packs]
[--refs-snapshot=<path>]
[--refs-snapshot=<path>] [--[no-]write-chain-file]
[--base=<checksum>]
'git multi-pack-index' [<options>] compact [--[no-]incremental]
[--[no-]bitmap] <from> <to>
[--[no-]bitmap] [--base=<checksum>] [--[no-]write-chain-file]
<from> <to>
'git multi-pack-index' [<options>] verify
'git multi-pack-index' [<options>] expire
'git multi-pack-index' [<options>] repack [--batch-size=<size>]
@ -83,6 +85,20 @@ marker).
and packs not present in an existing MIDX layer.
Migrates non-incremental MIDXs to incremental ones when
necessary.

--[no-]write-chain-file::
When used with `--incremental`, write a new MIDX layer
but do not update the multi-pack-index-chain file.
The checksum of the new layer is printed to standard
output, allowing the caller to assemble and write the
chain itself. Requires `--incremental`.

--base=<checksum>::
Specify the checksum of an existing MIDX layer to use
as the base when writing a new incremental layer.
The special value `none` indicates that the new layer
should have no base (i.e., it becomes a root layer).
Requires `--no-write-chain-file`.
--

compact::
@ -97,6 +113,18 @@ compact::

--[no-]bitmap::
Control whether or not a multi-pack bitmap is written.

--[no-]write-chain-file::
When used with `--incremental`, write a new compacted
MIDX layer but do not update the multi-pack-index-chain
file. The checksum of the new layer is printed to
standard output. Requires `--incremental`.

--base=<checksum>::
Specify the checksum of an existing MIDX layer to use
as the base for the compacted result, instead of using
the immediate parent of `<from>`. The special value
`none` indicates that the result should have no base.
--
+
Note that the compact command requires writing a version-2 midx that

View File

@ -7,8 +7,8 @@ git-range-diff - Compare two commit ranges (e.g. two versions of a branch)

SYNOPSIS
--------
[verse]
'git range-diff' [--color=[<when>]] [--no-color] [<diff-options>]
[synopsis]
git range-diff [--color=[<when>]] [--no-color] [<diff-options>]
[--no-dual-color] [--creation-factor=<factor>]
[--left-only | --right-only] [--diff-merges=<format>]
[--remerge-diff]
@ -21,14 +21,14 @@ DESCRIPTION
This command shows the differences between two versions of a patch
series, or more generally, two commit ranges (ignoring merge commits).

In the presence of `<path>` arguments, these commit ranges are limited
In the presence of _<path>_ arguments, these commit ranges are limited
accordingly.

To that end, it first finds pairs of commits from both commit ranges
that correspond with each other. Two commits are said to correspond when
the diff between their patches (i.e. the author information, the commit
message and the commit diff) is reasonably small compared to the
patches' size. See ``Algorithm`` below for details.
patches' size. See 'Algorithm' below for details.

Finally, the list of matching commits is shown in the order of the
second commit range, with unmatched commits being inserted just after
@ -37,7 +37,7 @@ all of their ancestors have been shown.
There are three ways to specify the commit ranges:

- `<range1> <range2>`: Either commit range can be of the form
`<base>..<rev>`, `<rev>^!` or `<rev>^-<n>`. See `SPECIFYING RANGES`
`<base>..<rev>`, `<rev>^!` or `<rev>^-<n>`. See 'SPECIFYING RANGES'
in linkgit:gitrevisions[7] for more details.

- `<rev1>...<rev2>`. This is equivalent to
@ -48,7 +48,7 @@ There are three ways to specify the commit ranges:

OPTIONS
-------
--no-dual-color::
`--no-dual-color`::
When the commit diffs differ, `git range-diff` recreates the
original diffs' coloring, and adds outer -/+ diff markers with
the *background* being red/green to make it easier to see e.g.
@ -56,33 +56,33 @@ OPTIONS
+
Additionally, the commit diff lines that are only present in the first commit
range are shown "dimmed" (this can be overridden using the `color.diff.<slot>`
config setting where `<slot>` is one of `contextDimmed`, `oldDimmed` and
config setting where _<slot>_ is one of `contextDimmed`, `oldDimmed` and
`newDimmed`), and the commit diff lines that are only present in the second
commit range are shown in bold (which can be overridden using the config
settings `color.diff.<slot>` with `<slot>` being one of `contextBold`,
settings `color.diff.<slot>` with _<slot>_ being one of `contextBold`,
`oldBold` or `newBold`).
+
This is known to `range-diff` as "dual coloring". Use `--no-dual-color`
to revert to color all lines according to the outer diff markers
(and completely ignore the inner diff when it comes to color).

--creation-factor=<percent>::
Set the creation/deletion cost fudge factor to `<percent>`.
`--creation-factor=<percent>`::
Set the creation/deletion cost fudge factor to _<percent>_.
Defaults to 60. Try a larger value if `git range-diff` erroneously
considers a large change a total rewrite (deletion of one commit
and addition of another), and a smaller one in the reverse case.
See the ``Algorithm`` section below for an explanation of why this is
See the 'Algorithm' section below for an explanation of why this is
needed.

--left-only::
`--left-only`::
Suppress commits that are missing from the first specified range
(or the "left range" when using the `<rev1>...<rev2>` format).
(or the "left range" when using the `<rev1>...<rev2>` form).

--right-only::
`--right-only`::
Suppress commits that are missing from the second specified range
(or the "right range" when using the `<rev1>...<rev2>` format).
(or the "right range" when using the `<rev1>...<rev2>` form).

--diff-merges=<format>::
`--diff-merges=<format>`::
Instead of ignoring merge commits, generate diffs for them using the
corresponding `--diff-merges=<format>` option of linkgit:git-log[1],
and include them in the comparison.
@ -93,30 +93,30 @@ have produced. In other words, if a merge commit is the result of a
non-conflicting `git merge`, the `remerge` mode will represent it with an empty
diff.

--remerge-diff::
`--remerge-diff`::
Convenience option, equivalent to `--diff-merges=remerge`.

--notes[=<ref>]::
--no-notes::
`--notes[=<ref>]`::
`--no-notes`::
This flag is passed to the `git log` program
(see linkgit:git-log[1]) that generates the patches.

<range1> <range2>::
`<range1> <range2>`::
Compare the commits specified by the two ranges, where
`<range1>` is considered an older version of `<range2>`.
_<range1>_ is considered an older version of _<range2>_.

<rev1>...<rev2>::
`<rev1>...<rev2>`::
Equivalent to passing `<rev2>..<rev1>` and `<rev1>..<rev2>`.

<base> <rev1> <rev2>::
`<base> <rev1> <rev2>`::
Equivalent to passing `<base>..<rev1>` and `<base>..<rev2>`.
Note that `<base>` does not need to be the exact branch point
Note that _<base>_ does not need to be the exact branch point
of the branches. Example: after rebasing a branch `my-topic`,
`git range-diff my-topic@{u} my-topic@{1} my-topic` would
show the differences introduced by the rebase.

`git range-diff` also accepts the regular diff options (see
linkgit:git-diff[1]), most notably the `--color=[<when>]` and
linkgit:git-diff[1]), most notably the `--color[=<when>]` and
`--no-color` options. These options are used when generating the "diff
between patches", i.e. to compare the author, commit message and diff of
corresponding old/new commits. There is currently no means to tweak most of the

View File

@ -11,7 +11,7 @@ SYNOPSIS
[verse]
'git repack' [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]
[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>]
[--write-midx] [--name-hash-version=<n>] [--path-walk]
[--write-midx[=<mode>]] [--name-hash-version=<n>] [--path-walk]

DESCRIPTION
-----------
@ -250,9 +250,47 @@ pack as the preferred pack for object selection by the MIDX (see
linkgit:git-multi-pack-index[1]).

-m::
--write-midx::
--write-midx[=<mode>]::
Write a multi-pack index (see linkgit:git-multi-pack-index[1])
containing the non-redundant packs.
containing the non-redundant packs. The following modes are
available:
+
--
`default`;;
Write a single MIDX covering all packs. This is the
default when `--write-midx` is given without an
explicit mode.

`incremental`;;
Write an incremental MIDX chain instead of a single
flat MIDX.
+
Without `--geometric`, a new MIDX layer is appended to the existing
chain (or a new chain is started) containing whatever packs were written
by the repack. Existing layers are preserved as-is.
+
When combined with `--geometric`, the incremental mode maintains a chain
of MIDX layers that is compacted over time using a geometric merging
strategy. Each repack creates a new tip layer containing the newly
written pack(s). Adjacent layers are then merged whenever the newer
layer's object count exceeds `1/repack.midxSplitFactor` of the next
deeper layer's count. Layers that do not meet this condition are
retained as-is.
+
The result is that newer (tip) layers tend to contain many small packs
with relatively few objects, while older (deeper) layers contain fewer,
larger packs covering more objects. Because compaction is driven by the
tip of the chain, newer layers are also rewritten more frequently than
older ones, which are only touched when enough objects have accumulated
to justify merging into them. This keeps the total number of layers
logarithmic relative to the total number of objects.
+
Only packs in the tip MIDX layer are considered as candidates for the
geometric repack; packs in deeper layers are left untouched. If the tip
layer contains fewer packs than `repack.midxNewLayerThreshold`, those
packs are excluded from the geometry entirely, and a new layer is
created for any new pack(s) without disturbing the existing chain.
--

--name-hash-version=<n>::
Provide this argument to the underlying `git pack-objects` process.

View File

@ -145,6 +145,13 @@ commit instead of the replaced commit.
There may be other problems when using 'git rev-list' related to
pending objects.

CAVEATS
-------

The existence of replace objects or commit grafts turns off reading or
writing to the commit-graph, which can cause performance issues. See
linkgit:git-commit-graph[1].

SEE ALSO
--------
linkgit:git-hash-object[1]

View File

@ -41,7 +41,7 @@ given, otherwise from the index.
+
As a special case, you may use `"<rev-A>...<rev-B>"` as a shortcut for the
merge base of _<rev-A>_ and _<rev-B>_ if there is exactly one merge base. You can
leave out at most one of _<rev-A>__ and _<rev-B>_, in which case it defaults to `HEAD`.
leave out at most one of _<rev-A>_ and _<rev-B>_, in which case it defaults to `HEAD`.

`-p`::
`--patch`::

View File

@ -3,63 +3,63 @@ git-shortlog(1)

NAME
----
git-shortlog - Summarize 'git log' output
git-shortlog - Summarize `git log` output

SYNOPSIS
--------
[verse]
'git shortlog' [<options>] [<revision-range>] [[--] <path>...]
git log --pretty=short | 'git shortlog' [<options>]
[synopsis]
git shortlog [<options>] [<revision-range>] [[--] <path>...]
git log --pretty=short | git shortlog [<options>]

DESCRIPTION
-----------
Summarizes 'git log' output in a format suitable for inclusion
Summarizes `git log` output in a format suitable for inclusion
in release announcements. Each commit will be grouped by author and title.

Additionally, "[PATCH]" will be stripped from the commit description.

If no revisions are passed on the command line and either standard input
is not a terminal or there is no current branch, 'git shortlog' will
is not a terminal or there is no current branch, `git shortlog` will
output a summary of the log read from standard input, without
reference to the current repository.

OPTIONS
-------

-n::
--numbered::
`-n`::
`--numbered`::
Sort output according to the number of commits per author instead
of author alphabetic order.

-s::
--summary::
`-s`::
`--summary`::
Suppress commit description and provide a commit count summary only.

-e::
--email::
`-e`::
`--email`::
Show the email address of each author.

--format[=<format>]::
`--format[=<format>]`::
Instead of the commit subject, use some other information to
describe each commit. '<format>' can be any string accepted
by the `--format` option of 'git log', such as '* [%h] %s'.
(See the "PRETTY FORMATS" section of linkgit:git-log[1].)
describe each commit. _<format>_ can be any string accepted
by the `--format` option of `git log`, such as '* [%h] %s'.
(See the 'PRETTY FORMATS' section of linkgit:git-log[1].)
+
Each pretty-printed commit will be rewrapped before it is shown.

--date=<format>::
`--date=<format>`::
Show dates formatted according to the given date string. (See
the `--date` option in the "Commit Formatting" section of
the `--date` option in the 'Commit Formatting' section of
linkgit:git-log[1]). Useful with `--group=format:<format>`.

--group=<type>::
Group commits based on `<type>`. If no `--group` option is
specified, the default is `author`. `<type>` is one of:
`--group=<type>`::
Group commits based on _<type>_. If no `--group` option is
specified, the default is `author`. _<type>_ is one of:
+
--
- `author`, commits are grouped by author
- `committer`, commits are grouped by committer (the same as `-c`)
- `trailer:<field>`, the `<field>` is interpreted as a case-insensitive
- `trailer:<field>`, the _<field>_ is interpreted as a case-insensitive
commit message trailer (see linkgit:git-interpret-trailers[1]). For
example, if your project uses `Reviewed-by` trailers, you might want
to see who has been reviewing with
@ -76,7 +76,7 @@ unless the `--email` option is specified. If the value cannot be parsed
as an identity, it will be taken literally and completely.

- `format:<format>`, any string accepted by the `--format` option of
'git log'. (See the "PRETTY FORMATS" section of
`git log`. (See the 'PRETTY FORMATS' section of
linkgit:git-log[1].)
--
+
@ -85,11 +85,11 @@ value (but again, only once per unique value in that commit). For
example, `git shortlog --group=author --group=trailer:co-authored-by`
counts both authors and co-authors.

-c::
--committer::
`-c`::
`--committer`::
This is an alias for `--group=committer`.

-w[<width>[,<indent1>[,<indent2>]]]::
`-w[<width>[,<indent1>[,<indent2>]]]`::
Linewrap the output by wrapping each line at `width`. The first
line of each entry is indented by `indent1` spaces, and the second
and subsequent lines are indented by `indent2` spaces. `width`,
@ -98,16 +98,16 @@ counts both authors and co-authors.
If width is `0` (zero) then indent the lines of the output without wrapping
them.

<revision-range>::
`<revision-range>`::
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`
specifies all the commits reachable from the current commit
(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].

[--] <path>...::
`[--] <path>...`::
Consider only commits that are enough to explain how the files
that match the specified paths came to be.
+

View File

@ -12,7 +12,7 @@ git stash list [<log-options>]
git stash show [-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>]
git stash drop [-q | --quiet] [<stash>]
git stash pop [--index] [-q | --quiet] [<stash>]
git stash apply [--index] [-q | --quiet] [<stash>]
git stash apply [--index] [-q | --quiet] [--label-ours=<label>] [--label-theirs=<label>] [--label-base=<label>] [<stash>]
git stash branch <branchname> [<stash>]
git stash [push] [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]
[-u | --include-untracked] [-a | --all] [(-m | --message) <message>]
@ -195,6 +195,15 @@ the index's ones. However, this can fail, when you have conflicts
(which are stored in the index, where you therefore can no longer
apply the changes as they were originally).

`--label-ours=<label>`::
`--label-theirs=<label>`::
`--label-base=<label>`::
These options are only valid for the `apply` command.
+
Use the given labels in conflict markers instead of the default
"Updated upstream", "Stashed changes", and "Stash base".
`--label-base` only has an effect with merge.conflictStyle=diff3.

`-k`::
`--keep-index`::
`--no-keep-index`::

View File

@ -439,7 +439,7 @@ Any other arguments are passed directly to 'git log'
'show-ignore'::
Recursively finds and lists the svn:ignore and svn:global-ignores
properties on directories. The output is suitable for appending to
the $GIT_DIR/info/exclude file.
the $GIT_COMMON_DIR/info/exclude file.

'mkdirs'::
Attempts to recreate empty directories that core Git cannot track

View File

@ -123,18 +123,19 @@ variable.

`-m`::
`--merge`::
If you have local modifications to one or more files that are
different between the current branch and the branch to which
you are switching, the command refuses to switch branches in
order to preserve your modifications in context. However,
with this option, a three-way merge between the current
branch, your working tree contents, and the new branch is
done, and you will be on the new branch.
+
When a merge conflict happens, the index entries for conflicting
paths are left unmerged, and you need to resolve the conflicts
and mark the resolved paths with `git add` (or `git rm` if the merge
should result in deletion of the path).
If you have local modifications to one or more files that
are different between the current branch and the branch to
which you are switching, the command normally refuses to
switch branches in order to preserve your modifications in
context. However, with this option, the conflicting local
changes are automatically stashed before the switch and
reapplied afterwards. If the local changes do not overlap
with the differences between branches, the switch proceeds
without stashing. If reapplying the stash results in
conflicts, the entry is saved to the stash list. Resolve
the conflicts and run `git stash drop` when done, or clear
the working tree (e.g. with `git reset --hard`) before
running `git stash pop` later to re-apply your changes.

`--conflict=<style>`::
The same as `--merge` option above, but changes the way the
@ -217,15 +218,18 @@ $ git switch mytopic
error: You have local changes to 'frotz'; not switching branches.
------------

You can give the `-m` flag to the command, which would try a three-way
merge:
You can give the `-m` flag to the command, which will carry your local
changes to the new branch:

------------
$ git switch -m mytopic
Auto-merging frotz
Applied autostash.
Switched to branch 'mytopic'
The following paths have local changes:
M frotz
------------

After this three-way merge, the local modifications are _not_
After the switch, the local modifications are reapplied and are _not_
registered in your index file, so `git diff` would show you what
changes you made since the tip of the new branch.


View File

@ -0,0 +1,80 @@
git-url-parse(1)
================

NAME
----
git-url-parse - Parse and extract git URL components

SYNOPSIS
--------
[synopsis]
git url-parse [-c <component>] [--] <url>...

DESCRIPTION
-----------

Git supports many ways to specify URLs, some of them non-standard.
For example, git supports the scp style [user@]host:[path] format.
This command eases interoperability with git URLs by enabling the
parsing and extraction of the components of all git URLs.

Any syntactically valid URL is parsed, even if the scheme is not one
git supports for fetching or pushing.

OPTIONS
-------

`-c <component>`::
`--component <component>`::
Extract the _<component>_ component from the given Git URLs.
_<component>_ can be one of:
`scheme`, `user`, `password`, `host`, `port`, `path`.

OUTPUT
------

When `--component` is given, the requested component of each URL
is printed on its own line, in the order the URLs were given. If
the URL has no such component (for example, a port in a URL that
does not specify one), an empty line is printed in its place.

When `--component` is not given, no output is produced. The exit
status is zero if every URL parses successfully and non-zero
otherwise, allowing the command to be used purely as a validator.

EXAMPLES
--------

* Print the host name:
+
------------
$ git url-parse --component host https://example.com/user/repo
example.com
------------

* Print the path:
+
------------
$ git url-parse --component path https://example.com/user/repo
/user/repo
$ git url-parse --component path example.com:~user/repo
~user/repo
$ git url-parse --component path example.com:user/repo
/user/repo
------------

* Validate URLs without outputting anything:
+
------------
$ git url-parse https://example.com/user/repo example.com:~user/repo
------------

SEE ALSO
--------
linkgit:git-clone[1],
linkgit:git-fetch[1],
linkgit:git-config[1]

GIT
---
Part of the linkgit:git[1] suite

View File

@ -911,7 +911,8 @@ patterns are available:

- `rust` suitable for source code in the Rust language.

- `scheme` suitable for source code in the Scheme language.
- `scheme` suitable for source code in most Lisp dialects,
including Scheme, Emacs Lisp, Common Lisp, and Clojure.

- `tex` suitable for source code for LaTeX documents.


View File

@ -291,14 +291,14 @@ Git index format
sequence in variable width encoding. Each string describes the
environment where the cache can be used.

- Stat data of $GIT_DIR/info/exclude. See "Index entry" section from
- Stat data of $GIT_COMMON_DIR/info/exclude. See "Index entry" section from
ctime field until "file size".

- Stat data of core.excludesFile

- 32-bit dir_flags (see struct dir_struct)

- Hash of $GIT_DIR/info/exclude. A null hash means the file
- Hash of $GIT_COMMON_DIR/info/exclude. A null hash means the file
does not exist.

- Hash of core.excludesFile. A null hash means the file does

View File

@ -7,7 +7,7 @@ gitignore - Specifies intentionally untracked files to ignore

SYNOPSIS
--------
$XDG_CONFIG_HOME/git/ignore, $GIT_DIR/info/exclude, .gitignore
$XDG_CONFIG_HOME/git/ignore, $GIT_COMMON_DIR/info/exclude, .gitignore

DESCRIPTION
-----------
@ -34,7 +34,7 @@ precedence, the last matching pattern decides the outcome):
includes such `.gitignore` files in its repository, containing patterns for
files generated as part of the project build.

* Patterns read from `$GIT_DIR/info/exclude`.
* Patterns read from `$GIT_COMMON_DIR/info/exclude`.

* Patterns read from the file specified by the configuration
variable `core.excludesFile`.
@ -50,7 +50,7 @@ be used.
specific to a particular repository but which do not need to be shared
with other related repositories (e.g., auxiliary files that live inside
the repository but are specific to one user's workflow) should go into
the `$GIT_DIR/info/exclude` file.
the `$GIT_COMMON_DIR/info/exclude` file.

* Patterns which a user wants Git to
ignore in all situations (e.g., backup or temporary files generated by
@ -97,7 +97,7 @@ PATTERN FORMAT
match at any level below the `.gitignore` level.

- Patterns read from exclude sources that are outside the working tree,
such as $GIT_DIR/info/exclude and core.excludesFile, are treated as if
such as $GIT_COMMON_DIR/info/exclude and core.excludesFile, are treated as if
they are specified at the root of the working tree, i.e. a leading "/"
in such patterns anchors the match at the root of the repository.

@ -146,8 +146,8 @@ CONFIGURATION

The optional configuration variable `core.excludesFile` indicates a path to a
file containing patterns of file names to exclude, similar to
`$GIT_DIR/info/exclude`. Patterns in the exclude file are used in addition to
those in `$GIT_DIR/info/exclude`.
`$GIT_COMMON_DIR/info/exclude`. Patterns in the exclude file are used in
addition to those in `$GIT_COMMON_DIR/info/exclude`.

NOTES
-----

View File

@ -150,7 +150,7 @@ with a configuration like so:
pattern = "refs/"
threshold = now
stableThreshold = never
sampleRate = 100
sampleRate = 1
maxMerges = 64
----

@ -177,7 +177,7 @@ like:
pattern = "refs/virtual/([0-9]+)/(heads|tags)/"
threshold = now
stableThreshold = never
sampleRate = 100
sampleRate = 1
maxMerges = 64
----


View File

@ -848,6 +848,10 @@ advertised, it can reply with "promisor-remote=<pr-names>" where
where `pr-name` is the urlencoded name of a promisor remote the server
advertised and the client accepts.

The promisor remotes that the client accepted will be tried before the
other configured promisor remotes when the client attempts to fetch
missing objects.

Note that, everywhere in this document, the ';' and ',' characters
MUST be encoded if they appear in `pr-name` or `field-value`.


View File

@ -55,6 +55,7 @@ manpages = {
'git-for-each-ref.adoc' : 1,
'git-for-each-repo.adoc' : 1,
'git-format-patch.adoc' : 1,
'git-format-rev.adoc' : 1,
'git-fsck-objects.adoc' : 1,
'git-fsck.adoc' : 1,
'git-fsmonitor--daemon.adoc' : 1,
@ -155,6 +156,7 @@ manpages = {
'git-update-server-info.adoc' : 1,
'git-upload-archive.adoc' : 1,
'git-upload-pack.adoc' : 1,
'git-url-parse.adoc' : 1,
'git-var.adoc' : 1,
'git-verify-commit.adoc' : 1,
'git-verify-pack.adoc' : 1,

View File

@ -283,13 +283,9 @@ include shared.mak
# Define SKIP_DASHED_BUILT_INS if you do not need the dashed versions of the
# built-ins to be linked/copied at all.
#
# Define USE_NED_ALLOCATOR if you want to replace the platforms default
# memory allocators with the nedmalloc allocator written by Niall Douglas.
#
# Define OVERRIDE_STRDUP to override the libc version of strdup(3).
# This is necessary when using a custom allocator in order to avoid
# crashes due to allocation and free working on different 'heaps'.
# It's defined automatically if USE_NED_ALLOCATOR is set.
#
# Define NO_REGEX if your C library lacks regex support with REG_STARTEND
# feature.
@ -498,9 +494,9 @@ include shared.mak
#
# == Optional Rust support ==
#
# Define WITH_RUST if you want to include features and subsystems written in
# Rust into Git. For now, Rust is still an optional feature of the build
# process. With Git 3.0 though, Rust will always be enabled.
# Define NO_RUST if you want to disable features and subsystems written in Rust
# from being compiled into Git. For now, Rust is still an optional feature of
# the build process. With Git 3.0 though, Rust will always be enabled.
#
# Building Rust code requires Cargo.
#
@ -872,6 +868,7 @@ TEST_BUILTINS_OBJS += test-submodule-config.o
TEST_BUILTINS_OBJS += test-submodule-nested-repo-config.o
TEST_BUILTINS_OBJS += test-submodule.o
TEST_BUILTINS_OBJS += test-subprocess.o
TEST_BUILTINS_OBJS += test-synthesize.o
TEST_BUILTINS_OBJS += test-trace2.o
TEST_BUILTINS_OBJS += test-truncate.o
TEST_BUILTINS_OBJS += test-userdiff.o
@ -895,6 +892,7 @@ BUILT_INS += $(patsubst builtin/%.o,git-%$X,$(BUILTIN_OBJS))
BUILT_INS += git-cherry$X
BUILT_INS += git-cherry-pick$X
BUILT_INS += git-format-patch$X
BUILT_INS += git-format-rev$X
BUILT_INS += git-fsck-objects$X
BUILT_INS += git-init$X
BUILT_INS += git-maintenance$X
@ -1218,7 +1216,9 @@ LIB_OBJS += object.o
LIB_OBJS += odb.o
LIB_OBJS += odb/source.o
LIB_OBJS += odb/source-files.o
LIB_OBJS += odb/source-inmemory.o
LIB_OBJS += odb/streaming.o
LIB_OBJS += odb/transaction.o
LIB_OBJS += oid-array.o
LIB_OBJS += oidmap.o
LIB_OBJS += oidset.o
@ -1351,7 +1351,7 @@ LIB_OBJS += urlmatch.o
LIB_OBJS += usage.o
LIB_OBJS += userdiff.o
LIB_OBJS += utf8.o
ifndef WITH_RUST
ifdef NO_RUST
LIB_OBJS += varint.o
endif
LIB_OBJS += version.o
@ -1497,6 +1497,7 @@ BUILTIN_OBJS += builtin/update-ref.o
BUILTIN_OBJS += builtin/update-server-info.o
BUILTIN_OBJS += builtin/upload-archive.o
BUILTIN_OBJS += builtin/upload-pack.o
BUILTIN_OBJS += builtin/url-parse.o
BUILTIN_OBJS += builtin/var.o
BUILTIN_OBJS += builtin/verify-commit.o
BUILTIN_OBJS += builtin/verify-pack.o
@ -1511,7 +1512,6 @@ BUILTIN_OBJS += builtin/write-tree.o
# upstream unnecessarily (making merging in future changes easier).
THIRD_PARTY_SOURCES += compat/inet_ntop.c
THIRD_PARTY_SOURCES += compat/inet_pton.c
THIRD_PARTY_SOURCES += compat/nedmalloc/%
THIRD_PARTY_SOURCES += compat/obstack.%
THIRD_PARTY_SOURCES += compat/poll/%
THIRD_PARTY_SOURCES += compat/regex/%
@ -1527,6 +1527,7 @@ CLAR_TEST_SUITES += u-hash
CLAR_TEST_SUITES += u-hashmap
CLAR_TEST_SUITES += u-list-objects-filter-options
CLAR_TEST_SUITES += u-mem-pool
CLAR_TEST_SUITES += u-odb-inmemory
CLAR_TEST_SUITES += u-oid-array
CLAR_TEST_SUITES += u-oidmap
CLAR_TEST_SUITES += u-oidtree
@ -1590,7 +1591,7 @@ endif
ALL_CFLAGS = $(DEVELOPER_CFLAGS) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_APPEND)
ALL_LDFLAGS = $(LDFLAGS) $(LDFLAGS_APPEND)

ifdef WITH_RUST
ifndef NO_RUST
BASIC_CFLAGS += -DWITH_RUST
GITLIBS += $(RUST_LIB)
ifeq ($(uname_S),Windows)
@ -2267,12 +2268,6 @@ ifdef NATIVE_CRLF
BASIC_CFLAGS += -DNATIVE_CRLF
endif

ifdef USE_NED_ALLOCATOR
COMPAT_CFLAGS += -Icompat/nedmalloc
COMPAT_OBJS += compat/nedmalloc/nedmalloc.o
OVERRIDE_STRDUP = YesPlease
endif

ifdef OVERRIDE_STRDUP
COMPAT_CFLAGS += -DOVERRIDE_STRDUP
COMPAT_OBJS += compat/strdup.o
@ -2671,7 +2666,7 @@ git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)

help.sp help.s help.o: command-list.h
builtin/bugreport.sp builtin/bugreport.s builtin/bugreport.o: hook-list.h
builtin/hook.sp builtin/hook.s builtin/hook.o: hook-list.h
hook.sp hook.s hook.o: hook-list.h

builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX
builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
@ -2983,12 +2978,6 @@ compat/regex/regex.sp compat/regex/regex.o: EXTRA_CPPFLAGS = \
-DGAWK -DNO_MBSUPPORT
endif

ifdef USE_NED_ALLOCATOR
compat/nedmalloc/nedmalloc.sp compat/nedmalloc/nedmalloc.o: EXTRA_CPPFLAGS = \
-DNDEBUG -DREPLACE_SYSTEM_ALLOCATOR
compat/nedmalloc/nedmalloc.sp: SP_EXTRA_FLAGS += -Wno-non-pointer-null
endif

headless-git.o: compat/win32/headless.c GIT-CFLAGS
$(QUIET_CC)$(CC) $(ALL_CFLAGS) $(COMPAT_CFLAGS) \
-fno-stack-protector -o $@ -c -Wall -Wwrite-strings $<

View File

@ -1 +1 @@
Documentation/RelNotes/2.54.0.adoc
Documentation/RelNotes/2.55.0.adoc

16
alias.c
View File

@ -34,8 +34,20 @@ static int config_alias_cb(const char *var, const char *value,
if (subsection && !subsection_len)
subsection = NULL;

if (subsection && strcmp(key, "command"))
return 0;
if (subsection && strcmp(key, "command")) {
/*
* We have historically supported the "alias.name" form when
* "name" happens to contain dots (e.g., alias.foo.bar to allow
* "git foo.bar". But our parsing above would split that into
* subsection "foo".
*
* If we do not understand the final key in a subsection-style
* variable, fall back to treating it as a two-level alias.
*/
key = var + strlen("alias.");
subsection = NULL;
subsection_len = 0;
}

if (data->alias) {
int match;

View File

@ -4881,8 +4881,10 @@ static int apply_patch(struct apply_state *state,

state->patch_input_file = filename;
state->linenr = 1;
if (read_patch_file(&buf, fd) < 0)
return -128;
if (read_patch_file(&buf, fd) < 0) {
res = -128;
goto end;
}
offset = 0;
while (offset < buf.len) {
struct patch *patch;

View File

@ -786,7 +786,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
* die ourselves; but its error message will be more specific
* than what we could write here.
*/
setup_git_directory();
setup_git_directory(the_repository);
}

parse_treeish_arg(argv, &args, remote);

View File

@ -2813,7 +2813,7 @@ void setup_scoreboard(struct blame_scoreboard *sb,
}

if (!sb->contents_from)
setup_work_tree();
setup_work_tree(the_repository);

sb->final = fake_working_tree_commit(sb->repo,
&sb->revs->diffopt,

View File

@ -189,6 +189,7 @@ int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix, struct re
int cmd_for_each_ref(int argc, const char **argv, const char *prefix, struct repository *repo);
int cmd_for_each_repo(int argc, const char **argv, const char *prefix, struct repository *repo);
int cmd_format_patch(int argc, const char **argv, const char *prefix, struct repository *repo);
int cmd_format_rev(int argc, const char **argv, const char *prefix, struct repository *repo);
int cmd_fsck(int argc, const char **argv, const char *prefix, struct repository *repo);
int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix, struct repository *repo);
int cmd_gc(int argc, const char **argv, const char *prefix, struct repository *repo);
@ -271,6 +272,7 @@ int cmd_update_server_info(int argc, const char **argv, const char *prefix, stru
int cmd_upload_archive(int argc, const char **argv, const char *prefix, struct repository *repo);
int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix, struct repository *repo);
int cmd_upload_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
int cmd_url_parse(int argc, const char **argv, const char *prefix, struct repository *repo);
int cmd_var(int argc, const char **argv, const char *prefix, struct repository *repo);
int cmd_verify_commit(int argc, const char **argv, const char *prefix, struct repository *repo);
int cmd_verify_tag(int argc, const char **argv, const char *prefix, struct repository *repo);

View File

@ -16,6 +16,7 @@
#include "run-command.h"
#include "object-file.h"
#include "odb.h"
#include "odb/transaction.h"
#include "parse-options.h"
#include "path.h"
#include "preload-index.h"

View File

@ -490,9 +490,11 @@ static int run_applypatch_msg_hook(struct am_state *state)

assert(state->msg);

if (!state->no_verify)
ret = run_hooks_l(the_repository, "applypatch-msg",
am_path(state, "final-commit"), NULL);
if (!state->no_verify) {
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT_FORCE_SERIAL;
strvec_push(&opt.args, am_path(state, "final-commit"));
ret = run_hooks_opt(the_repository, "applypatch-msg", &opt);
}

if (!ret) {
FREE_AND_NULL(state->msg);

View File

@ -26,7 +26,7 @@
#include "path-walk.h"

static const char * const builtin_backfill_usage[] = {
N_("git backfill [--min-batch-size=<n>] [--[no-]sparse]"),
N_("git backfill [--min-batch-size=<n>] [--[no-]sparse] [--[no-]include-edges] [<revision-range>]"),
NULL
};

@ -35,6 +35,7 @@ struct backfill_context {
struct oid_array current_batch;
size_t min_batch_size;
int sparse;
int include_edges;
struct rev_info revs;
};

@ -78,6 +79,28 @@ static int fill_missing_blobs(const char *path UNUSED,
return 0;
}

static void reject_unsupported_rev_list_options(struct rev_info *revs)
{
if (revs->diffopt.pickaxe)
die(_("'%s' cannot be used with 'git backfill'"),
(revs->diffopt.pickaxe_opts & DIFF_PICKAXE_REGEX) ? "-G" : "-S");
if (revs->diffopt.filter || revs->diffopt.filter_not)
die(_("'%s' cannot be used with 'git backfill'"),
"--diff-filter");
if (revs->diffopt.flags.follow_renames)
die(_("'%s' cannot be used with 'git backfill'"),
"--follow");
if (revs->line_level_traverse)
die(_("'%s' cannot be used with 'git backfill'"),
"-L");
if (revs->explicit_diff_merges)
die(_("'%s' cannot be used with 'git backfill'"),
"--diff-merges");
if (revs->filter.choice)
die(_("'%s' cannot be used with 'git backfill'"),
"--filter");
}

static int do_backfill(struct backfill_context *ctx)
{
struct path_walk_info info = PATH_WALK_INFO_INIT;
@ -94,6 +117,8 @@ static int do_backfill(struct backfill_context *ctx)
/* Walk from HEAD if otherwise unspecified. */
if (!ctx->revs.pending.nr)
add_head_to_pending(&ctx->revs);
if (ctx->include_edges)
ctx->revs.edge_hint = 1;

info.blobs = 1;
info.tags = info.commits = info.trees = 0;
@ -121,12 +146,15 @@ int cmd_backfill(int argc, const char **argv, const char *prefix, struct reposit
.min_batch_size = 50000,
.sparse = -1,
.revs = REV_INFO_INIT,
.include_edges = 1,
};
struct option options[] = {
OPT_UNSIGNED(0, "min-batch-size", &ctx.min_batch_size,
N_("Minimum number of objects to request at a time")),
OPT_BOOL(0, "sparse", &ctx.sparse,
N_("Restrict the missing objects to the current sparse-checkout")),
OPT_BOOL(0, "include-edges", &ctx.include_edges,
N_("Include blobs from boundary commits in the backfill")),
OPT_END(),
};
struct repo_config_values *cfg = repo_config_values(the_repository);
@ -144,6 +172,7 @@ int cmd_backfill(int argc, const char **argv, const char *prefix, struct reposit

if (argc > 1)
die(_("unrecognized argument: %s"), argv[1]);
reject_unsupported_rev_list_options(&ctx.revs);

repo_config(repo, git_default_config, NULL);


View File

@ -708,7 +708,7 @@ static unsigned parse_score(const char *arg)

static char *add_prefix(const char *prefix, const char *path)
{
return prefix_path(prefix, prefix ? strlen(prefix) : 0, path);
return prefix_path(the_repository, prefix, prefix ? strlen(prefix) : 0, path);
}

static int git_blame_config(const char *var, const char *value,

View File

@ -67,7 +67,7 @@ static void check_attr(const char *prefix, struct attr_check *check,

{
char *full_path =
prefix_path(prefix, prefix ? strlen(prefix) : 0, file);
prefix_path(the_repository, prefix, prefix ? strlen(prefix) : 0, file);

if (collect_all) {
git_all_attrs(the_repository->index, full_path, check);
@ -117,7 +117,7 @@ int cmd_check_attr(int argc,
int cnt, i, doubledash, filei;

if (!is_bare_repository())
setup_work_tree();
setup_work_tree(the_repository);

repo_config(the_repository, git_default_config, NULL);


View File

@ -1,6 +1,9 @@
/*
* GIT - The information manager from hell
*/

#define USE_THE_REPOSITORY_VARIABLE

#include "builtin.h"
#include "refs.h"
#include "setup.h"
@ -41,7 +44,7 @@ static int check_ref_format_branch(const char *arg)
const char *name;
int nongit;

setup_git_directory_gently(&nongit);
setup_git_directory_gently(the_repository, &nongit);
if (check_branch_ref(&sb, arg) ||
!skip_prefix(sb.buf, "refs/heads/", &name))
die("'%s' is not a valid branch name", arg);

View File

@ -303,7 +303,7 @@ int cmd_checkout_index(int argc,
die("git checkout-index: don't mix '--all' and explicit filenames");
if (read_from_stdin)
die("git checkout-index: don't mix '--stdin' and explicit filenames");
p = prefix_path(prefix, prefix_length, arg);
p = prefix_path(repo, prefix, prefix_length, arg);
err |= checkout_file(repo->index, p, prefix);
free(p);
}
@ -325,7 +325,7 @@ int cmd_checkout_index(int argc,
die("line is badly quoted");
strbuf_swap(&buf, &unquoted);
}
p = prefix_path(prefix, prefix_length, buf.buf);
p = prefix_path(repo, prefix, prefix_length, buf.buf);
err |= checkout_file(repo->index, p, prefix);
free(p);
}

View File

@ -17,7 +17,6 @@
#include "merge-ll.h"
#include "lockfile.h"
#include "mem-pool.h"
#include "merge-ort-wrappers.h"
#include "object-file.h"
#include "object-name.h"
#include "odb.h"
@ -30,7 +29,9 @@
#include "repo-settings.h"
#include "resolve-undo.h"
#include "revision.h"
#include "sequencer.h"
#include "setup.h"
#include "strvec.h"
#include "submodule.h"
#include "symlinks.h"
#include "trace2.h"
@ -99,6 +100,8 @@ struct checkout_opts {
.auto_advance = 1, \
}

#define MERGE_WORKING_TREE_UNPACK_FAILED (-2)

struct branch_info {
char *name; /* The short name used */
char *path; /* The full name of a real branch */
@ -123,13 +126,19 @@ static void branch_info_release(struct branch_info *info)
static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,
int changed)
{
return run_hooks_l(the_repository, "post-checkout",
oid_to_hex(old_commit ? &old_commit->object.oid : null_oid(the_hash_algo)),
oid_to_hex(new_commit ? &new_commit->object.oid : null_oid(the_hash_algo)),
changed ? "1" : "0", NULL);
/* "new_commit" can be NULL when checking out from the index before
a commit exists. */
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT_FORCE_SERIAL;

/*
* "new_commit" can be NULL when checking out from the index before
* a commit exists.
*/
strvec_pushl(&opt.args,
oid_to_hex(old_commit ? &old_commit->object.oid : null_oid(the_hash_algo)),
oid_to_hex(new_commit ? &new_commit->object.oid : null_oid(the_hash_algo)),
changed ? "1" : "0",
NULL);

return run_hooks_opt(the_repository, "post-checkout", &opt);
}

static int update_some(const struct object_id *oid, struct strbuf *base,
@ -753,9 +762,9 @@ static void setup_branch_path(struct branch_info *branch)
branch->path = strbuf_detach(&buf, NULL);
}

static void init_topts(struct unpack_trees_options *topts, int merge,
static void init_topts(struct unpack_trees_options *topts,
int show_progress, int overwrite_ignore,
struct commit *old_commit)
bool quiet)
{
memset(topts, 0, sizeof(*topts));
topts->head_idx = -1;
@ -767,7 +776,7 @@ static void init_topts(struct unpack_trees_options *topts, int merge,
topts->initial_checkout = is_index_unborn(the_repository->index);
topts->update = 1;
topts->merge = 1;
topts->quiet = merge && old_commit;
topts->quiet = quiet;
topts->verbose_update = show_progress;
topts->fn = twoway_merge;
topts->preserve_ignored = !overwrite_ignore;
@ -776,6 +785,7 @@ static void init_topts(struct unpack_trees_options *topts, int merge,
static int merge_working_tree(const struct checkout_opts *opts,
struct branch_info *old_branch_info,
struct branch_info *new_branch_info,
bool quiet,
int *writeout_error)
{
int ret;
@ -783,8 +793,10 @@ static int merge_working_tree(const struct checkout_opts *opts,
struct tree *new_tree;

repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
if (repo_read_index_preload(the_repository, NULL, 0) < 0)
if (repo_read_index_preload(the_repository, NULL, 0) < 0) {
rollback_lock_file(&lock_file);
return error(_("index file corrupt"));
}

resolve_undo_clear_index(the_repository->index);
if (opts->new_orphan_branch && opts->orphan_from_empty_tree) {
@ -797,14 +809,18 @@ static int merge_working_tree(const struct checkout_opts *opts,
} else {
new_tree = repo_get_commit_tree(the_repository,
new_branch_info->commit);
if (!new_tree)
if (!new_tree) {
rollback_lock_file(&lock_file);
return error(_("unable to read tree (%s)"),
oid_to_hex(&new_branch_info->commit->object.oid));
}
}
if (opts->discard_changes) {
ret = reset_tree(new_tree, opts, 1, writeout_error, new_branch_info);
if (ret)
if (ret) {
rollback_lock_file(&lock_file);
return ret;
}
} else {
struct tree_desc trees[2];
struct tree *tree;
@ -814,13 +830,14 @@ static int merge_working_tree(const struct checkout_opts *opts,
refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);

if (unmerged_index(the_repository->index)) {
rollback_lock_file(&lock_file);
error(_("you need to resolve your current index first"));
return 1;
}

/* 2-way merge to the new branch */
init_topts(&topts, opts->merge, opts->show_progress,
opts->overwrite_ignore, old_branch_info->commit);
init_topts(&topts, opts->show_progress,
opts->overwrite_ignore, quiet);
init_checkout_metadata(&topts.meta, new_branch_info->refname,
new_branch_info->commit ?
&new_branch_info->commit->object.oid :
@ -846,82 +863,8 @@ static int merge_working_tree(const struct checkout_opts *opts,
ret = unpack_trees(2, trees, &topts);
clear_unpack_trees_porcelain(&topts);
if (ret == -1) {
/*
* Unpack couldn't do a trivial merge; either
* give up or do a real merge, depending on
* whether the merge flag was used.
*/
struct tree *work;
struct tree *old_tree;
struct merge_options o;
struct strbuf sb = STRBUF_INIT;
struct strbuf old_commit_shortname = STRBUF_INIT;

if (!opts->merge)
return 1;

/*
* Without old_branch_info->commit, the below is the same as
* the two-tree unpack we already tried and failed.
*/
if (!old_branch_info->commit)
return 1;
old_tree = repo_get_commit_tree(the_repository,
old_branch_info->commit);

if (repo_index_has_changes(the_repository, old_tree, &sb))
die(_("cannot continue with staged changes in "
"the following files:\n%s"), sb.buf);
strbuf_release(&sb);

/* Do more real merge */

/*
* We update the index fully, then write the
* tree from the index, then merge the new
* branch with the current tree, with the old
* branch as the base. Then we reset the index
* (but not the working tree) to the new
* branch, leaving the working tree as the
* merged version, but skipping unmerged
* entries in the index.
*/

add_files_to_cache(the_repository, NULL, NULL, NULL, 0,
0, 0);
init_ui_merge_options(&o, the_repository);
o.verbosity = 0;
work = write_in_core_index_as_tree(the_repository,
the_repository->index);

ret = reset_tree(new_tree,
opts, 1,
writeout_error, new_branch_info);
if (ret)
return ret;
o.ancestor = old_branch_info->name;
if (!old_branch_info->name) {
strbuf_add_unique_abbrev(&old_commit_shortname,
&old_branch_info->commit->object.oid,
DEFAULT_ABBREV);
o.ancestor = old_commit_shortname.buf;
}
o.branch1 = new_branch_info->name;
o.branch2 = "local";
o.conflict_style = opts->conflict_style;
ret = merge_ort_nonrecursive(&o,
new_tree,
work,
old_tree);
if (ret < 0)
die(NULL);
ret = reset_tree(new_tree,
opts, 0,
writeout_error, new_branch_info);
strbuf_release(&o.obuf);
strbuf_release(&old_commit_shortname);
if (ret)
return ret;
rollback_lock_file(&lock_file);
return MERGE_WORKING_TREE_UNPACK_FAILED;
}
}

@ -1166,6 +1109,10 @@ static int switch_branches(const struct checkout_opts *opts,
struct object_id rev;
int flag, writeout_error = 0;
int do_merge = 1;
int created_autostash = 0;
struct strbuf old_commit_shortname = STRBUF_INIT;
struct strbuf autostash_msg = STRBUF_INIT;
const char *stash_label_base = NULL;

trace2_cmd_mode("branch");

@ -1203,11 +1150,49 @@ static int switch_branches(const struct checkout_opts *opts,
do_merge = 0;
}

if (old_branch_info.name) {
stash_label_base = old_branch_info.name;
} else if (old_branch_info.commit) {
strbuf_add_unique_abbrev(&old_commit_shortname,
&old_branch_info.commit->object.oid,
DEFAULT_ABBREV);
stash_label_base = old_commit_shortname.buf;
}

if (do_merge) {
ret = merge_working_tree(opts, &old_branch_info, new_branch_info, &writeout_error);
ret = merge_working_tree(opts, &old_branch_info, new_branch_info,
opts->merge, &writeout_error);
if (ret == MERGE_WORKING_TREE_UNPACK_FAILED && opts->merge) {
strbuf_addf(&autostash_msg,
"autostash while switching to '%s'",
new_branch_info->name);
create_autostash_ref(the_repository,
"CHECKOUT_AUTOSTASH_HEAD",
autostash_msg.buf, true);
created_autostash = 1;
ret = merge_working_tree(opts, &old_branch_info, new_branch_info,
false, &writeout_error);
}
if (created_autostash) {
if (opts->conflict_style >= 0) {
struct strbuf cfg = STRBUF_INIT;
strbuf_addf(&cfg, "merge.conflictStyle=%s",
conflict_style_name(opts->conflict_style));
git_config_push_parameter(cfg.buf);
strbuf_release(&cfg);
}
apply_autostash_ref(the_repository,
"CHECKOUT_AUTOSTASH_HEAD",
new_branch_info->name,
"local",
stash_label_base,
autostash_msg.buf);
}
if (ret) {
branch_info_release(&old_branch_info);
return ret;
strbuf_release(&old_commit_shortname);
strbuf_release(&autostash_msg);
return ret < 0 ? 1 : ret;
}
}

@ -1216,8 +1201,22 @@ static int switch_branches(const struct checkout_opts *opts,

update_refs_for_switch(opts, &old_branch_info, new_branch_info);

if (created_autostash) {
discard_index(the_repository->index);
if (repo_read_index(the_repository) < 0)
die(_("index file corrupt"));

if (!opts->quiet && new_branch_info->commit) {
printf(_("The following paths have local changes:\n"));
show_local_changes(&new_branch_info->commit->object,
&opts->diff_options);
}
}

ret = post_checkout_hook(old_branch_info.commit, new_branch_info->commit, 1);
branch_info_release(&old_branch_info);
strbuf_release(&old_commit_shortname);
strbuf_release(&autostash_msg);

return ret || writeout_error;
}
@ -1485,7 +1484,7 @@ static int parse_branchname_arg(int argc, const char **argv,
* it would be extremely annoying.
*/
if (argc)
verify_non_filename(opts->prefix, arg);
verify_non_filename(the_repository, opts->prefix, arg);
} else if (opts->accept_pathspec) {
argcount++;
argv++;

View File

@ -647,6 +647,7 @@ static int checkout(int submodule_progress,
struct tree *tree;
struct tree_desc t;
int err = 0;
struct run_hooks_opt hook_opt = RUN_HOOKS_OPT_INIT_FORCE_SERIAL;

if (option_no_checkout)
return 0;
@ -668,7 +669,7 @@ static int checkout(int submodule_progress,
}

/* We need to be in the new work tree for the checkout */
setup_work_tree();
setup_work_tree(the_repository);

repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);

@ -697,8 +698,9 @@ static int checkout(int submodule_progress,
if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));

err |= run_hooks_l(the_repository, "post-checkout", oid_to_hex(null_oid(the_hash_algo)),
oid_to_hex(&oid), "1", NULL);
strvec_pushl(&hook_opt.args, oid_to_hex(null_oid(the_hash_algo)),
oid_to_hex(&oid), "1", NULL);
err |= run_hooks_opt(the_repository, "post-checkout", &hook_opt);

if (!err && (option_recurse_submodules.nr > 0)) {
struct child_process cmd = CHILD_PROCESS_INIT;
@ -1114,7 +1116,7 @@ int cmd_clone(int argc,
die_errno(_("could not create work tree dir '%s'"),
work_tree);
junk_work_tree = work_tree;
set_git_work_tree(work_tree);
set_git_work_tree(the_repository, work_tree);
}

if (real_git_dir) {
@ -1184,7 +1186,7 @@ int cmd_clone(int argc,
* repository, and reference backends may persist that information into
* their on-disk data structures.
*/
init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN,
init_db(the_repository, git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN,
ref_storage_format, NULL,
do_not_override_repo_unix_permissions, INIT_DB_QUIET | INIT_DB_SKIP_REFDB);

@ -1227,7 +1229,7 @@ int cmd_clone(int argc,
*
* This is sufficient for Git commands to discover the Git directory.
*/
initialize_repository_version(GIT_HASH_UNKNOWN,
initialize_repository_version(the_repository, GIT_HASH_UNKNOWN,
the_repository->ref_storage_format, 1);

refs_create_refdir_stubs(the_repository, git_dir, NULL);
@ -1440,9 +1442,9 @@ int cmd_clone(int argc,
* ours to the same thing.
*/
hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
initialize_repository_version(hash_algo, the_repository->ref_storage_format, 1);
initialize_repository_version(the_repository, hash_algo, the_repository->ref_storage_format, 1);
repo_set_hash_algo(the_repository, hash_algo);
create_reference_database(NULL, 1);
create_reference_database(the_repository, NULL, 1);

/*
* Before fetching from the remote, download and install bundle

View File

@ -1979,7 +1979,8 @@ int cmd_commit(int argc,
&oid, flags);
}

apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
apply_autostash_ref(the_repository, "MERGE_AUTOSTASH",
NULL, NULL, NULL, NULL);

cleanup:
free_commit_extra_headers(extra);

View File

@ -781,7 +781,7 @@ int cmd_describe(int argc,
struct rev_info revs;
int fd;

setup_work_tree();
setup_work_tree(the_repository);
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;
repo_read_index(the_repository);

View File

@ -69,7 +69,7 @@ int cmd_diff_index(int argc,
rev.max_count != -1 || rev.min_age != -1 || rev.max_age != -1)
usage(diff_cache_usage);
if (!(option & DIFF_INDEX_CACHED)) {
setup_work_tree();
setup_work_tree(the_repository);
if (repo_read_index_preload(the_repository, &rev.diffopt.pathspec, 0) < 0) {
perror("repo_read_index_preload");
return -1;

View File

@ -159,7 +159,7 @@ static void builtin_diff_index(struct rev_info *revs,
revs->max_age != -1)
usage(builtin_diff_usage);
if (!(option & DIFF_INDEX_CACHED)) {
setup_work_tree();
setup_work_tree(the_repository);
if (repo_read_index_preload(the_repository,
&revs->diffopt.pathspec, 0) < 0) {
die_errno("repo_read_index_preload");
@ -281,7 +281,7 @@ static void builtin_diff_files(struct rev_info *revs, int argc, const char **arg
(revs->diffopt.output_format & DIFF_FORMAT_PATCH))
diff_merges_set_dense_combined_if_unset(revs);

setup_work_tree();
setup_work_tree(the_repository);
if (repo_read_index_preload(the_repository, &revs->diffopt.pathspec,
0) < 0) {
die_errno("repo_read_index_preload");
@ -455,7 +455,7 @@ int cmd_diff(int argc,
break;
}

prefix = setup_git_directory_gently(&nongit);
prefix = setup_git_directory_gently(the_repository, &nongit);

if (!nongit) {
prepare_repo_settings(the_repository);
@ -471,8 +471,8 @@ int cmd_diff(int argc,
* as a colourful "diff" replacement.
*/
if (nongit || ((argc == i + 2) &&
(!path_inside_repo(prefix, argv[i]) ||
!path_inside_repo(prefix, argv[i + 1]))))
(!path_inside_repo(the_repository, prefix, argv[i]) ||
!path_inside_repo(the_repository, prefix, argv[i + 1]))))
no_index = DIFF_NO_INDEX_IMPLICIT;
}


View File

@ -767,7 +767,7 @@ int cmd_difftool(int argc,
die(_("difftool requires worktree or --no-index"));

if (!no_index){
setup_work_tree();
setup_work_tree(repo);
setenv(GIT_DIR_ENVIRONMENT, absolute_path(repo_get_git_dir(repo)), 1);
setenv(GIT_WORK_TREE_ENVIRONMENT, absolute_path(repo_get_work_tree(repo)), 1);
} else if (dir_diff)

View File

@ -98,7 +98,8 @@ static struct transport *gtransport;
static struct transport *gsecondary;
static struct refspec refmap = REFSPEC_INIT_FETCH;
static struct string_list server_options = STRING_LIST_INIT_DUP;
static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
static struct string_list negotiation_restrict = STRING_LIST_INIT_NODUP;
static struct string_list negotiation_include = STRING_LIST_INIT_NODUP;

struct fetch_config {
enum display_format display_format;
@ -1534,23 +1535,29 @@ static int add_oid(const struct reference *ref, void *cb_data)
return 0;
}

static void add_negotiation_tips(struct git_transport_options *smart_options)
static void add_negotiation_tips(struct string_list *input_list,
struct oid_array **output_list,
const char *argname)
{
struct oid_array *oids = xcalloc(1, sizeof(*oids));
int i;

for (i = 0; i < negotiation_tip.nr; i++) {
const char *s = negotiation_tip.items[i].string;
for (i = 0; i < input_list->nr; i++) {
const char *s = input_list->items[i].string;
struct refs_for_each_ref_options opts = {
.pattern = s,
};
int old_nr;
if (!has_glob_specials(s)) {
struct object_id oid;

/* Ignore missing reference. */
if (repo_get_oid(the_repository, s, &oid))
die(_("%s is not a valid object"), s);
continue;
/* Fail on missing object pointed by ref. */
if (!odb_has_object(the_repository->objects, &oid, 0))
die(_("the object %s does not exist"), s);

oid_array_append(oids, &oid);
continue;
}
@ -1558,10 +1565,10 @@ static void add_negotiation_tips(struct git_transport_options *smart_options)
refs_for_each_ref_ext(get_main_ref_store(the_repository),
add_oid, oids, &opts);
if (old_nr == oids->nr)
warning("ignoring --negotiation-tip=%s because it does not match any refs",
s);
warning(_("ignoring %s=%s because it does not match any refs"),
argname, s);
}
smart_options->negotiation_tips = oids;
*output_list = oids;
}

static struct transport *prepare_transport(struct remote *remote, int deepen,
@ -1595,11 +1602,50 @@ static struct transport *prepare_transport(struct remote *remote, int deepen,
set_option(transport, TRANS_OPT_LIST_OBJECTS_FILTER, spec);
set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
}
if (negotiation_tip.nr) {
if (negotiation_restrict.nr) {
if (transport->smart_options)
add_negotiation_tips(transport->smart_options);
add_negotiation_tips(&negotiation_restrict,
&transport->smart_options->negotiation_restrict_tips,
"--negotiation-restrict");
else
warning("ignoring --negotiation-tip because the protocol does not support it");
warning(_("ignoring %s because the protocol does not support it"),
"--negotiation-restrict");
} else if (remote->negotiation_restrict.nr) {
struct string_list_item *item;
for_each_string_list_item(item, &remote->negotiation_restrict)
string_list_append(&negotiation_restrict, item->string);
if (transport->smart_options)
add_negotiation_tips(&negotiation_restrict,
&transport->smart_options->negotiation_restrict_tips,
"--negotiation-restrict");
else {
struct strbuf config_name = STRBUF_INIT;
strbuf_addf(&config_name, "remote.%s.negotiationRestrict", remote->name);
warning(_("ignoring %s because the protocol does not support it"),
config_name.buf);
strbuf_release(&config_name);
}
}
if (negotiation_include.nr) {
if (transport->smart_options)
add_negotiation_tips(&negotiation_include,
&transport->smart_options->negotiation_include_tips,
"--negotiation-include");
else
warning(_("ignoring %s because the protocol does not support it"),
"--negotiation-include");
} else if (remote->negotiation_include.nr) {
if (transport->smart_options) {
add_negotiation_tips(&remote->negotiation_include,
&transport->smart_options->negotiation_include_tips,
"--negotiation-include");
} else {
struct strbuf config_name = STRBUF_INIT;
strbuf_addf(&config_name, "remote.%s.negotiationInclude", remote->name);
warning(_("ignoring %s because the protocol does not support it"),
config_name.buf);
strbuf_release(&config_name);
}
}
return transport;
}
@ -2565,8 +2611,11 @@ int cmd_fetch(int argc,
N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg),
OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
OPT_IPVERSION(&family),
OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"),
OPT_STRING_LIST(0, "negotiation-restrict", &negotiation_restrict, N_("revision"),
N_("report that we have only objects reachable from this object")),
OPT_ALIAS(0, "negotiation-tip", "negotiation-restrict"),
OPT_STRING_LIST(0, "negotiation-include", &negotiation_include, N_("revision"),
N_("ensure this ref is always sent as a negotiation have")),
OPT_BOOL(0, "negotiate-only", &negotiate_only,
N_("do not fetch a packfile; instead, print ancestors of negotiation tips")),
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
@ -2656,9 +2705,6 @@ int cmd_fetch(int argc,
config.display_format = DISPLAY_FORMAT_PORCELAIN;
}

if (negotiate_only && !negotiation_tip.nr)
die(_("--negotiate-only needs one or more --negotiation-tip=*"));

if (deepen_relative) {
if (deepen_relative < 0)
die(_("negative depth in --deepen is not supported"));
@ -2746,14 +2792,19 @@ int cmd_fetch(int argc,
if (!remote)
die(_("must supply remote when using --negotiate-only"));
gtransport = prepare_transport(remote, 1, &filter_options);
if (gtransport->smart_options) {
gtransport->smart_options->acked_commits = &acked_commits;
} else {

if (!gtransport->smart_options) {
warning(_("protocol does not support --negotiate-only, exiting"));
result = 1;
trace2_region_leave("fetch", "negotiate-only", the_repository);
goto cleanup;
}
if (!gtransport->smart_options->negotiation_restrict_tips)
die(_("%s needs one or more %s"), "--negotiate-only",
"--negotiation-restrict=*");

gtransport->smart_options->acked_commits = &acked_commits;

if (server_options.nr)
gtransport->server_options = &server_options;
result = transport_fetch_refs(gtransport, NULL);

View File

@ -1590,6 +1590,7 @@ static int maintenance_task_geometric_repack(struct maintenance_run_opts *opts,
pack_geometry_split(&geometry);

child.git_cmd = 1;
child.odb_to_close = the_repository->objects;

strvec_pushl(&child.args, "repack", "-d", "-l", NULL);
if (geometry.split < geometry.pack_nr)

View File

@ -28,9 +28,12 @@
#include "object-file.h"
#include "object-name.h"
#include "odb.h"
#include "oid-array.h"
#include "oidset.h"
#include "packfile.h"
#include "pager.h"
#include "path.h"
#include "promisor-remote.h"
#include "read-cache-ll.h"
#include "write-or-die.h"

@ -692,6 +695,144 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
return hit;
}

static void collect_blob_oids_for_tree(struct repository *repo,
const struct pathspec *pathspec,
struct tree_desc *tree,
struct strbuf *base,
int tn_len,
struct oidset *blob_oids)
{
struct name_entry entry;
int old_baselen = base->len;
struct strbuf name = STRBUF_INIT;
enum interesting match = entry_not_interesting;

while (tree_entry(tree, &entry)) {
if (match != all_entries_interesting) {
strbuf_addstr(&name, base->buf + tn_len);
match = tree_entry_interesting(repo->index,
&entry, &name,
pathspec);
strbuf_reset(&name);

if (match == all_entries_not_interesting)
break;
if (match == entry_not_interesting)
continue;
}

strbuf_add(base, entry.path, tree_entry_len(&entry));

if (S_ISREG(entry.mode)) {
if (!odb_has_object(repo->objects, &entry.oid, 0))
oidset_insert(blob_oids, &entry.oid);
} else if (S_ISDIR(entry.mode)) {
enum object_type type;
struct tree_desc sub_tree;
void *data;
unsigned long size;

data = odb_read_object(repo->objects, &entry.oid,
&type, &size);
if (!data)
die(_("unable to read tree (%s)"),
oid_to_hex(&entry.oid));

strbuf_addch(base, '/');
init_tree_desc(&sub_tree, &entry.oid, data, size);
collect_blob_oids_for_tree(repo, pathspec, &sub_tree,
base, tn_len, blob_oids);
free(data);
}
/*
* ...no else clause for S_ISGITLINK: submodules have their
* own promisor configuration and would need separate fetches
* anyway.
*/

strbuf_setlen(base, old_baselen);
}

strbuf_release(&name);
}

static void collect_blob_oids_for_treeish(struct grep_opt *opt,
const struct pathspec *pathspec,
const struct object_id *tree_ish_oid,
const char *name,
struct oidset *blob_oids)
{
struct tree_desc tree;
void *data;
unsigned long size;
struct strbuf base = STRBUF_INIT;
int len;

data = odb_read_object_peeled(opt->repo->objects, tree_ish_oid,
OBJ_TREE, &size, NULL);

if (!data)
return;

len = name ? strlen(name) : 0;
if (len) {
strbuf_add(&base, name, len);
strbuf_addch(&base, ':');
}
init_tree_desc(&tree, tree_ish_oid, data, size);

collect_blob_oids_for_tree(opt->repo, pathspec, &tree,
&base, base.len, blob_oids);

strbuf_release(&base);
free(data);
}

static void prefetch_grep_blobs(struct grep_opt *opt,
const struct pathspec *pathspec,
const struct object_array *list)
{
struct oidset blob_oids = OIDSET_INIT;

/* Exit if we're not in a partial clone */
if (!repo_has_promisor_remote(opt->repo))
return;

/* For each tree, gather the blobs in it */
for (int i = 0; i < list->nr; i++) {
struct object *real_obj;

obj_read_lock();
real_obj = deref_tag(opt->repo, list->objects[i].item,
NULL, 0);
obj_read_unlock();

if (real_obj &&
(real_obj->type == OBJ_COMMIT ||
real_obj->type == OBJ_TREE))
collect_blob_oids_for_treeish(opt, pathspec,
&real_obj->oid,
list->objects[i].name,
&blob_oids);
}

/* Prefetch the blobs we found */
if (oidset_size(&blob_oids)) {
struct oid_array to_fetch = OID_ARRAY_INIT;
struct oidset_iter iter;
const struct object_id *oid;

oidset_iter_init(&blob_oids, &iter);
while ((oid = oidset_iter_next(&iter)))
oid_array_append(&to_fetch, oid);

promisor_remote_get_direct(opt->repo, to_fetch.oid, to_fetch.nr);

oid_array_clear(&to_fetch);
}
oidset_clear(&blob_oids);
}

static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
struct object *obj, const char *name, const char *path)
{
@ -732,6 +873,8 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
int hit = 0;
const unsigned int nr = list->nr;

prefetch_grep_blobs(opt, pathspec, list);

for (i = 0; i < nr; i++) {
struct object *real_obj;

@ -1064,7 +1207,7 @@ int cmd_grep(int argc,
use_index = 0;
else
/* die the same way as if we did it at the beginning */
setup_git_directory();
setup_git_directory(the_repository);
}
/* Ignore --recurse-submodules if --no-index is given or implied */
if (!use_index)
@ -1151,7 +1294,7 @@ int cmd_grep(int argc,

object = parse_object_or_die(the_repository, &oid, arg);
if (!seen_dashdash)
verify_non_filename(prefix, arg);
verify_non_filename(the_repository, prefix, arg);
add_object_array_with_path(object, arg, &list, oc.mode, oc.path);
object_context_release(&oc);
}
@ -1163,7 +1306,7 @@ int cmd_grep(int argc,
if (!seen_dashdash) {
int j;
for (j = i; j < argc; j++)
verify_filename(prefix, argv[j], j == i && allow_revs);
verify_filename(the_repository, prefix, argv[j], j == i && allow_revs);
}

parse_pathspec(&pathspec, 0,
@ -1272,7 +1415,7 @@ int cmd_grep(int argc,
die(_("--[no-]exclude-standard cannot be used for tracked contents"));
} else if (!list.nr) {
if (!cached)
setup_work_tree();
setup_work_tree(the_repository);

hit = grep_cache(&opt, &pathspec, cached);
} else {

View File

@ -100,9 +100,9 @@ int cmd_hash_object(int argc,
hash_object_usage, 0);

if (flags & INDEX_WRITE_OBJECT)
prefix = setup_git_directory();
prefix = setup_git_directory(the_repository);
else
prefix = setup_git_directory_gently(&nongit);
prefix = setup_git_directory_gently(the_repository, &nongit);

if (nongit && !the_hash_algo)
repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT);

View File

@ -740,7 +740,7 @@ int cmd_help(int argc,
return 0;
}

setup_git_directory_gently(&nongit);
setup_git_directory_gently(the_repository, &nongit);
repo_config(the_repository, git_help_config, NULL);

if (parsed_help_format != HELP_FORMAT_NONE)

View File

@ -10,6 +10,7 @@
#include "gettext.h"
#include "hex.h"
#include "lockfile.h"
#include "merge-ort.h"
#include "oidmap.h"
#include "parse-options.h"
#include "path.h"
@ -23,6 +24,8 @@
#include "unpack-trees.h"
#include "wt-status.h"

#define GIT_HISTORY_FIXUP_USAGE \
N_("git history fixup <commit> [--dry-run] [--update-refs=(branches|head)] [--reedit-message] [--empty=(drop|keep|abort)]")
#define GIT_HISTORY_REWORD_USAGE \
N_("git history reword <commit> [--dry-run] [--update-refs=(branches|head)]")
#define GIT_HISTORY_SPLIT_USAGE \
@ -91,13 +94,18 @@ static int fill_commit_message(struct repository *repo,
return 0;
}

static int commit_tree_with_edited_message_ext(struct repository *repo,
const char *action,
struct commit *commit_with_message,
const struct commit_list *parents,
const struct object_id *old_tree,
const struct object_id *new_tree,
struct commit **out)
enum commit_tree_flags {
COMMIT_TREE_EDIT_MESSAGE = (1 << 0),
};

static int commit_tree_ext(struct repository *repo,
const char *action,
struct commit *commit_with_message,
const struct commit_list *parents,
const struct object_id *old_tree,
const struct object_id *new_tree,
struct commit **out,
enum commit_tree_flags flags)
{
const char *exclude_gpgsig[] = {
/* We reencode the message, so the encoding needs to be stripped. */
@ -122,10 +130,14 @@ static int commit_tree_with_edited_message_ext(struct repository *repo,
original_author = xmemdupz(ptr, len);
find_commit_subject(original_message, &original_body);

ret = fill_commit_message(repo, old_tree, new_tree,
original_body, action, &commit_message);
if (ret < 0)
goto out;
if (flags & COMMIT_TREE_EDIT_MESSAGE) {
ret = fill_commit_message(repo, old_tree, new_tree,
original_body, action, &commit_message);
if (ret < 0)
goto out;
} else {
strbuf_addstr(&commit_message, original_body);
}

original_extra_headers = read_commit_extra_headers(commit_with_message,
exclude_gpgsig);
@ -168,8 +180,8 @@ static int commit_tree_with_edited_message(struct repository *repo,
oidcpy(&parent_tree_oid, repo->hash_algo->empty_tree);
}

return commit_tree_with_edited_message_ext(repo, action, original, original->parents,
&parent_tree_oid, tree_oid, out);
return commit_tree_ext(repo, action, original, original->parents,
&parent_tree_oid, tree_oid, out, COMMIT_TREE_EDIT_MESSAGE);
}

enum ref_action {
@ -326,10 +338,13 @@ static int handle_reference_updates(struct rev_info *revs,
struct commit *original,
struct commit *rewritten,
const char *reflog_msg,
int dry_run)
int dry_run,
enum replay_empty_commit_action empty)
{
const struct name_decoration *decoration;
struct replay_revisions_options opts = { 0 };
struct replay_revisions_options opts = {
.empty = empty,
};
struct replay_result result = { 0 };
struct ref_transaction *transaction = NULL;
struct strbuf err = STRBUF_INIT;
@ -425,6 +440,236 @@ out:
return ret;
}

static int commit_became_empty(struct repository *repo,
struct commit *original,
struct tree *result)
{
struct commit *parent = original->parents ? original->parents->item : NULL;
struct object_id parent_tree_oid;

if (parent) {
if (repo_parse_commit(repo, parent))
return error(_("unable to parse parent of %s"),
oid_to_hex(&original->object.oid));

parent_tree_oid = repo_get_commit_tree(repo, parent)->object.oid;
} else {
oidcpy(&parent_tree_oid, repo->hash_algo->empty_tree);
}

return oideq(&result->object.oid, &parent_tree_oid);
}

static int parse_opt_empty(const struct option *opt, const char *arg, int unset)
{
enum replay_empty_commit_action *value = opt->value;

BUG_ON_OPT_NEG(unset);

if (!strcmp(arg, "drop"))
*value = REPLAY_EMPTY_COMMIT_DROP;
else if (!strcmp(arg, "keep"))
*value = REPLAY_EMPTY_COMMIT_KEEP;
else if (!strcmp(arg, "abort"))
*value = REPLAY_EMPTY_COMMIT_ABORT;
else
die(_("unrecognized '--empty=' action '%s'; "
"valid values are \"drop\", \"keep\", and \"abort\"."), arg);

return 0;
}

static int cmd_history_fixup(int argc,
const char **argv,
const char *prefix,
struct repository *repo)
{
const char * const usage[] = {
GIT_HISTORY_FIXUP_USAGE,
NULL,
};
enum replay_empty_commit_action empty = REPLAY_EMPTY_COMMIT_DROP;
enum ref_action action = REF_ACTION_DEFAULT;
enum commit_tree_flags flags = 0;
int dry_run = 0;
struct option options[] = {
OPT_CALLBACK_F(0, "update-refs", &action, "(branches|head)",
N_("control which refs should be updated"),
PARSE_OPT_NONEG, parse_ref_action),
OPT_BOOL('n', "dry-run", &dry_run,
N_("perform a dry-run without updating any refs")),
OPT_BIT(0, "reedit-message", &flags,
N_("open an editor to modify the commit message"),
COMMIT_TREE_EDIT_MESSAGE),
OPT_CALLBACK_F(0, "empty", &empty, "(drop|keep|abort)",
N_("how to handle commits that become empty"),
PARSE_OPT_NONEG, parse_opt_empty),
OPT_END(),
};
struct merge_result merge_result = { 0 };
struct merge_options merge_opts = { 0 };
struct strbuf reflog_msg = STRBUF_INIT;
struct commit *head_commit, *original, *rewritten;
struct tree *head_tree, *original_tree, *index_tree;
struct rev_info revs = { 0 };
bool skip_commit = false;
int ret;

argc = parse_options(argc, argv, prefix, options, usage, 0);
if (argc != 1) {
ret = error(_("command expects a single revision"));
goto out;
}
repo_config(repo, git_default_config, NULL);

if (action == REF_ACTION_DEFAULT)
action = REF_ACTION_BRANCHES;

if (is_bare_repository()) {
ret = error(_("cannot run fixup in a bare repository"));
goto out;
}

/* Resolve the original commit, which is the one we want to fix up. */
original = lookup_commit_reference_by_name(argv[0]);
if (!original) {
ret = error(_("commit cannot be found: %s"), argv[0]);
goto out;
}

/*
* Resolve HEAD so we can use its tree as the merge base: the staged
* changes are expressed as a diff from HEAD's tree to the index tree.
*/
head_commit = lookup_commit_reference_by_name("HEAD");
if (!head_commit) {
ret = error(_("cannot look up HEAD"));
goto out;
}

head_tree = repo_get_commit_tree(repo, head_commit);
if (!head_tree) {
ret = error(_("cannot get tree for HEAD"));
goto out;
}

if (repo_read_index(repo) < 0) {
ret = error(_("unable to read index"));
goto out;
}

if (!repo_index_has_changes(repo, head_tree, NULL)) {
ret = error(_("nothing to fixup: no staged changes"));
goto out;
}

/*
* Write the index as a tree object. This is the "theirs" side of the
* three-way merge: it is HEAD's tree with the staged changes applied.
*/
index_tree = write_in_core_index_as_tree(repo, repo->index);
if (!index_tree) {
ret = error(_("unable to write index as a tree"));
goto out;
}

original_tree = repo_get_commit_tree(repo, original);
if (!original_tree) {
ret = error(_("cannot get tree for commit %s"), argv[0]);
goto out;
}

/*
* Perform the three-way merge to reapply changes in the index onto the
* target commit. This is using basically the same logic as a
* cherry-pick, where the base commit is our HEAD, ours is the original
* tree and theirs is the index tree.
*/
init_basic_merge_options(&merge_opts, repo);
merge_opts.ancestor = "HEAD";
merge_opts.branch1 = argv[0];
merge_opts.branch2 = "staged";
merge_incore_nonrecursive(&merge_opts, head_tree,
original_tree, index_tree, &merge_result);

if (merge_result.clean < 0) {
ret = error(_("merge failed while applying fixup"));
goto out;
}

if (!merge_result.clean) {
ret = error(_("fixup would produce conflicts; aborting"));
goto out;
}

ret = commit_became_empty(repo, original, merge_result.tree);
if (ret < 0)
goto out;
if (ret > 0) {
switch (empty) {
case REPLAY_EMPTY_COMMIT_DROP:
/*
* Drop the target commit by replaying its descendants
* directly onto its parent.
*/
rewritten = original->parents ? original->parents->item : NULL;

/*
* TODO: we don't yet have the ability to drop root
* commits, but there's ultimately no good reason for
* this restriction to exist other than a technical
* limitation.
*/
if (!rewritten) {
ret = error(_("cannot drop root commit %s: "
"it has no parent to replay onto"),
argv[0]);
goto out;
}

skip_commit = true;
break;
case REPLAY_EMPTY_COMMIT_KEEP:
/* Proceed and record the empty commit. */
break;
case REPLAY_EMPTY_COMMIT_ABORT:
ret = error(_("fixup makes commit %s empty"), argv[0]);
goto out;
}
}

ret = setup_revwalk(repo, action, original, &revs);
if (ret)
goto out;

if (!skip_commit) {
ret = commit_tree_ext(repo, "fixup", original, original->parents,
&original_tree->object.oid, &merge_result.tree->object.oid,
&rewritten, flags);
if (ret < 0) {
ret = error(_("failed writing fixed-up commit"));
goto out;
}
}

strbuf_addf(&reflog_msg, "fixup: updating %s", argv[0]);

ret = handle_reference_updates(&revs, action, original, rewritten,
reflog_msg.buf, dry_run, empty);
if (ret < 0) {
ret = error(_("failed replaying descendants"));
goto out;
}

ret = 0;

out:
merge_finalize(&merge_opts, &merge_result);
strbuf_release(&reflog_msg);
release_revisions(&revs);
return ret;
}

static int cmd_history_reword(int argc,
const char **argv,
const char *prefix,
@ -478,7 +723,7 @@ static int cmd_history_reword(int argc,
strbuf_addf(&reflog_msg, "reword: updating %s", argv[0]);

ret = handle_reference_updates(&revs, action, original, rewritten,
reflog_msg.buf, dry_run);
reflog_msg.buf, dry_run, REPLAY_EMPTY_COMMIT_ABORT);
if (ret < 0) {
ret = error(_("failed replaying descendants"));
goto out;
@ -616,9 +861,8 @@ static int split_commit(struct repository *repo,
* The first commit is constructed from the split-out tree. The base
* that shall be diffed against is the parent of the original commit.
*/
ret = commit_tree_with_edited_message_ext(repo, "split-out", original,
original->parents, &parent_tree_oid,
&split_tree->object.oid, &first_commit);
ret = commit_tree_ext(repo, "split-out", original, original->parents, &parent_tree_oid,
&split_tree->object.oid, &first_commit, COMMIT_TREE_EDIT_MESSAGE);
if (ret < 0) {
ret = error(_("failed writing first commit"));
goto out;
@ -634,9 +878,8 @@ static int split_commit(struct repository *repo,
old_tree_oid = &repo_get_commit_tree(repo, first_commit)->object.oid;
new_tree_oid = &repo_get_commit_tree(repo, original)->object.oid;

ret = commit_tree_with_edited_message_ext(repo, "split-out", original,
parents, old_tree_oid,
new_tree_oid, &second_commit);
ret = commit_tree_ext(repo, "split-out", original, parents, old_tree_oid,
new_tree_oid, &second_commit, COMMIT_TREE_EDIT_MESSAGE);
if (ret < 0) {
ret = error(_("failed writing second commit"));
goto out;
@ -717,7 +960,7 @@ static int cmd_history_split(int argc,
strbuf_addf(&reflog_msg, "split: updating %s", argv[0]);

ret = handle_reference_updates(&revs, action, original, rewritten,
reflog_msg.buf, dry_run);
reflog_msg.buf, dry_run, REPLAY_EMPTY_COMMIT_ABORT);
if (ret < 0) {
ret = error(_("failed replaying descendants"));
goto out;
@ -738,12 +981,14 @@ int cmd_history(int argc,
struct repository *repo)
{
const char * const usage[] = {
GIT_HISTORY_FIXUP_USAGE,
GIT_HISTORY_REWORD_USAGE,
GIT_HISTORY_SPLIT_USAGE,
NULL,
};
parse_opt_subcommand_fn *fn = NULL;
struct option options[] = {
OPT_SUBCOMMAND("fixup", &fn, cmd_history_fixup),
OPT_SUBCOMMAND("reword", &fn, cmd_history_reword),
OPT_SUBCOMMAND("split", &fn, cmd_history_split),
OPT_END(),

View File

@ -4,23 +4,15 @@
#include "environment.h"
#include "gettext.h"
#include "hook.h"
#include "hook-list.h"
#include "parse-options.h"
#include "thread-utils.h"

#define BUILTIN_HOOK_RUN_USAGE \
N_("git hook run [--allow-unknown-hook-name] [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-args>]")
N_("git hook run [--allow-unknown-hook-name] [--ignore-missing] [--to-stdin=<path>] [(-j|--jobs) <n>]\n" \
"<hook-name> [-- <hook-args>]")
#define BUILTIN_HOOK_LIST_USAGE \
N_("git hook list [--allow-unknown-hook-name] [-z] [--show-scope] <hook-name>")

static int is_known_hook(const char *name)
{
const char **p;
for (p = hook_name_list; *p; p++)
if (!strcmp(*p, name))
return 1;
return 0;
}

static const char * const builtin_hook_usage[] = {
BUILTIN_HOOK_RUN_USAGE,
BUILTIN_HOOK_LIST_USAGE,
@ -96,14 +88,22 @@ static int list(int argc, const char **argv, const char *prefix,
const char *name = h->u.configured.friendly_name;
const char *scope = show_scope ?
config_scope_name(h->u.configured.scope) : NULL;
/*
* Show the most relevant disable reason. Event-level
* takes precedence: if the whole event is off, that
* is what the user needs to know. The per-hook
* "disabled" surfaces once the event is re-enabled.
*/
const char *disability =
h->u.configured.event_disabled ? "event-disabled\t" :
h->u.configured.disabled ? "disabled\t" :
"";
if (scope)
printf("%s\t%s%s%c", scope,
h->u.configured.disabled ? "disabled\t" : "",
name, line_terminator);
printf("%s\t%s%s%c", scope, disability, name,
line_terminator);
else
printf("%s%s%c",
h->u.configured.disabled ? "disabled\t" : "",
name, line_terminator);
printf("%s%s%c", disability, name,
line_terminator);
break;
}
default:
@ -124,6 +124,7 @@ static int run(int argc, const char **argv, const char *prefix,
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
int ignore_missing = 0;
int allow_unknown = 0;
int jobs = 0;
const char *hook_name;
struct option run_options[] = {
OPT_BOOL(0, "allow-unknown-hook-name", &allow_unknown,
@ -132,6 +133,8 @@ static int run(int argc, const char **argv, const char *prefix,
N_("silently ignore missing requested <hook-name>")),
OPT_STRING(0, "to-stdin", &opt.path_to_stdin, N_("path"),
N_("file to read into hooks' stdin")),
OPT_INTEGER('j', "jobs", &jobs,
N_("run up to <n> hooks simultaneously (-1 for CPU count)")),
OPT_END(),
};
int ret;
@ -140,6 +143,15 @@ static int run(int argc, const char **argv, const char *prefix,
builtin_hook_run_usage,
PARSE_OPT_KEEP_DASHDASH);

if (jobs == -1)
opt.jobs = online_cpus();
else if (jobs < 0)
die(_("invalid value for -j: %d"
" (use -1 for CPU count or a"
" positive integer)"), jobs);
else
opt.jobs = jobs;

if (!argc)
goto usage;


View File

@ -37,7 +37,7 @@ static const char index_pack_usage[] =

struct object_entry {
struct pack_idx_entry idx;
unsigned long size;
size_t size;
unsigned char hdr_size;
signed char type;
signed char real_type;
@ -145,8 +145,7 @@ static int check_self_contained_and_connected;

static struct progress *progress;

/* We always read in 4kB chunks. */
static unsigned char input_buffer[4096];
static unsigned char input_buffer[DEFAULT_IO_BUFFER_SIZE];
static unsigned int input_offset, input_len;
static off_t consumed_bytes;
static off_t max_input_size;
@ -469,7 +468,7 @@ static int is_delta_type(enum object_type type)
return (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA);
}

static void *unpack_entry_data(off_t offset, unsigned long size,
static void *unpack_entry_data(off_t offset, size_t size,
enum object_type type, struct object_id *oid)
{
static char fixed_buf[8192];
@ -524,7 +523,7 @@ static void *unpack_raw_entry(struct object_entry *obj,
struct object_id *oid)
{
unsigned char *p;
unsigned long size, c;
size_t size, c;
off_t base_offset;
unsigned shift;
void *data;
@ -539,6 +538,8 @@ static void *unpack_raw_entry(struct object_entry *obj,
size = (c & 15);
shift = 4;
while (c & 0x80) {
if ((bitsizeof(size_t) - 7) < shift)
die(_("object size too large for this platform"));
p = fill(1);
c = *p;
use(1);

View File

@ -237,9 +237,9 @@ int cmd_init_db(int argc,
if (!git_work_tree_cfg)
git_work_tree_cfg = xgetcwd();
if (work_tree)
set_git_work_tree(work_tree);
set_git_work_tree(the_repository, work_tree);
else
set_git_work_tree(git_work_tree_cfg);
set_git_work_tree(the_repository, git_work_tree_cfg);
if (access(repo_get_work_tree(the_repository), X_OK))
die_errno (_("Cannot access work tree '%s'"),
repo_get_work_tree(the_repository));
@ -248,11 +248,11 @@ int cmd_init_db(int argc,
if (real_git_dir)
die(_("--separate-git-dir incompatible with bare repository"));
if (work_tree)
set_git_work_tree(work_tree);
set_git_work_tree(the_repository, work_tree);
}

flags |= INIT_DB_EXIST_OK;
ret = init_db(git_dir, real_git_dir, template_dir, hash_algo,
ret = init_db(the_repository, git_dir, real_git_dir, template_dir, hash_algo,
ref_storage_format, initial_branch,
init_shared_repository, flags);


View File

@ -21,10 +21,12 @@
#include "color.h"
#include "commit.h"
#include "diff.h"
#include "diffcore.h"
#include "diff-merges.h"
#include "revision.h"
#include "log-tree.h"
#include "oid-array.h"
#include "oidset.h"
#include "tag.h"
#include "reflog-walk.h"
#include "patch-ids.h"
@ -43,9 +45,11 @@
#include "utf8.h"

#include "commit-reach.h"
#include "promisor-remote.h"
#include "range-diff.h"
#include "tmp-objdir.h"
#include "tree.h"
#include "userdiff.h"
#include "write-or-die.h"

#define MAIL_DEFAULT_WRAP 72
@ -2602,6 +2606,131 @@ static void print_commit(char sign, struct commit *commit, int verbose,
}
}

/*
* Enumerate blob OIDs from a single commit's diff, inserting them into blobs.
* Skips files whose userdiff driver explicitly declares binary status
* (drv->binary > 0), since patch-ID uses oid_to_hex() for those and
* never reads blob content. Use userdiff_find_by_path() since
* diff_filespec_load_driver() is static in diff.c.
*
* Clean up with diff_queue_clear() (from diffcore.h).
*/
static void collect_diff_blob_oids(struct commit *commit,
struct diff_options *opts,
struct oidset *blobs)
{
struct diff_queue_struct *q;

/*
* Merge commits are filtered out by patch_id_defined() in patch-ids.c,
* so we'll never be called with one.
*/
assert(!commit->parents || !commit->parents->next);

if (commit->parents)
diff_tree_oid(&commit->parents->item->object.oid,
&commit->object.oid, "", opts);
else
diff_root_tree_oid(&commit->object.oid, "", opts);
diffcore_std(opts);

q = &diff_queued_diff;
for (int i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
struct userdiff_driver *drv;

/* Skip binary files */
drv = userdiff_find_by_path(opts->repo->index, p->one->path);
if (drv && drv->binary > 0)
continue;

if (DIFF_FILE_VALID(p->one) &&
odb_read_object_info_extended(opts->repo->objects,
&p->one->oid, NULL,
OBJECT_INFO_FOR_PREFETCH))
oidset_insert(blobs, &p->one->oid);
if (DIFF_FILE_VALID(p->two) &&
odb_read_object_info_extended(opts->repo->objects,
&p->two->oid, NULL,
OBJECT_INFO_FOR_PREFETCH))
oidset_insert(blobs, &p->two->oid);
}
diff_queue_clear(q);
}

static int always_match(const void *cmp_data UNUSED,
const struct hashmap_entry *entry1 UNUSED,
const struct hashmap_entry *entry2 UNUSED,
const void *keydata UNUSED)
{
return 0;
}

/*
* Prefetch blobs for git cherry in partial clones.
*
* Called between the revision walk (which builds the head-side
* commit list) and the has_commit_patch_id() comparison loop.
*
* Uses a cmpfn-swap trick to avoid reading blobs: temporarily
* replaces the hashmap's comparison function with a trivial
* always-match function, so hashmap_get()/hashmap_get_next() match
* any entry with the same oidhash bucket. These are the set of oids
* that would trigger patch_id_neq() during normal lookup and cause
* blobs to be read on demand, and we want to prefetch them all at
* once instead.
*/
static void prefetch_cherry_blobs(struct repository *repo,
struct commit_list *list,
struct patch_ids *ids)
{
struct oidset blobs = OIDSET_INIT;
hashmap_cmp_fn original_cmpfn;

/* Exit if we're not in a partial clone */
if (!repo_has_promisor_remote(repo))
return;

/* Save original cmpfn, replace with always_match */
original_cmpfn = ids->patches.cmpfn;
ids->patches.cmpfn = always_match;

/* Find header-only collisions, gather blobs from those commits */
for (struct commit_list *l = list; l; l = l->next) {
struct commit *c = l->item;
bool match_found = false;
for (struct patch_id *cur = patch_id_iter_first(c, ids);
cur;
cur = patch_id_iter_next(cur, ids)) {
match_found = true;
collect_diff_blob_oids(cur->commit, &ids->diffopts,
&blobs);
}
if (match_found)
collect_diff_blob_oids(c, &ids->diffopts, &blobs);
}

/* Restore original cmpfn */
ids->patches.cmpfn = original_cmpfn;

/* If we have any blobs to fetch, fetch them */
if (oidset_size(&blobs)) {
struct oid_array to_fetch = OID_ARRAY_INIT;
struct oidset_iter iter;
const struct object_id *oid;

oidset_iter_init(&blobs, &iter);
while ((oid = oidset_iter_next(&iter)))
oid_array_append(&to_fetch, oid);

promisor_remote_get_direct(repo, to_fetch.oid, to_fetch.nr);

oid_array_clear(&to_fetch);
}

oidset_clear(&blobs);
}

int cmd_cherry(int argc,
const char **argv,
const char *prefix,
@ -2673,6 +2802,8 @@ int cmd_cherry(int argc,
commit_list_insert(commit, &list);
}

prefetch_cherry_blobs(the_repository, list, &ids);

for (struct commit_list *l = list; l; l = l->next) {
char sign = '+';


View File

@ -703,8 +703,8 @@ int cmd_ls_files(int argc,
if (dir.exclude_per_dir)
exc_given = 1;

if (require_work_tree && !is_inside_work_tree())
setup_work_tree();
if (require_work_tree && !is_inside_work_tree(repo))
setup_work_tree(repo);

if (recurse_submodules &&
(show_deleted || show_others || show_unmerged ||

View File

@ -11,10 +11,12 @@

static int show_merge_base(struct commit **rev, size_t rev_nr, int show_all)
{
enum merge_base_flags flags = show_all ? MERGE_BASE_FIND_ALL : 0;
struct commit_list *result = NULL, *r;

if (repo_get_merge_bases_many_dirty(the_repository, rev[0],
rev_nr - 1, rev + 1, &result) < 0) {
rev_nr - 1, rev + 1,
flags, &result) < 0) {
commit_list_free(result);
return -1;
}

View File

@ -110,7 +110,7 @@ int cmd_merge_file(int argc,

if (!repo && object_id)
/* emit the correct "not a git repo" error in this case */
setup_git_directory();
setup_git_directory(the_repository);

for (i = 0; i < 3; i++) {
char *fname;

View File

@ -537,7 +537,8 @@ static void finish(struct commit *head_commit,
run_hooks_l(the_repository, "post-merge", squash ? "1" : "0", NULL);

if (new_head)
apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
apply_autostash_ref(the_repository, "MERGE_AUTOSTASH",
NULL, NULL, NULL, NULL);
strbuf_release(&reflog_message);
}

@ -1672,12 +1673,14 @@ int cmd_merge(int argc,
}

if (autostash)
create_autostash_ref(the_repository, "MERGE_AUTOSTASH");
create_autostash_ref(the_repository, "MERGE_AUTOSTASH",
NULL, false);
if (checkout_fast_forward(the_repository,
&head_commit->object.oid,
&commit->object.oid,
overwrite_ignore)) {
apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
apply_autostash_ref(the_repository, "MERGE_AUTOSTASH",
NULL, NULL, NULL, NULL);
ret = 1;
goto done;
}
@ -1735,21 +1738,11 @@ int cmd_merge(int argc,
struct commit_list *j;

for (j = remoteheads; j; j = j->next) {
struct commit_list *common_one = NULL;
struct commit *common_item;

/*
* Here we *have* to calculate the individual
* merge_bases again, otherwise "git merge HEAD^
* HEAD^^" would be missed.
*/
if (repo_get_merge_bases(the_repository, head_commit,
j->item, &common_one) < 0)
int ret = repo_in_merge_bases(the_repository,
j->item, head_commit);
if (ret < 0)
exit(128);

common_item = common_one->item;
commit_list_free(common_one);
if (!oideq(&common_item->object.oid, &j->item->object.oid)) {
if (!ret) {
up_to_date = 0;
break;
}
@ -1764,7 +1757,8 @@ int cmd_merge(int argc,
die_ff_impossible();

if (autostash)
create_autostash_ref(the_repository, "MERGE_AUTOSTASH");
create_autostash_ref(the_repository, "MERGE_AUTOSTASH",
NULL, false);

/* We are going to make a new commit. */
git_committer_info(IDENT_STRICT);
@ -1849,7 +1843,8 @@ int cmd_merge(int argc,
else
fprintf(stderr, _("Merge with strategy %s failed.\n"),
use_strategies[0]->name);
apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
apply_autostash_ref(the_repository, "MERGE_AUTOSTASH",
NULL, NULL, NULL, NULL);
ret = 2;
goto done;
} else if (best_strategy == wt_strategy)

View File

@ -16,11 +16,13 @@
#define BUILTIN_MIDX_WRITE_USAGE \
N_("git multi-pack-index [<options>] write [--preferred-pack=<pack>]\n" \
" [--[no-]bitmap] [--[no-]incremental] [--[no-]stdin-packs]\n" \
" [--refs-snapshot=<path>]")
" [--refs-snapshot=<path>] [--[no-]write-chain-file]\n" \
" [--base=<checksum>]")

#define BUILTIN_MIDX_COMPACT_USAGE \
N_("git multi-pack-index [<options>] compact [--[no-]incremental]\n" \
" [--[no-]bitmap] <from> <to>")
" [--[no-]bitmap] [--base=<checksum>] [--[no-]write-chain-file]\n" \
" <from> <to>")

#define BUILTIN_MIDX_VERIFY_USAGE \
N_("git multi-pack-index [<options>] verify")
@ -63,6 +65,7 @@ static char const * const builtin_multi_pack_index_usage[] = {
static struct opts_multi_pack_index {
char *object_dir;
const char *preferred_pack;
const char *incremental_base;
char *refs_snapshot;
unsigned long batch_size;
unsigned flags;
@ -151,8 +154,13 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
N_("pack for reuse when computing a multi-pack bitmap")),
OPT_BIT(0, "bitmap", &opts.flags, N_("write multi-pack bitmap"),
MIDX_WRITE_BITMAP | MIDX_WRITE_REV_INDEX),
OPT_STRING(0, "base", &opts.incremental_base, N_("checksum"),
N_("base MIDX for incremental writes")),
OPT_BIT(0, "incremental", &opts.flags,
N_("write a new incremental MIDX"), MIDX_WRITE_INCREMENTAL),
OPT_NEGBIT(0, "write-chain-file", &opts.flags,
N_("write the multi-pack-index chain file"),
MIDX_WRITE_NO_CHAIN),
OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
N_("write multi-pack index containing only given indexes")),
OPT_FILENAME(0, "refs-snapshot", &opts.refs_snapshot,
@ -178,6 +186,22 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
if (argc)
usage_with_options(builtin_multi_pack_index_write_usage,
options);

if (opts.flags & MIDX_WRITE_NO_CHAIN &&
!(opts.flags & MIDX_WRITE_INCREMENTAL)) {
error(_("cannot use %s without %s"),
"--no-write-chain-file", "--incremental");
usage_with_options(builtin_multi_pack_index_write_usage,
options);
}

if (opts.incremental_base &&
!(opts.flags & MIDX_WRITE_NO_CHAIN)) {
error(_("cannot use --base without --no-write-chain-file"));
usage_with_options(builtin_multi_pack_index_write_usage,
options);
}

source = handle_object_dir_option(repo);

FREE_AND_NULL(options);
@ -189,7 +213,8 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,

ret = write_midx_file_only(source, &packs,
opts.preferred_pack,
opts.refs_snapshot, opts.flags);
opts.refs_snapshot,
opts.incremental_base, opts.flags);

string_list_clear(&packs, 0);
free(opts.refs_snapshot);
@ -217,10 +242,15 @@ static int cmd_multi_pack_index_compact(int argc, const char **argv,

struct option *options;
static struct option builtin_multi_pack_index_compact_options[] = {
OPT_STRING(0, "base", &opts.incremental_base, N_("checksum"),
N_("base MIDX for incremental writes")),
OPT_BIT(0, "bitmap", &opts.flags, N_("write multi-pack bitmap"),
MIDX_WRITE_BITMAP | MIDX_WRITE_REV_INDEX),
OPT_BIT(0, "incremental", &opts.flags,
N_("write a new incremental MIDX"), MIDX_WRITE_INCREMENTAL),
OPT_NEGBIT(0, "write-chain-file", &opts.flags,
N_("write the multi-pack-index chain file"),
MIDX_WRITE_NO_CHAIN),
OPT_END(),
};

@ -239,6 +269,15 @@ static int cmd_multi_pack_index_compact(int argc, const char **argv,
if (argc != 2)
usage_with_options(builtin_multi_pack_index_compact_usage,
options);

if (opts.flags & MIDX_WRITE_NO_CHAIN &&
!(opts.flags & MIDX_WRITE_INCREMENTAL)) {
error(_("cannot use %s without %s"),
"--no-write-chain-file", "--incremental");
usage_with_options(builtin_multi_pack_index_compact_usage,
options);
}

source = handle_object_dir_option(the_repository);

FREE_AND_NULL(options);
@ -266,7 +305,8 @@ static int cmd_multi_pack_index_compact(int argc, const char **argv,
die(_("MIDX %s must be an ancestor of %s"), argv[0], argv[1]);
}

ret = write_midx_file_compact(source, from_midx, to_midx, opts.flags);
ret = write_midx_file_compact(source, from_midx, to_midx,
opts.incremental_base, opts.flags);

return ret;
}

View File

@ -71,7 +71,7 @@ static void internal_prefix_pathspec(struct strvec *out,

trimmed = xmemdupz(pathspec[i], to_copy);
maybe_basename = (flags & DUP_BASENAME) ? basename(trimmed) : trimmed;
prefixed_path = prefix_path(prefix, prefixlen, maybe_basename);
prefixed_path = prefix_path(the_repository, prefix, prefixlen, maybe_basename);
strvec_push(out, prefixed_path);

free(prefixed_path);
@ -394,7 +394,8 @@ dir_check:
for (j = 0; j < last - first; j++) {
const struct cache_entry *ce = the_repository->index->cache[first + j];
const char *path = ce->name;
char *prefixed_path = prefix_path(dst_with_slash, dst_with_slash_len, path + length + 1);
char *prefixed_path = prefix_path(the_repository, dst_with_slash,
dst_with_slash_len, path + length + 1);

strvec_push(&sources, path);
strvec_push(&destinations, prefixed_path);

View File

@ -17,6 +17,10 @@
#include "commit-graph.h"
#include "wildmatch.h"
#include "mem-pool.h"
#include "pretty.h"
#include "revision.h"
#include "notes.h"
#include "write-or-die.h"

/*
* One day. See the 'name a rev shortly after epoch' test in t6120 when
@ -270,6 +274,43 @@ struct name_ref_data {
struct string_list exclude_filters;
};

struct pretty_format {
struct pretty_print_context ctx;
struct userformat_want want;
};

enum command_type {
NAME_REV = 1,
FORMAT_REV = 2,
};

enum stdin_mode {
TEXT = 1,
REVS = 2,
};

struct command {
enum command_type type;
union {
int name_only;
struct pretty_format *pretty_format;
} u;
};

static void init_name_rev_command(struct command *cmd,
int name_only)
{
cmd->type = NAME_REV;
cmd->u.name_only = name_only;
}

static void init_format_rev_command(struct command *cmd,
struct pretty_format *pretty_format)
{
cmd->type = FORMAT_REV;
cmd->u.pretty_format = pretty_format;
}

static struct tip_table {
struct tip_table_entry {
struct object_id oid;
@ -464,9 +505,9 @@ static const char *get_rev_name(const struct object *o, struct strbuf *buf)
if (!n)
return NULL;

if (!n->generation)
if (!n->generation) {
return n->tip_name;
else {
} else {
strbuf_reset(buf);
strbuf_addstr(buf, n->tip_name);
strbuf_strip_suffix(buf, "^0");
@ -475,6 +516,27 @@ static const char *get_rev_name(const struct object *o, struct strbuf *buf)
}
}

static const char *get_format_rev(const struct commit *c,
struct pretty_format *format_ctx,
struct strbuf *buf)
{
strbuf_reset(buf);

if (format_ctx->want.notes) {
struct strbuf notebuf = STRBUF_INIT;

format_display_notes(&c->object.oid, &notebuf,
get_log_output_encoding(),
format_ctx->ctx.fmt == CMIT_FMT_USERFORMAT);
format_ctx->ctx.notes_message = strbuf_detach(&notebuf, NULL);
}

pretty_print_commit(&format_ctx->ctx, c, buf);
FREE_AND_NULL(format_ctx->ctx.notes_message);

return buf->buf;
}

static void show_name(const struct object *obj,
const char *caller_name,
int always, int allow_undefined, int name_only)
@ -505,7 +567,7 @@ static char const * const name_rev_usage[] = {
NULL
};

static void name_rev_line(char *p, struct name_ref_data *data)
static void name_rev_line(char *p, struct command *cmd)
{
struct strbuf buf = STRBUF_INIT;
int counter = 0;
@ -514,33 +576,52 @@ static void name_rev_line(char *p, struct name_ref_data *data)

for (p_start = p; *p; p++) {
#define ishex(x) (isdigit((x)) || ((x) >= 'a' && (x) <= 'f'))
if (!ishex(*p))
if (!ishex(*p)) {
counter = 0;
else if (++counter == hexsz &&
!ishex(*(p+1))) {
} else if (++counter == hexsz &&
!ishex(*(p + 1))) {
struct object_id oid;
const char *name = NULL;
char c = *(p+1);
char c = *(p + 1);
int p_len = p - p_start + 1;
struct object *o = NULL;
int oid_ret = 1;

counter = 0;

*(p+1) = 0;
if (!repo_get_oid(the_repository, p - (hexsz - 1), &oid)) {
struct object *o =
lookup_object(the_repository, &oid);
*(p + 1) = 0;
oid_ret = repo_get_oid(the_repository, p - (hexsz - 1), &oid);
*(p + 1) = c;

switch (cmd->type) {
case NAME_REV:
if (!oid_ret)
o = lookup_object(the_repository, &oid);
if (o)
name = get_rev_name(o, &buf);
if (!name)
continue;
if (cmd->u.name_only)
printf("%.*s%s", p_len - hexsz, p_start, name);
else
printf("%.*s (%s)", p_len, p_start, name);
break;
case FORMAT_REV:
if (!oid_ret)
o = parse_object(the_repository, &oid);
if (o && o->type == OBJ_COMMIT)
name = get_format_rev((const struct commit *)o,
cmd->u.pretty_format,
&buf);
if (name)
printf("%.*s%s", p_len - hexsz, p_start, name);
else
printf("%.*s", p_len, p_start);
break;
default:
BUG("uncovered case: %d", cmd->type);
}
*(p+1) = c;

if (!name)
continue;

if (data->name_only)
printf("%.*s%s", p_len - hexsz, p_start, name);
else
printf("%.*s (%s)", p_len, p_start, name);
p_start = p + 1;
}
}
@ -565,13 +646,14 @@ int cmd_name_rev(int argc,
#endif
int all = 0, annotate_stdin = 0, allow_undefined = 1, always = 0, peel_tag = 0;
struct name_ref_data data = { 0, 0, STRING_LIST_INIT_NODUP, STRING_LIST_INIT_NODUP };
struct command cmd;
struct option opts[] = {
OPT_BOOL(0, "name-only", &data.name_only, N_("print only ref-based names (no object names)")),
OPT_BOOL(0, "tags", &data.tags_only, N_("only use tags to name the commits")),
OPT_STRING_LIST(0, "refs", &data.ref_filters, N_("pattern"),
N_("only use refs matching <pattern>")),
N_("only use refs matching <pattern>")),
OPT_STRING_LIST(0, "exclude", &data.exclude_filters, N_("pattern"),
N_("ignore refs matching <pattern>")),
N_("ignore refs matching <pattern>")),
OPT_GROUP(""),
OPT_BOOL(0, "all", &all, N_("list all commits reachable from all refs")),
#ifndef WITH_BREAKING_CHANGES
@ -583,10 +665,10 @@ int cmd_name_rev(int argc,
#endif /* WITH_BREAKING_CHANGES */
OPT_BOOL(0, "annotate-stdin", &annotate_stdin, N_("annotate text from stdin")),
OPT_BOOL(0, "undefined", &allow_undefined, N_("allow to print `undefined` names (default)")),
OPT_BOOL(0, "always", &always,
N_("show abbreviated commit object as fallback")),
OPT_BOOL(0, "always", &always,
N_("show abbreviated commit object as fallback")),
OPT_HIDDEN_BOOL(0, "peel-tag", &peel_tag,
N_("dereference tags in the input (internal use)")),
N_("dereference tags in the input (internal use)")),
OPT_END(),
};

@ -594,6 +676,7 @@ int cmd_name_rev(int argc,
init_commit_rev_name(&rev_names);
repo_config(the_repository, git_default_config, NULL);
argc = parse_options(argc, argv, prefix, opts, name_rev_usage, 0);
init_name_rev_command(&cmd, data.name_only);

#ifndef WITH_BREAKING_CHANGES
if (transform_stdin) {
@ -661,7 +744,7 @@ int cmd_name_rev(int argc,

while (strbuf_getline(&sb, stdin) != EOF) {
strbuf_addch(&sb, '\n');
name_rev_line(sb.buf, &data);
name_rev_line(sb.buf, &cmd);
}
strbuf_release(&sb);
} else if (all) {
@ -688,3 +771,170 @@ int cmd_name_rev(int argc,
object_array_clear(&revs);
return 0;
}

struct format_nul_data {
bool nul_input;
bool nul_output;
};

static int format_nul_cb(const struct option *option,
const char *arg,
int unset)
{
struct format_nul_data *data = option->value;
data->nul_input = 1;
data->nul_output = 1;
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
return 0;
}

static enum stdin_mode parse_stdin_mode(const char *stdin_mode)
{
if (!strcmp(stdin_mode, "text"))
return TEXT;
else if (!strcmp(stdin_mode, "revs") ||
!strcmp(stdin_mode, "rev"))
return REVS;
else
die(_("'%s' needs to be either text, revs, or rev"),
"--stdin-mode");
}

static char const *const format_rev_usage[] = {
N_("(EXPERIMENTAL!) git format-rev --stdin-mode=<mode> "
"--format=<pretty> [--[no-]notes=<ref>] "
"[-z] [--[no-]null-output] [--[no-]null-input]"),
NULL
};

int cmd_format_rev(int argc,
const char **argv,
const char *prefix,
struct repository *repo UNUSED)
{
const char *format = NULL;
enum stdin_mode stdin_mode;
const char *stdin_mode_arg = NULL;
struct format_nul_data nul_data = { 0, 0 };
char output_terminator;
strbuf_getline_fn getline_fn;
struct display_notes_opt format_notes_opt;
struct rev_info format_rev = REV_INFO_INIT;
struct pretty_format format_pp = { 0 };
struct string_list notes = STRING_LIST_INIT_NODUP;
struct strbuf scratch_buf = STRBUF_INIT;
struct command cmd;
struct option opts[] = {
OPT_STRING(0, "format", &format, N_("format"),
N_("pretty format to use")),
OPT_STRING(0, "stdin-mode", &stdin_mode_arg, N_("stdin-mode"),
N_("how revs are processed")),
OPT_STRING_LIST(0, "notes", &notes, N_("notes"),
N_("display notes for pretty format")),
OPT_CALLBACK_F('z', "null", &nul_data, N_("z"),
N_("Use NUL for input and output termination"),
PARSE_OPT_NOARG | PARSE_OPT_NONEG, format_nul_cb),
OPT_BOOL(0, "null-input", &nul_data.nul_input,
N_("Use NUL for input termination")),
OPT_BOOL(0, "null-output", &nul_data.nul_output,
N_("Use NUL for output termination")),
OPT_END(),
};

argc = parse_options(argc, argv, prefix, opts, format_rev_usage, 0);

if (argc > 0) {
error(_("too many arguments"));
usage_with_options(format_rev_usage, opts);
}

if (!format)
die(_("'%s' is required"), "--format");
if (!stdin_mode_arg)
die(_("'%s' is required"), "--stdin-mode");

getline_fn = nul_data.nul_input ? strbuf_getline_nul : strbuf_getline_lf;
output_terminator = nul_data.nul_output ? '\0' : '\n';

init_display_notes(&format_notes_opt);
stdin_mode = parse_stdin_mode(stdin_mode_arg);

get_commit_format(format, &format_rev);
format_pp.ctx.rev = &format_rev;
format_pp.ctx.fmt = format_rev.commit_format;
format_pp.ctx.abbrev = format_rev.abbrev;
format_pp.ctx.date_mode_explicit = format_rev.date_mode_explicit;
format_pp.ctx.date_mode = format_rev.date_mode;
format_pp.ctx.color = GIT_COLOR_AUTO;

userformat_find_requirements(format,
&format_pp.want);
if (format_pp.want.notes) {
int ignore_show_notes = 0;
struct string_list_item *n;

for_each_string_list_item(n, &notes)
enable_ref_display_notes(&format_notes_opt,
&ignore_show_notes,
n->string);
load_display_notes(&format_notes_opt);
}

init_format_rev_command(&cmd, &format_pp);

switch (stdin_mode) {
case TEXT:
while (getline_fn(&scratch_buf, stdin) != EOF) {
name_rev_line(scratch_buf.buf, &cmd);
/*
* We do not pass on the terminator to name_rev_line,
* unlike name-rev.
*/
printf("%c", output_terminator);
maybe_flush_or_die(stdout, "stdout");
}
break;
case REVS:
while (getline_fn(&scratch_buf, stdin) != EOF) {
struct object_id oid;
struct object *object;
struct object *peeled;

if (repo_get_oid(the_repository, scratch_buf.buf, &oid)) {
fprintf(stderr, "Could not get object name for %s. Skipping.\n",
scratch_buf.buf);
continue;
}

object = parse_object(the_repository, &oid);
if (!object) {
fprintf(stderr, "Could not get object for %s. Skipping.\n",
scratch_buf.buf);
continue;
}

peeled = deref_tag(the_repository, object, scratch_buf.buf, 0);
if (!peeled || peeled->type != OBJ_COMMIT) {
fprintf(stderr,
"Could not get commit for %s. Skipping.\n",
scratch_buf.buf);
continue;
}

get_format_rev((struct commit *)peeled,
&format_pp, &scratch_buf);
printf("%s%c", scratch_buf.buf, output_terminator);
maybe_flush_or_die(stdout, "stdout");
strbuf_release(&scratch_buf);
}
break;
default:
BUG("uncovered case: %d", stdin_mode);
}

strbuf_release(&scratch_buf);
string_list_clear(&notes, 0);
release_display_notes(&format_notes_opt);
return 0;
}

View File

@ -629,14 +629,21 @@ static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
struct packed_git *p = IN_PACK(entry);
struct pack_window *w_curs = NULL;
uint32_t pos;
off_t offset;
off_t offset, cur;
enum object_type type = oe_type(entry);
enum object_type in_pack_type;
off_t datalen;
unsigned char header[MAX_PACK_OBJECT_HEADER],
dheader[MAX_PACK_OBJECT_HEADER];
unsigned hdrlen;
const unsigned hashsz = the_hash_algo->rawsz;
unsigned long entry_size = SIZE(entry);
size_t entry_size;

cur = entry->in_pack_offset;
in_pack_type = unpack_object_header(p, &w_curs, &cur, &entry_size);
if (in_pack_type < 0)
die(_("write_reuse_object: unable to parse object header of %s"),
oid_to_hex(&entry->idx.oid));

if (DELTA(entry))
type = (allow_ofs_delta && DELTA(entry)->idx.offset) ?
@ -664,7 +671,8 @@ static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
datalen -= entry->in_pack_header_size;

if (!pack_to_stdout && p->index_version == 1 &&
check_pack_inflate(p, &w_curs, offset, datalen, entry_size)) {
check_pack_inflate(p, &w_curs, offset, datalen,
cast_size_t_to_ulong(entry_size))) {
error(_("corrupt packed object for %s"),
oid_to_hex(&entry->idx.oid));
unuse_pack(&w_curs);
@ -1087,7 +1095,7 @@ static void write_reused_pack_one(struct packed_git *reuse_packfile,
{
off_t offset, next, cur;
enum object_type type;
unsigned long size;
size_t size;

offset = pack_pos_to_offset(reuse_packfile, pos);
next = pack_pos_to_offset(reuse_packfile, pos + 1);
@ -2243,7 +2251,7 @@ static void check_object(struct object_entry *entry, uint32_t object_index)
off_t ofs;
unsigned char *buf, c;
enum object_type type;
unsigned long in_pack_size;
size_t in_pack_size;

buf = use_pack(p, &w_curs, entry->in_pack_offset, &avail);

@ -2270,7 +2278,7 @@ static void check_object(struct object_entry *entry, uint32_t object_index)
default:
/* Not a delta hence we've already got all we need. */
oe_set_type(entry, entry->in_pack_type);
SET_SIZE(entry, in_pack_size);
SET_SIZE(entry, cast_size_t_to_ulong(in_pack_size));
entry->in_pack_header_size = used;
if (oe_type(entry) < OBJ_COMMIT || oe_type(entry) > OBJ_BLOB)
goto give_up;
@ -2324,8 +2332,8 @@ static void check_object(struct object_entry *entry, uint32_t object_index)
if (have_base &&
can_reuse_delta(&base_ref, entry, &base_entry)) {
oe_set_type(entry, entry->in_pack_type);
SET_SIZE(entry, in_pack_size); /* delta size */
SET_DELTA_SIZE(entry, in_pack_size);
SET_SIZE(entry, cast_size_t_to_ulong(in_pack_size)); /* delta size */
SET_DELTA_SIZE(entry, cast_size_t_to_ulong(in_pack_size));

if (base_entry) {
SET_DELTA(entry, base_entry);
@ -2734,16 +2742,18 @@ unsigned long oe_get_size_slow(struct packing_data *pack,
struct pack_window *w_curs;
unsigned char *buf;
enum object_type type;
unsigned long used, avail, size;
unsigned long used, avail;
size_t size;

if (e->type_ != OBJ_OFS_DELTA && e->type_ != OBJ_REF_DELTA) {
unsigned long sz;
packing_data_lock(&to_pack);
if (odb_read_object_info(the_repository->objects,
&e->idx.oid, &size) < 0)
&e->idx.oid, &sz) < 0)
die(_("unable to get size of %s"),
oid_to_hex(&e->idx.oid));
packing_data_unlock(&to_pack);
return size;
return sz;
}

p = oe_in_pack(pack, e);
@ -2760,7 +2770,7 @@ unsigned long oe_get_size_slow(struct packing_data *pack,

unuse_pack(&w_curs);
packing_data_unlock(&to_pack);
return size;
return cast_size_t_to_ulong(size);
}

static int try_delta(struct unpacked *trg, struct unpacked *src,
@ -4265,6 +4275,7 @@ static void enumerate_and_traverse_cruft_objects(struct string_list *fresh_packs
traverse_commit_list(&revs, show_cruft_commit, show_cruft_object, NULL);

stop_progress(&progress_state);
release_revisions(&revs);
}

static void read_cruft_objects(void)

View File

@ -996,9 +996,13 @@ int cmd_pull(int argc,
OPT_PASSTHRU('6', "ipv6", &opt_ipv6, NULL,
N_("use IPv6 addresses only"),
PARSE_OPT_NOARG),
OPT_PASSTHRU_ARGV(0, "negotiation-tip", &opt_fetch, N_("revision"),
OPT_PASSTHRU_ARGV(0, "negotiation-restrict", &opt_fetch, N_("revision"),
N_("report that we have only objects reachable from this object"),
0),
OPT_ALIAS(0, "negotiation-tip", "negotiation-restrict"),
OPT_PASSTHRU_ARGV(0, "negotiation-include", &opt_fetch, N_("revision"),
N_("ensure this ref is always sent as a negotiation have"),
0),
OPT_BOOL(0, "show-forced-updates", &opt_show_forced_updates,
N_("check for forced-updates on all updated branches")),
OPT_PASSTHRU(0, "set-upstream", &set_upstream, NULL,

View File

@ -229,7 +229,7 @@ int cmd_read_tree(int argc,
opts.preserve_ignored = 0;
/* otherwise, opts.preserve_ignored is irrelevant */
if (opts.merge && !opts.index_only)
setup_work_tree();
setup_work_tree(the_repository);

if (opts.skip_sparse_checkout)
ensure_full_index(the_repository->index);

View File

@ -1456,7 +1456,8 @@ static const char *push_to_checkout(unsigned char *hash,
struct strvec *env,
const char *work_tree)
{
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT_FORCE_SERIAL;

opt.invoked_hook = invoked_hook;

strvec_pushf(env, "GIT_WORK_TREE=%s", absolute_path(work_tree));
@ -1641,8 +1642,8 @@ static const char *update(struct command *cmd, struct shallow_info *si)
ret = NULL; /* good */
}
strbuf_release(&err);
}
else {
} else {
enum ref_transaction_error tx_err;
struct strbuf err = STRBUF_INIT;
if (shallow_update && si->shallow_ref[cmd->index] &&
update_shallow_ref(cmd, si)) {
@ -1650,14 +1651,18 @@ static const char *update(struct command *cmd, struct shallow_info *si)
goto out;
}

if (ref_transaction_update(transaction,
namespaced_name,
new_oid, old_oid,
NULL, NULL,
0, "push",
&err)) {
tx_err = ref_transaction_update(transaction,
namespaced_name,
new_oid, old_oid,
NULL, NULL,
0, "push",
&err);
if (tx_err) {
rp_error("%s", err.buf);
ret = "failed to update ref";
if (tx_err == REF_TRANSACTION_ERROR_GENERIC)
ret = "failed to update ref";
else
ret = ref_transaction_error_msg(tx_err);
} else {
ret = NULL; /* good */
}
@ -2642,7 +2647,7 @@ int cmd_receive_pack(int argc,

setup_path();

if (!enter_repo(service_dir, 0))
if (!enter_repo(the_repository, service_dir, 0))
die("'%s' does not appear to be a git repository", service_dir);

repo_config(the_repository, receive_pack_config, NULL);

View File

@ -33,7 +33,7 @@ static int midx_must_contain_cruft = 1;
static const char *const git_repack_usage[] = {
N_("git repack [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m]\n"
"[--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>]\n"
"[--write-midx] [--name-hash-version=<n>] [--path-walk]"),
"[--write-midx[=<mode>]] [--name-hash-version=<n>] [--path-walk]"),
NULL
};

@ -42,9 +42,14 @@ static const char incremental_bitmap_conflict_error[] = N_(
"--no-write-bitmap-index or disable the pack.writeBitmaps configuration."
);

#define DEFAULT_MIDX_SPLIT_FACTOR 2
#define DEFAULT_MIDX_NEW_LAYER_THRESHOLD 8

struct repack_config_ctx {
struct pack_objects_args *po_args;
struct pack_objects_args *cruft_po_args;
int midx_split_factor;
int midx_new_layer_threshold;
};

static int repack_config(const char *var, const char *value,
@ -94,9 +99,39 @@ static int repack_config(const char *var, const char *value,
midx_must_contain_cruft = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "repack.midxsplitfactor")) {
repack_ctx->midx_split_factor = git_config_int(var, value,
ctx->kvi);
return 0;
}
if (!strcmp(var, "repack.midxnewlayerthreshold")) {
repack_ctx->midx_new_layer_threshold = git_config_int(var, value,
ctx->kvi);
return 0;
}
return git_default_config(var, value, ctx, cb);
}

static int option_parse_write_midx(const struct option *opt, const char *arg,
int unset)
{
enum repack_write_midx_mode *cfg = opt->value;

if (unset) {
*cfg = REPACK_WRITE_MIDX_NONE;
return 0;
}

if (!arg || !*arg)
*cfg = REPACK_WRITE_MIDX_DEFAULT;
else if (!strcmp(arg, "incremental"))
*cfg = REPACK_WRITE_MIDX_INCREMENTAL;
else
return error(_("unknown value for %s: %s"), opt->long_name, arg);

return 0;
}

int cmd_repack(int argc,
const char **argv,
const char *prefix,
@ -119,7 +154,7 @@ int cmd_repack(int argc,
struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
struct pack_objects_args po_args = PACK_OBJECTS_ARGS_INIT;
struct pack_objects_args cruft_po_args = PACK_OBJECTS_ARGS_INIT;
int write_midx = 0;
enum repack_write_midx_mode write_midx = REPACK_WRITE_MIDX_NONE;
const char *cruft_expiration = NULL;
const char *expire_to = NULL;
const char *filter_to = NULL;
@ -185,8 +220,14 @@ int cmd_repack(int argc,
N_("do not repack this pack")),
OPT_INTEGER('g', "geometric", &geometry.split_factor,
N_("find a geometric progression with factor <N>")),
OPT_BOOL('m', "write-midx", &write_midx,
N_("write a multi-pack index of the resulting packs")),
OPT_CALLBACK_F(0, "write-midx", &write_midx,
N_("mode"),
N_("write a multi-pack index of the resulting packs"),
PARSE_OPT_OPTARG, option_parse_write_midx),
OPT_SET_INT_F('m', NULL, &write_midx,
N_("write a multi-pack index of the resulting packs"),
REPACK_WRITE_MIDX_DEFAULT,
PARSE_OPT_HIDDEN),
OPT_STRING(0, "expire-to", &expire_to, N_("dir"),
N_("pack prefix to store a pack containing pruned objects")),
OPT_STRING(0, "filter-to", &filter_to, N_("dir"),
@ -199,6 +240,8 @@ int cmd_repack(int argc,
memset(&config_ctx, 0, sizeof(config_ctx));
config_ctx.po_args = &po_args;
config_ctx.cruft_po_args = &cruft_po_args;
config_ctx.midx_split_factor = DEFAULT_MIDX_SPLIT_FACTOR;
config_ctx.midx_new_layer_threshold = DEFAULT_MIDX_NEW_LAYER_THRESHOLD;

repo_config(repo, repack_config, &config_ctx);

@ -221,14 +264,16 @@ int cmd_repack(int argc,
pack_everything |= ALL_INTO_ONE;

if (write_bitmaps < 0) {
if (!write_midx &&
if (write_midx == REPACK_WRITE_MIDX_NONE &&
(!(pack_everything & ALL_INTO_ONE) || !is_bare_repository()))
write_bitmaps = 0;
}
if (po_args.pack_kept_objects < 0)
po_args.pack_kept_objects = write_bitmaps > 0 && !write_midx;
po_args.pack_kept_objects = write_bitmaps > 0 &&
write_midx == REPACK_WRITE_MIDX_NONE;

if (write_bitmaps && !(pack_everything & ALL_INTO_ONE) && !write_midx)
if (write_bitmaps && !(pack_everything & ALL_INTO_ONE) &&
write_midx == REPACK_WRITE_MIDX_NONE)
die(_(incremental_bitmap_conflict_error));

if (write_bitmaps && po_args.local &&
@ -244,7 +289,14 @@ int cmd_repack(int argc,
write_bitmaps = 0;
}

if (write_midx && write_bitmaps) {
if (config_ctx.midx_split_factor < 2)
die(_("invalid value for %s: %d"), "--midx-split-factor",
config_ctx.midx_split_factor);
if (config_ctx.midx_new_layer_threshold < 1)
die(_("invalid value for %s: %d"), "--midx-new-layer-threshold",
config_ctx.midx_new_layer_threshold);

if (write_midx != REPACK_WRITE_MIDX_NONE && write_bitmaps) {
struct strbuf path = STRBUF_INIT;

strbuf_addf(&path, "%s/%s_XXXXXX",
@ -267,6 +319,10 @@ int cmd_repack(int argc,
if (geometry.split_factor) {
if (pack_everything)
die(_("options '%s' and '%s' cannot be used together"), "--geometric", "-A/-a");
if (write_midx == REPACK_WRITE_MIDX_INCREMENTAL) {
geometry.midx_layer_threshold = config_ctx.midx_new_layer_threshold;
geometry.midx_layer_threshold_set = true;
}
pack_geometry_init(&geometry, &existing, &po_args);
pack_geometry_split(&geometry);
}
@ -297,7 +353,7 @@ int cmd_repack(int argc,
}
if (repo_has_promisor_remote(repo))
strvec_push(&cmd.args, "--exclude-promisor-objects");
if (!write_midx) {
if (write_midx == REPACK_WRITE_MIDX_NONE) {
if (write_bitmaps > 0)
strvec_push(&cmd.args, "--write-bitmap-index");
else if (write_bitmaps < 0)
@ -417,7 +473,7 @@ int cmd_repack(int argc,
* midx_has_unknown_packs() will make the decision for
* us.
*/
if (!get_multi_pack_index(repo->objects->sources))
if (!get_multi_pack_index(existing.source))
midx_must_contain_cruft = 1;
}

@ -516,10 +572,13 @@ int cmd_repack(int argc,
packtmp);
/* End of pack replacement. */

if (delete_redundant && pack_everything & ALL_INTO_ONE)
if (delete_redundant && pack_everything & ALL_INTO_ONE) {
if (write_midx == REPACK_WRITE_MIDX_INCREMENTAL)
existing_packs_retain_midx_packs(&existing);
existing_packs_mark_for_deletion(&existing, &names);
}

if (write_midx) {
if (write_midx != REPACK_WRITE_MIDX_NONE) {
struct repack_write_midx_opts opts = {
.existing = &existing,
.geometry = &geometry,
@ -528,11 +587,13 @@ int cmd_repack(int argc,
.packdir = packdir,
.show_progress = show_progress,
.write_bitmaps = write_bitmaps > 0,
.midx_must_contain_cruft = midx_must_contain_cruft
.midx_must_contain_cruft = midx_must_contain_cruft,
.midx_split_factor = config_ctx.midx_split_factor,
.midx_new_layer_threshold = config_ctx.midx_new_layer_threshold,
.mode = write_midx,
};

ret = write_midx_included_packs(&opts);

ret = repack_write_midx(&opts);
if (ret)
goto cleanup;
}
@ -541,11 +602,15 @@ int cmd_repack(int argc,

if (delete_redundant) {
int opts = 0;
existing_packs_remove_redundant(&existing, packdir);
bool wrote_incremental_midx = write_midx == REPACK_WRITE_MIDX_INCREMENTAL;

existing_packs_remove_redundant(&existing, packdir,
wrote_incremental_midx);

if (geometry.split_factor)
pack_geometry_remove_redundant(&geometry, &names,
&existing, packdir);
&existing, packdir,
wrote_incremental_midx);
if (show_progress)
opts |= PRUNE_PACKED_VERBOSE;
prune_packed_objects(opts);
@ -564,8 +629,7 @@ int cmd_repack(int argc,
unsigned flags = 0;
if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL, 0))
flags |= MIDX_WRITE_INCREMENTAL;
write_midx_file(repo->objects->sources,
NULL, NULL, flags);
write_midx_file(existing.source, NULL, NULL, flags);
}

cleanup:

View File

@ -281,11 +281,11 @@ static void parse_args(struct pathspec *pathspec,
* Ok, argv[0] looks like a commit/tree; it should not
* be a filename.
*/
verify_non_filename(prefix, argv[0]);
verify_non_filename(the_repository, prefix, argv[0]);
rev = *argv++;
} else {
/* Otherwise we treat this as a filename */
verify_filename(prefix, argv[0], 1);
verify_filename(the_repository, prefix, argv[0], 1);
}
}

@ -468,7 +468,7 @@ int cmd_reset(int argc,
trace2_cmd_mode(reset_type_names[reset_type]);

if (reset_type != SOFT && (reset_type != MIXED || repo_get_work_tree(the_repository)))
setup_work_tree();
setup_work_tree(the_repository);

if (reset_type == MIXED && is_bare_repository())
die(_("%s reset is not allowed in a bare repository"),

View File

@ -739,7 +739,7 @@ int cmd_rev_parse(int argc,

/* No options; just report on whether we're in a git repo or not. */
if (argc == 1) {
setup_git_directory();
setup_git_directory(the_repository);
repo_config(the_repository, git_default_config, NULL);
return 0;
}
@ -749,7 +749,7 @@ int cmd_rev_parse(int argc,

if (as_is) {
if (show_file(arg, output_prefix) && as_is < 2)
verify_filename(prefix, arg, 0);
verify_filename(the_repository, prefix, arg, 0);
continue;
}

@ -774,7 +774,7 @@ int cmd_rev_parse(int argc,

/* The rest of the options require a git repository. */
if (!did_repo_setup) {
prefix = setup_git_directory();
prefix = setup_git_directory(the_repository);
repo_config(the_repository, git_default_config, NULL);
did_repo_setup = 1;

@ -1006,7 +1006,7 @@ int cmd_rev_parse(int argc,
}
if (!strcmp(arg, "--show-cdup")) {
const char *pfx = prefix;
if (!is_inside_work_tree()) {
if (!is_inside_work_tree(the_repository)) {
const char *work_tree =
repo_get_work_tree(the_repository);
if (work_tree)
@ -1063,12 +1063,12 @@ int cmd_rev_parse(int argc,
continue;
}
if (!strcmp(arg, "--is-inside-git-dir")) {
printf("%s\n", is_inside_git_dir() ? "true"
printf("%s\n", is_inside_git_dir(the_repository) ? "true"
: "false");
continue;
}
if (!strcmp(arg, "--is-inside-work-tree")) {
printf("%s\n", is_inside_work_tree() ? "true"
printf("%s\n", is_inside_work_tree(the_repository) ? "true"
: "false");
continue;
}
@ -1173,7 +1173,7 @@ int cmd_rev_parse(int argc,
as_is = 1;
if (!show_file(arg, output_prefix))
continue;
verify_filename(prefix, arg, 1);
verify_filename(the_repository, prefix, arg, 1);
}
strbuf_release(&buf);
if (verify) {

View File

@ -296,7 +296,7 @@ int cmd_rm(int argc,
die(_("No pathspec was given. Which files should I remove?"));

if (!index_only)
setup_work_tree();
setup_work_tree(the_repository);

prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;

View File

@ -63,7 +63,7 @@ static int sparse_checkout_list(int argc, const char **argv, const char *prefix,
int res;
struct repo_config_values *cfg = repo_config_values(the_repository);

setup_work_tree();
setup_work_tree(the_repository);
if (!cfg->apply_sparse_checkout)
die(_("this worktree is not sparse"));

@ -229,7 +229,7 @@ static int update_working_directory(struct repository *r,
o.dst_index = r->index;
o.skip_sparse_checkout = 0;

setup_work_tree();
setup_work_tree(the_repository);

repo_hold_locked_index(r, &lock_file, LOCK_DIE_ON_ERROR);

@ -468,7 +468,7 @@ static int sparse_checkout_init(int argc, const char **argv, const char *prefix,
OPT_END(),
};

setup_work_tree();
setup_work_tree(the_repository);
repo_read_index(repo);

init_opts.cone_mode = -1;
@ -735,7 +735,8 @@ static void sanitize_paths(struct repository *repo,
int prefix_len = strlen(prefix);

for (i = 0; i < args->nr; i++) {
char *prefixed_path = prefix_path(prefix, prefix_len, args->v[i]);
char *prefixed_path = prefix_path(the_repository, prefix,
prefix_len, args->v[i]);
strvec_replace(args, i, prefixed_path);
free(prefixed_path);
}
@ -801,7 +802,7 @@ static int sparse_checkout_add(int argc, const char **argv, const char *prefix,
int ret;
struct repo_config_values *cfg = repo_config_values(the_repository);

setup_work_tree();
setup_work_tree(the_repository);
if (!cfg->apply_sparse_checkout)
die(_("no sparse-checkout to add to"));

@ -855,7 +856,7 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix,
struct strvec patterns = STRVEC_INIT;
int ret;

setup_work_tree();
setup_work_tree(the_repository);
repo_read_index(repo);

set_opts.cone_mode = -1;
@ -911,7 +912,7 @@ static int sparse_checkout_reapply(int argc, const char **argv,
};
struct repo_config_values *cfg = repo_config_values(the_repository);

setup_work_tree();
setup_work_tree(the_repository);
if (!cfg->apply_sparse_checkout)
die(_("must be in a sparse-checkout to reapply sparsity patterns"));

@ -974,7 +975,7 @@ static int sparse_checkout_clean(int argc, const char **argv,
OPT_END(),
};

setup_work_tree();
setup_work_tree(the_repository);
if (!cfg->apply_sparse_checkout)
die(_("must be in a sparse-checkout to clean directories"));
if (!core_sparse_checkout_cone)
@ -1052,7 +1053,7 @@ static int sparse_checkout_disable(int argc, const char **argv,
* forcibly return to a dense checkout regardless of initial state.
*/

setup_work_tree();
setup_work_tree(the_repository);
argc = parse_options(argc, argv, prefix,
builtin_sparse_checkout_disable_options,
builtin_sparse_checkout_disable_usage, 0);

View File

@ -44,7 +44,7 @@
#define BUILTIN_STASH_POP_USAGE \
N_("git stash pop [--index] [-q | --quiet] [<stash>]")
#define BUILTIN_STASH_APPLY_USAGE \
N_("git stash apply [--index] [-q | --quiet] [<stash>]")
N_("git stash apply [--index] [-q | --quiet] [--label-ours=<label>] [--label-theirs=<label>] [--label-base=<label>] [<stash>]")
#define BUILTIN_STASH_BRANCH_USAGE \
N_("git stash branch <branchname> [<stash>]")
#define BUILTIN_STASH_STORE_USAGE \
@ -591,7 +591,9 @@ static void unstage_changes_unless_new(struct object_id *orig_tree)
}

static int do_apply_stash(const char *prefix, struct stash_info *info,
int index, int quiet)
int index, int quiet,
const char *label_ours, const char *label_theirs,
const char *label_base)
{
int clean, ret;
int has_index = index;
@ -643,9 +645,9 @@ static int do_apply_stash(const char *prefix, struct stash_info *info,

init_ui_merge_options(&o, the_repository);

o.branch1 = "Updated upstream";
o.branch2 = "Stashed changes";
o.ancestor = "Stash base";
o.branch1 = label_ours ? label_ours : "Updated upstream";
o.branch2 = label_theirs ? label_theirs : "Stashed changes";
o.ancestor = label_base ? label_base : "Stash base";

if (oideq(&info->b_tree, &c_tree))
o.branch1 = "Version stash was based on";
@ -723,11 +725,18 @@ static int apply_stash(int argc, const char **argv, const char *prefix,
int ret = -1;
int quiet = 0;
int index = use_index;
const char *label_ours = NULL, *label_theirs = NULL, *label_base = NULL;
struct stash_info info = STASH_INFO_INIT;
struct option options[] = {
OPT__QUIET(&quiet, N_("be quiet, only report errors")),
OPT_BOOL(0, "index", &index,
N_("attempt to recreate the index")),
OPT_STRING(0, "label-ours", &label_ours, N_("label"),
N_("label for the upstream side in conflict markers")),
OPT_STRING(0, "label-theirs", &label_theirs, N_("label"),
N_("label for the stashed side in conflict markers")),
OPT_STRING(0, "label-base", &label_base, N_("label"),
N_("label for the base in diff3 conflict markers")),
OPT_END()
};

@ -737,7 +746,8 @@ static int apply_stash(int argc, const char **argv, const char *prefix,
if (get_stash_info(&info, argc, argv))
goto cleanup;

ret = do_apply_stash(prefix, &info, index, quiet);
ret = do_apply_stash(prefix, &info, index, quiet,
label_ours, label_theirs, label_base);
cleanup:
free_stash_info(&info);
return ret;
@ -836,7 +846,8 @@ static int pop_stash(int argc, const char **argv, const char *prefix,
if (get_stash_info_assert(&info, argc, argv))
goto cleanup;

if ((ret = do_apply_stash(prefix, &info, index, quiet)))
if ((ret = do_apply_stash(prefix, &info, index, quiet,
NULL, NULL, NULL)))
printf_ln(_("The stash entry is kept in case "
"you need it again."));
else
@ -877,7 +888,8 @@ static int branch_stash(int argc, const char **argv, const char *prefix,
strvec_push(&cp.args, oid_to_hex(&info.b_commit));
ret = run_command(&cp);
if (!ret)
ret = do_apply_stash(prefix, &info, 1, 0);
ret = do_apply_stash(prefix, &info, 1, 0,
NULL, NULL, NULL);
if (!ret && info.is_stash_ref)
ret = do_drop_stash(&info, 0);


View File

@ -54,7 +54,7 @@ int cmd_stripspace(int argc,
usage_with_options(stripspace_usage, options);

if (mode == STRIP_COMMENTS || mode == COMMENT_LINES) {
setup_git_directory_gently(&nongit);
setup_git_directory_gently(the_repository, &nongit);
repo_config(the_repository, git_default_config, NULL);
}


View File

@ -1250,7 +1250,7 @@ static int compute_summary_module_list(struct object_id *head_oid,

if (!info->cached) {
if (diff_cmd == DIFF_INDEX)
setup_work_tree();
setup_work_tree(the_repository);
if (repo_read_index_preload(the_repository, &rev.diffopt.pathspec, 0) < 0) {
perror("repo_read_index_preload");
ret = -1;

Some files were not shown because too many files have changed in this diff Show More