Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/check-style.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
jobname: ClangFormat
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
fetch-depth: 0

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/check-whitespace.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
check-whitespace:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
fetch-depth: 0

Expand Down
78 changes: 43 additions & 35 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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@v9
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
if: steps.check-ref.outputs.enabled == 'yes'
with:
github-token: ${{secrets.GITHUB_TOKEN}}
Expand Down Expand Up @@ -112,8 +112,10 @@ jobs:
group: windows-build-${{ github.ref }}
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
steps:
- uses: actions/checkout@v6
- uses: git-for-windows/setup-git-for-windows-sdk@v2
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- uses: git-for-windows/setup-git-for-windows-sdk@aed153d1258c311b680b81584a72a1a4807401f0 # v2.2.1
with:
architecture: mingw64
- name: build
shell: bash
env:
Expand All @@ -123,7 +125,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@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: windows-artifacts
path: artifacts
Expand All @@ -140,14 +142,16 @@ jobs:
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
steps:
- name: download tracked files and build artifacts
uses: actions/download-artifact@v8
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # 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@v2
- uses: git-for-windows/setup-git-for-windows-sdk@aed153d1258c311b680b81584a72a1a4807401f0 # v2.2.1
with:
architecture: mingw64
- name: test
shell: bash
run: . /etc/profile && ci/run-test-slice.sh $((${{matrix.nr}} + 1)) 10
Expand All @@ -157,7 +161,7 @@ jobs:
run: ci/print-test-failures.sh
- name: Upload failed tests' directories
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: failed-tests-windows-${{ matrix.nr }}
path: ${{env.FAILED_TEST_ARTIFACTS}}
Expand All @@ -173,20 +177,22 @@ jobs:
group: vs-build-${{ github.ref }}
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
steps:
- uses: actions/checkout@v6
- uses: git-for-windows/setup-git-for-windows-sdk@v2
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- uses: git-for-windows/setup-git-for-windows-sdk@aed153d1258c311b680b81584a72a1a4807401f0 # v2.2.1
with:
architecture: mingw64
- name: initialize vcpkg
uses: actions/checkout@v6
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
with:
repository: 'microsoft/vcpkg'
path: 'compat/vcbuild/vcpkg'
- name: download vcpkg artifacts
uses: git-for-windows/get-azure-pipelines-artifact@v0
uses: git-for-windows/get-azure-pipelines-artifact@2e424b98e1251b725d6064c5f1a9f854a33e5b88 # v0
with:
repository: git/git
definitionId: 9
- name: add msbuild to PATH
uses: microsoft/setup-msbuild@v3
uses: microsoft/setup-msbuild@30375c66a4eea26614e0d39710365f22f8b0af57 # v3
- name: copy dlls to root
shell: cmd
run: compat\vcbuild\vcpkg_copy_dlls.bat release
Expand All @@ -208,7 +214,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@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: vs-artifacts
path: artifacts
Expand All @@ -224,9 +230,11 @@ 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@v2
- uses: git-for-windows/setup-git-for-windows-sdk@aed153d1258c311b680b81584a72a1a4807401f0 # v2.2.1
with:
architecture: mingw64
- name: download tracked files and build artifacts
uses: actions/download-artifact@v8
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: vs-artifacts
path: ${{github.workspace}}
Expand All @@ -244,7 +252,7 @@ jobs:
run: ci/print-test-failures.sh
- name: Upload failed tests' directories
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: failed-tests-windows-vs-${{ matrix.nr }}
path: ${{env.FAILED_TEST_ARTIFACTS}}
Expand All @@ -258,8 +266,8 @@ jobs:
group: windows-meson-build-${{ github.ref }}
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
- name: Set up dependencies
shell: pwsh
run: pip install meson ninja
Expand All @@ -270,7 +278,7 @@ jobs:
shell: pwsh
run: meson compile -C build
- name: Upload build artifacts
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: windows-meson-artifacts
path: build
Expand All @@ -286,13 +294,13 @@ jobs:
group: windows-meson-test-${{ matrix.nr }}-${{ github.ref }}
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
- name: Set up dependencies
shell: pwsh
run: pip install meson ninja
- name: Download build artifacts
uses: actions/download-artifact@v8
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
name: windows-meson-artifacts
path: build
Expand All @@ -305,7 +313,7 @@ jobs:
run: ci/print-test-failures.sh
- name: Upload failed tests' directories
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: failed-tests-windows-meson-${{ matrix.nr }}
path: ${{env.FAILED_TEST_ARTIFACTS}}
Expand Down Expand Up @@ -341,15 +349,15 @@ jobs:
TEST_OUTPUT_DIRECTORY: ${{github.workspace}}/t
runs-on: ${{matrix.vector.pool}}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- run: ci/install-dependencies.sh
- run: ci/run-build-and-tests.sh
- name: print test failures
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
run: ci/print-test-failures.sh
- name: Upload failed tests' directories
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
uses: actions/upload-artifact@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: failed-tests-${{matrix.vector.jobname}}
path: ${{env.FAILED_TEST_ARTIFACTS}}
Expand All @@ -362,7 +370,7 @@ jobs:
CI_JOB_IMAGE: ubuntu-latest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- run: ci/install-dependencies.sh
- run: ci/run-build-and-minimal-fuzzers.sh
dockerized:
Expand Down Expand Up @@ -411,9 +419,9 @@ jobs:
# A RHEL 8 compatible distro. Supported until 2029-05-31.
- jobname: almalinux-8
image: almalinux:8
# Supported until 2026-08-31.
- jobname: debian-11
image: debian:11
# Supported until 2028-06-30.
- jobname: debian-12
image: debian:12
env:
jobname: ${{matrix.vector.jobname}}
CC: ${{matrix.vector.cc}}
Expand Down Expand Up @@ -441,7 +449,7 @@ jobs:
else
apt-get -q update && apt-get -q -y install git
fi
- uses: actions/checkout@v6
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- run: ci/install-dependencies.sh
- run: useradd builder --create-home
- run: chown -R builder .
Expand All @@ -451,7 +459,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@v7
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: failed-tests-${{matrix.vector.jobname}}
path: ${{env.FAILED_TEST_ARTIFACTS}}
Expand All @@ -466,7 +474,7 @@ jobs:
group: static-analysis-${{ github.ref }}
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- run: ci/install-dependencies.sh
- run: ci/run-static-analysis.sh
- run: ci/check-directional-formatting.bash
Expand All @@ -482,7 +490,7 @@ jobs:
group: rust-analysis-${{ github.ref }}
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- run: ci/install-dependencies.sh
- run: ci/run-rust-checks.sh
sparse:
Expand All @@ -496,7 +504,7 @@ jobs:
group: sparse-${{ github.ref }}
cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- name: Install other dependencies
run: ci/install-dependencies.sh
- run: make sparse
Expand All @@ -512,6 +520,6 @@ jobs:
CI_JOB_IMAGE: ubuntu-latest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
- run: ci/install-dependencies.sh
- run: ci/test-documentation.sh
23 changes: 22 additions & 1 deletion Documentation/config/push.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,28 @@ This will result in only b (a and c are cleared).
sent by rounds of negotiation in which the client and the
server attempt to find commits in common. If `false`, Git will
rely solely on the server's ref advertisement to find commits
in common.
in common. Defaults to `false`.
+
If set to `required`, abort the push before constructing or sending a
packfile if negotiation fails, including when the server or protocol does
not support negotiation. With `true`, a negotiation failure only produces
a warning and the push proceeds.
+
WebDAV and remote-helper `export` do not support required negotiation.
Remote-helper `push` requires the helper to advertise
`push-negotiate-required`; otherwise Git rejects the push before submitting
it to the helper. Helpers that connect to Git's native protocol use the
normal negotiation implementation. See linkgit:gitremote-helpers[7].
+
A successful negotiation need not find any common commits. `required`
does not limit the size of the resulting packfile or change which commits
the server acknowledges. On a supported transport, negotiation is skipped
when there are no negotiation tips, as with a deletion-only push without
explicitly configured tips. Unsupported transports reject updates, including
deletions, without starting object transfer. To permit a push after a
negotiation failure, explicitly use
`git -c push.negotiate=true push`; to skip negotiation, use
`git -c push.negotiate=false push`.

`push.useBitmaps`::
If set to `false`, disable use of bitmaps for `git push` even if
Expand Down
5 changes: 5 additions & 0 deletions Documentation/git-version.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ detection algorithm and thus may be vulnerable to known SHA-1 collision
attacks. When a faster SHA-1 implementation without collision detection is used
for only non-cryptographic purposes, the algorithm is displayed in the form
`non-collision-detecting-SHA-1: <option>`.
+
The line `feature: push-negotiate-required` indicates support for
`push.negotiate=required`, including rejection of unsupported push transports.
It does not indicate that a particular remote supports negotiation. See
linkgit:git-config[1].

GIT
---
Expand Down
14 changes: 14 additions & 0 deletions Documentation/gitremote-helpers.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,20 @@ Supported commands: 'stateless-connect'.
+
Supported commands: 'list for-push', 'push'.

'push-negotiate-required'::
With 'push', the helper promises to honor `push.negotiate=required`
in the inherited Git configuration. When required, supported
negotiation must complete successfully before enumerating objects for
transfer, constructing a pack, or uploading objects. Failed or
unsupported negotiation must fail the push. Successful negotiation
may find no common commits. On a supported transport, negotiation may
be skipped when there are no negotiation tips, as described for
`push.negotiate` in linkgit:git-config[1].
+
This capability does not enable required negotiation by itself. It does not
apply to 'export', which Git rejects when negotiation is required because
Git would start 'fast-export' before the helper can negotiate.

'export'::
Can discover remote refs and push specified objects from a
fast-import stream to remote refs.
Expand Down
16 changes: 15 additions & 1 deletion fetch-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -2556,6 +2556,20 @@ void negotiate_using_fetch(const struct oid_array *negotiation_restrict_tips,
trace2_data_intmax("negotiate_using_fetch", the_repository,
"in_vain", in_vain);

/*
* Previous responses are complete and there are no new haves.
* An empty request could ask the server to send a pack instead.
* Still send the first request: it may contain only explicit
* negotiation-include commits, which add_haves() does not count.
*/
if (!haves_added && negotiation_round > 1) {
trace2_region_leave_printf("negotiate_using_fetch", "round",
the_repository, "%d",
negotiation_round);
negotiation_round--;
break;
}

/* Send request */
packet_buf_flush(&req_buf);
if (write_in_full(fd[1], req_buf.buf, req_buf.len) < 0)
Expand Down Expand Up @@ -2588,7 +2602,7 @@ void negotiate_using_fetch(const struct oid_array *negotiation_restrict_tips,
REACH_SCRATCH, 0,
min_generation))
last_iteration = 1;
trace2_region_leave_printf("negotiation", "round",
trace2_region_leave_printf("negotiate_using_fetch", "round",
the_repository, "%d",
negotiation_round);
}
Expand Down
1 change: 1 addition & 0 deletions help.c
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,7 @@ void get_version_info(struct strbuf *buf, int show_build_options)

if (fsmonitor_ipc__is_supported())
strbuf_addstr(buf, "feature: fsmonitor--daemon\n");
strbuf_addstr(buf, "feature: push-negotiate-required\n");
#if !defined NO_GETTEXT
strbuf_addstr(buf, "gettext: enabled\n");
#endif
Expand Down
4 changes: 4 additions & 0 deletions http-push.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "object-file.h"
#include "odb.h"
#include "commit-reach.h"
#include "send-pack.h"

#ifdef EXPAT_NEEDS_XMLPARSE_H
#include <xmlparse.h>
Expand Down Expand Up @@ -1792,6 +1793,9 @@ int cmd_main(int argc, const char **argv)

gitdir = setup_git_directory(the_repository);

if (get_push_negotiation_mode(the_repository) == PUSH_NEGOTIATE_REQUIRED)
die(_("WebDAV does not support required push negotiation"));

memset(remote_dir_exists, -1, 256);

http_init(NULL, repo->url, 1);
Expand Down
Loading
Loading