Version in base suite: 2.39.2-1.1 Base version: git_2.39.2-1.1 Target version: git_2.39.5-0+deb12u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/g/git/git_2.39.2-1.1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/g/git/git_2.39.5-0+deb12u1.dsc .github/workflows/check-whitespace.yml | 63 +++++++-- .github/workflows/l10n.yml | 6 .github/workflows/main.yml | 87 ++++++++---- Documentation/RelNotes/2.30.9.txt | 43 ++++++ Documentation/RelNotes/2.31.8.txt | 6 Documentation/RelNotes/2.32.7.txt | 7 + Documentation/RelNotes/2.33.8.txt | 7 + Documentation/RelNotes/2.34.8.txt | 7 + Documentation/RelNotes/2.35.8.txt | 7 + Documentation/RelNotes/2.36.6.txt | 7 + Documentation/RelNotes/2.37.7.txt | 7 + Documentation/RelNotes/2.38.5.txt | 8 + Documentation/RelNotes/2.39.3.txt | 64 +++++++++ Documentation/RelNotes/2.39.4.txt | 79 +++++++++++ Documentation/RelNotes/2.39.5.txt | 26 +++ Documentation/git-branch.txt | 4 Documentation/git-checkout.txt | 14 +- Documentation/git-cherry-pick.txt | 2 Documentation/git-merge.txt | 3 Documentation/git-rebase.txt | 7 + Documentation/git-reset.txt | 3 Documentation/git-upload-pack.txt | 31 ++++ Documentation/git.txt | 31 ++++ Documentation/githooks.txt | 12 + Documentation/revisions.txt | 3 GIT-VERSION-GEN | 2 INSTALL | 2 Makefile | 11 + RelNotes | 29 +++- add-interactive.c | 2 apply.c | 18 ++ blob.c | 3 blob.h | 3 builtin/add.c | 2 builtin/am.c | 12 + builtin/branch.c | 6 builtin/bundle.c | 9 - builtin/clone.c | 39 ++++- builtin/fast-export.c | 2 builtin/init-db.c | 22 --- builtin/ls-tree.c | 13 - builtin/merge-tree.c | 2 builtin/merge.c | 2 builtin/rerere.c | 2 builtin/reset.c | 3 builtin/submodule--helper.c | 88 ++++++++++++ builtin/upload-pack.c | 2 cache.h | 15 ++ ci/install-dependencies.sh | 2 ci/lib.sh | 10 - combine-diff.c | 2 commit.c | 6 compat/fsmonitor/fsm-darwin-gcc.h | 4 compat/fsmonitor/fsm-listen-darwin.c | 35 +++-- compat/regcomp_enhanced.c | 9 + config.c | 36 +++-- config.mak.uname | 1 configure | 18 +- connect.c | 21 +-- connect.h | 3 debian/changelog | 10 + debian/changelog.upstream | 229 +++++++++++++++++++++++++++++++++ debian/versions.upstream | 3 diff-lib.c | 2 diff.c | 48 +++--- dir.c | 19 ++ dir.h | 7 + entry.c | 16 ++ fetch-pack.c | 12 - gettext.c | 4 gettext.h | 6 git-compat-util.h | 22 ++- git-curl-compat.h | 9 + git-send-email.perl | 32 +--- hook.c | 18 +- http.c | 37 ++++- line-range.c | 7 - list-objects-filter.c | 31 ++-- list-objects.c | 33 ---- ls-refs.c | 5 object-file.c | 11 - object.c | 5 pack-write.c | 1 path.c | 2 promisor-remote.c | 10 + range-diff.c | 12 + read-cache.c | 72 ++-------- ref-filter.c | 5 reflog.c | 4 refs.c | 9 - refs.h | 6 refs/packed-backend.c | 3 remote-curl.c | 3 revision.c | 25 ++- sequencer.c | 1 setup.c | 76 ++++++++++ submodule.c | 91 ++++++++++++- submodule.h | 5 t/lib-httpd.sh | 17 +- t/lib-httpd/apache.conf | 33 ---- t/lib-httpd/ssl.cnf | 2 t/t0000-basic.sh | 28 ++++ t/t0033-safe-directory.sh | 24 +++ t/t0411-clone-from-partial.sh | 78 +++++++++++ t/t1091-sparse-checkout-builtin.sh | 11 + t/t1300-config.sh | 30 ++++ t/t1350-config-hooks-path.sh | 7 + t/t3104-ls-tree-format.sh | 6 t/t3204-branch-name-interpretation.sh | 10 + t/t3920-crlf-messages.sh | 2 t/t4023-diff-rename-typechange.sh | 12 - t/t4045-diff-relative.sh | 29 ++++ t/t4115-apply-symlink.sh | 15 ++ t/t4205-log-pretty-formats.sh | 2 t/t4211-line-log.sh | 22 +++ t/t5314-pack-cycle-detection.sh | 17 +- t/t5510-fetch.sh | 24 +++ t/t5541-http-push-smart.sh | 57 +------- t/t5551-http-fetch-smart.sh | 172 +++++++++++++++--------- t/t5559-http-fetch-smart-http2.sh | 1 t/t5601-clone.sh | 15 ++ t/t6020-bundle-misc.sh | 7 + t/t7400-submodule-basic.sh | 31 ++++ t/t7406-submodule-update.sh | 48 ++++++ t/t7423-submodule-symlinks.sh | 67 +++++++++ t/t7450-bad-git-dotfiles.sh | 34 ++++ t/t7600-merge.sh | 2 t/t9001-send-email.sh | 5 t/test-lib.sh | 1 unpack-trees.c | 1 userdiff.c | 3 version | 2 ws.c | 2 wt-status.c | 4 xdiff/xdiffi.c | 2 xdiff/xemit.c | 4 136 files changed, 2128 insertions(+), 560 deletions(-) diff -Nru git-2.39.2/.github/workflows/check-whitespace.yml git-2.39.5/.github/workflows/check-whitespace.yml --- git-2.39.2/.github/workflows/check-whitespace.yml 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/.github/workflows/check-whitespace.yml 2024-05-31 00:35:55.000000000 +0000 @@ -9,42 +9,83 @@ pull_request: types: [opened, synchronize] +# Avoid unnecessary builds. Unlike the main CI jobs, these are not +# ci-configurable (but could be). +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: check-whitespace: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: git log --check id: check_out run: | - log= + baseSha=${{github.event.pull_request.base.sha}} + problems=() commit= - while read dash etc + commitText= + commitTextmd= + goodparent= + while read dash sha etc do case "${dash}" in "---") - commit="${etc}" + if test -z "${commit}" + then + goodparent=${sha} + fi + commit="${sha}" + commitText="${sha} ${etc}" + commitTextmd="[${sha}](https://github.com/${{ github.repository }}/commit/${sha}) ${etc}" ;; "") ;; *) if test -n "${commit}" then - log="${log}\n${commit}" + problems+=("1) --- ${commitTextmd}") echo "" - echo "--- ${commit}" + echo "--- ${commitText}" + commit= fi - commit= - log="${log}\n${dash} ${etc}" - echo "${dash} ${etc}" + case "${dash}" in + *:[1-9]*:) # contains file and line number information + dashend=${dash#*:} + problems+=("[${dash}](https://github.com/${{ github.repository }}/blob/${{github.event.pull_request.head.ref}}/${dash%%:*}#L${dashend%:}) ${sha} ${etc}") + ;; + *) + problems+=("\`${dash} ${sha} ${etc}\`") + ;; + esac + echo "${dash} ${sha} ${etc}" ;; esac - done <<< $(git log --check --pretty=format:"---% h% s" ${{github.event.pull_request.base.sha}}..) + done <<< $(git log --check --pretty=format:"---% h% s" ${baseSha}..) - if test -n "${log}" + if test ${#problems[*]} -gt 0 then + if test -z "${commit}" + then + goodparent=${baseSha: 0:7} + fi + echo "đŸ›‘ Please review the Summary output for further information." + echo "### :x: A whitespace issue was found in one or more of the commits." >$GITHUB_STEP_SUMMARY + echo "" >>$GITHUB_STEP_SUMMARY + echo "Run these commands to correct the problem:" >>$GITHUB_STEP_SUMMARY + echo "1. \`git rebase --whitespace=fix ${goodparent}\`" >>$GITHUB_STEP_SUMMARY + echo "1. \`git push --force\`" >>$GITHUB_STEP_SUMMARY + echo " " >>$GITHUB_STEP_SUMMARY + echo "Errors:" >>$GITHUB_STEP_SUMMARY + for i in "${problems[@]}" + do + echo "${i}" >>$GITHUB_STEP_SUMMARY + done + exit 2 fi diff -Nru git-2.39.2/.github/workflows/l10n.yml git-2.39.5/.github/workflows/l10n.yml --- git-2.39.2/.github/workflows/l10n.yml 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/.github/workflows/l10n.yml 2024-05-31 00:35:55.000000000 +0000 @@ -2,6 +2,12 @@ on: [push, pull_request_target] +# Avoid unnecessary builds. Unlike the main CI jobs, these are not +# ci-configurable (but could be). +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: git-po-helper: if: >- diff -Nru git-2.39.2/.github/workflows/main.yml git-2.39.5/.github/workflows/main.yml --- git-2.39.2/.github/workflows/main.yml 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/.github/workflows/main.yml 2024-05-31 00:35:55.000000000 +0000 @@ -11,6 +11,7 @@ runs-on: ubuntu-latest outputs: enabled: ${{ steps.check-ref.outputs.enabled }}${{ steps.skip-if-redundant.outputs.enabled }} + skip_concurrent: ${{ steps.check-ref.outputs.skip_concurrent }} steps: - name: try to clone ci-config branch run: | @@ -34,10 +35,18 @@ then enabled=no fi + + skip_concurrent=yes + if test -x config-repo/ci/config/skip-concurrent && + ! config-repo/ci/config/skip-concurrent '${{ github.ref }}' + then + skip_concurrent=no + fi echo "enabled=$enabled" >>$GITHUB_OUTPUT + 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@v6 + uses: actions/github-script@v7 if: steps.check-ref.outputs.enabled == 'yes' with: github-token: ${{secrets.GITHUB_TOKEN}} @@ -82,8 +91,11 @@ needs: ci-config if: needs.ci-config.outputs.enabled == 'yes' runs-on: windows-latest + concurrency: + group: windows-build-${{ github.ref }} + cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: git-for-windows/setup-git-for-windows-sdk@v1 - name: build shell: bash @@ -94,21 +106,24 @@ - 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@v3 + uses: actions/upload-artifact@v4 with: name: windows-artifacts path: artifacts windows-test: name: win test runs-on: windows-latest - needs: [windows-build] + needs: [ci-config, windows-build] strategy: fail-fast: false matrix: nr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + concurrency: + group: windows-test-${{ matrix.nr }}-${{ github.ref }} + cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - name: download tracked files and build artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: windows-artifacts path: ${{github.workspace}} @@ -125,23 +140,26 @@ run: ci/print-test-failures.sh - name: Upload failed tests' directories if: failure() && env.FAILED_TEST_ARTIFACTS != '' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: failed-tests-windows path: ${{env.FAILED_TEST_ARTIFACTS}} vs-build: name: win+VS build needs: ci-config - if: needs.ci-config.outputs.enabled == 'yes' + if: github.event.repository.owner.login == 'git-for-windows' && needs.ci-config.outputs.enabled == 'yes' env: NO_PERL: 1 GIT_CONFIG_PARAMETERS: "'user.name=CI' 'user.email=ci@git'" runs-on: windows-latest + concurrency: + group: vs-build-${{ github.ref }} + cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: git-for-windows/setup-git-for-windows-sdk@v1 - name: initialize vcpkg - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: 'microsoft/vcpkg' path: 'compat/vcbuild/vcpkg' @@ -177,22 +195,25 @@ - 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@v3 + uses: actions/upload-artifact@v4 with: name: vs-artifacts path: artifacts vs-test: name: win+VS test runs-on: windows-latest - needs: vs-build + needs: [ci-config, vs-build] strategy: fail-fast: false matrix: nr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + concurrency: + 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 - name: download tracked files and build artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: vs-artifacts path: ${{github.workspace}} @@ -210,7 +231,7 @@ run: ci/print-test-failures.sh - name: Upload failed tests' directories if: failure() && env.FAILED_TEST_ARTIFACTS != '' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: failed-tests-windows path: ${{env.FAILED_TEST_ARTIFACTS}} @@ -218,6 +239,9 @@ name: ${{matrix.vector.jobname}} (${{matrix.vector.pool}}) needs: ci-config if: needs.ci-config.outputs.enabled == 'yes' + concurrency: + group: ${{ matrix.vector.jobname }}-${{ matrix.vector.pool }}-${{ github.ref }} + cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} strategy: fail-fast: false matrix: @@ -238,11 +262,10 @@ pool: ubuntu-20.04 - jobname: osx-clang cc: clang - pool: macos-12 + pool: macos-13 - jobname: osx-gcc - cc: gcc - cc_package: gcc-9 - pool: macos-12 + cc: gcc-13 + pool: macos-13 - jobname: linux-gcc-default cc: gcc pool: ubuntu-latest @@ -262,14 +285,14 @@ runs_on_pool: ${{matrix.vector.pool}} runs-on: ${{matrix.vector.pool}} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: ci/install-dependencies.sh - run: ci/run-build-and-tests.sh - run: ci/print-test-failures.sh if: failure() && env.FAILED_TEST_ARTIFACTS != '' - name: Upload failed tests' directories if: failure() && env.FAILED_TEST_ARTIFACTS != '' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: failed-tests-${{matrix.vector.jobname}} path: ${{env.FAILED_TEST_ARTIFACTS}} @@ -277,6 +300,9 @@ name: ${{matrix.vector.jobname}} (${{matrix.vector.image}}) needs: ci-config if: needs.ci-config.outputs.enabled == 'yes' + concurrency: + group: dockerized-${{ matrix.vector.jobname }}-${{ matrix.vector.image }}-${{ github.ref }} + cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} strategy: fail-fast: false matrix: @@ -292,9 +318,9 @@ runs-on: ubuntu-latest container: ${{matrix.vector.image}} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 if: matrix.vector.jobname != 'linux32' - - uses: actions/checkout@v1 + - uses: actions/checkout@v1 # cannot be upgraded because Node.js Actions aren't supported in this container if: matrix.vector.jobname == 'linux32' - run: ci/install-docker-dependencies.sh - run: ci/run-build-and-tests.sh @@ -302,13 +328,13 @@ if: failure() && env.FAILED_TEST_ARTIFACTS != '' - name: Upload failed tests' directories if: failure() && env.FAILED_TEST_ARTIFACTS != '' && matrix.vector.jobname != 'linux32' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: failed-tests-${{matrix.vector.jobname}} path: ${{env.FAILED_TEST_ARTIFACTS}} - name: Upload failed tests' directories if: failure() && env.FAILED_TEST_ARTIFACTS != '' && matrix.vector.jobname == 'linux32' - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v1 # cannot be upgraded because Node.js Actions aren't supported in this container with: name: failed-tests-${{matrix.vector.jobname}} path: ${{env.FAILED_TEST_ARTIFACTS}} @@ -318,8 +344,11 @@ env: jobname: StaticAnalysis runs-on: ubuntu-22.04 + concurrency: + group: static-analysis-${{ github.ref }} + cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: ci/install-dependencies.sh - run: ci/run-static-analysis.sh - run: ci/check-directional-formatting.bash @@ -329,6 +358,9 @@ env: jobname: sparse runs-on: ubuntu-20.04 + concurrency: + group: sparse-${{ github.ref }} + cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} steps: - name: Download a current `sparse` package # Ubuntu's `sparse` version is too old for us @@ -339,7 +371,7 @@ artifact: sparse-20.04 - name: Install the current `sparse` package run: sudo dpkg -i sparse-20.04/sparse_*.deb - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install other dependencies run: ci/install-dependencies.sh - run: make sparse @@ -347,10 +379,13 @@ name: documentation needs: ci-config if: needs.ci-config.outputs.enabled == 'yes' + concurrency: + group: documentation-${{ github.ref }} + cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }} env: jobname: Documentation runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: ci/install-dependencies.sh - run: ci/test-documentation.sh diff -Nru git-2.39.2/Documentation/RelNotes/2.30.9.txt git-2.39.5/Documentation/RelNotes/2.30.9.txt --- git-2.39.2/Documentation/RelNotes/2.30.9.txt 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/Documentation/RelNotes/2.30.9.txt 2024-05-31 00:35:55.000000000 +0000 @@ -0,0 +1,43 @@ +Git v2.30.9 Release Notes +========================= + +This release addresses the security issues CVE-2023-25652, +CVE-2023-25815, and CVE-2023-29007. + + +Fixes since v2.30.8 +------------------- + + * CVE-2023-25652: + + By feeding specially crafted input to `git apply --reject`, a + path outside the working tree can be overwritten with partially + controlled contents (corresponding to the rejected hunk(s) from + the given patch). + + * CVE-2023-25815: + + When Git is compiled with runtime prefix support and runs without + translated messages, it still used the gettext machinery to + display messages, which subsequently potentially looked for + translated messages in unexpected places. This allowed for + malicious placement of crafted messages. + + * CVE-2023-29007: + + When renaming or deleting a section from a configuration file, + certain malicious configuration values may be misinterpreted as + the beginning of a new configuration section, leading to arbitrary + configuration injection. + +Credit for finding CVE-2023-25652 goes to Ry0taK, and the fix was +developed by Taylor Blau, Junio C Hamano and Johannes Schindelin, +with the help of Linus Torvalds. + +Credit for finding CVE-2023-25815 goes to Maxime Escourbiac and +Yassine BENGANA of Michelin, and the fix was developed by Johannes +Schindelin. + +Credit for finding CVE-2023-29007 goes to AndrĂ© Baptista and VĂ­tor Pinho +of Ethiack, and the fix was developed by Taylor Blau, and Johannes +Schindelin, with help from Jeff King, and Patrick Steinhardt. diff -Nru git-2.39.2/Documentation/RelNotes/2.31.8.txt git-2.39.5/Documentation/RelNotes/2.31.8.txt --- git-2.39.2/Documentation/RelNotes/2.31.8.txt 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/Documentation/RelNotes/2.31.8.txt 2024-05-31 00:35:55.000000000 +0000 @@ -0,0 +1,6 @@ +Git v2.31.8 Release Notes +========================= + +This release merges the fixes that appear in v2.30.9 to address the +security issues CVE-2023-25652, CVE-2023-25815, and CVE-2023-29007; +see the release notes for that version for details. diff -Nru git-2.39.2/Documentation/RelNotes/2.32.7.txt git-2.39.5/Documentation/RelNotes/2.32.7.txt --- git-2.39.2/Documentation/RelNotes/2.32.7.txt 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/Documentation/RelNotes/2.32.7.txt 2024-05-31 00:35:55.000000000 +0000 @@ -0,0 +1,7 @@ +Git v2.32.7 Release Notes +========================= + +This release merges the fixes that appear in v2.30.9 and v2.31.8 to +address the security issues CVE-2023-25652, CVE-2023-25815, and +CVE-2023-29007; see the release notes for these versions for +details. diff -Nru git-2.39.2/Documentation/RelNotes/2.33.8.txt git-2.39.5/Documentation/RelNotes/2.33.8.txt --- git-2.39.2/Documentation/RelNotes/2.33.8.txt 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/Documentation/RelNotes/2.33.8.txt 2024-05-31 00:35:55.000000000 +0000 @@ -0,0 +1,7 @@ +Git v2.33.8 Release Notes +========================= + +This release merges the fixes that appear in v2.30.9, v2.31.8 and +v2.32.7 to address the security issues CVE-2023-25652, +CVE-2023-25815, and CVE-2023-29007; see the release notes for these +versions for details. diff -Nru git-2.39.2/Documentation/RelNotes/2.34.8.txt git-2.39.5/Documentation/RelNotes/2.34.8.txt --- git-2.39.2/Documentation/RelNotes/2.34.8.txt 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/Documentation/RelNotes/2.34.8.txt 2024-05-31 00:35:55.000000000 +0000 @@ -0,0 +1,7 @@ +Git v2.34.8 Release Notes +========================= + +This release merges the fixes that appear in v2.30.9, v2.31.8, +v2.32.7 and v2.33.8 to address the security issues CVE-2023-25652, +CVE-2023-25815, and CVE-2023-29007; see the release notes for these +versions for details. diff -Nru git-2.39.2/Documentation/RelNotes/2.35.8.txt git-2.39.5/Documentation/RelNotes/2.35.8.txt --- git-2.39.2/Documentation/RelNotes/2.35.8.txt 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/Documentation/RelNotes/2.35.8.txt 2024-05-31 00:35:55.000000000 +0000 @@ -0,0 +1,7 @@ +Git v2.35.8 Release Notes +========================= + +This release merges the fixes that appear in v2.30.9, v2.31.8, +v2.32.7, v2.33.8 and v2.34.8 to address the security issues +CVE-2023-25652, CVE-2023-25815, and CVE-2023-29007; see the release +notes for these versions for details. diff -Nru git-2.39.2/Documentation/RelNotes/2.36.6.txt git-2.39.5/Documentation/RelNotes/2.36.6.txt --- git-2.39.2/Documentation/RelNotes/2.36.6.txt 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/Documentation/RelNotes/2.36.6.txt 2024-05-31 00:35:55.000000000 +0000 @@ -0,0 +1,7 @@ +Git v2.36.6 Release Notes +========================= + +This release merges the fixes that appear in v2.30.9, v2.31.8, +v2.32.7, v2.33.8, v2.34.8 and v2.35.8 to address the security issues +CVE-2023-25652, CVS-2023-25815, and CVE-2023-29007; see the release +notes for these versions for details. diff -Nru git-2.39.2/Documentation/RelNotes/2.37.7.txt git-2.39.5/Documentation/RelNotes/2.37.7.txt --- git-2.39.2/Documentation/RelNotes/2.37.7.txt 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/Documentation/RelNotes/2.37.7.txt 2024-05-31 00:35:55.000000000 +0000 @@ -0,0 +1,7 @@ +Git v2.37.7 Release Notes +========================= + +This release merges up the fix that appears in v2.30.9, v2.31.8, +v2.32.7, v2.33.8, v2.34.8, v2.35.8 and v2.36.6 to address the +security issues CVE-2023-25652, CVE-2023-25815, and CVE-2023-29007; +see the release notes for these versions for details. diff -Nru git-2.39.2/Documentation/RelNotes/2.38.5.txt git-2.39.5/Documentation/RelNotes/2.38.5.txt --- git-2.39.2/Documentation/RelNotes/2.38.5.txt 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/Documentation/RelNotes/2.38.5.txt 2024-05-31 00:35:55.000000000 +0000 @@ -0,0 +1,8 @@ +Git v2.38.5 Release Notes +========================= + +This release merges up the fix that appears in v2.30.9, v2.31.8, +v2.32.7, v2.33.8, v2.34.8, v2.35.8, v2.36.6 and v2.37.7 to address +the security issues CVE-2023-25652, CVE-2023-25815, and +CVE-2023-29007; see the release notes for these versions for +details. diff -Nru git-2.39.2/Documentation/RelNotes/2.39.3.txt git-2.39.5/Documentation/RelNotes/2.39.3.txt --- git-2.39.2/Documentation/RelNotes/2.39.3.txt 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/Documentation/RelNotes/2.39.3.txt 2024-05-31 00:35:55.000000000 +0000 @@ -0,0 +1,64 @@ +Git v2.39.3 Release Notes +========================= + +This release merges up the fix that appears in v2.30.9, v2.31.8, +v2.32.7, v2.33.8, v2.34.8, v2.35.8, v2.36.6, v2.37.7 and v2.38.5 to +address the security issues CVE-2023-25652, CVE-2023-25815, and +CVE-2023-29007; see the release notes for these versions for +details. + +This release also merges fixes that have accumulated on the 'master' +front to prepare for the 2.40 release that are still relevant to +2.39.x maintenance track. + +Fixes since v2.39.2 +------------------- + + * Stop running win+VS build by default. + + * CI updates. We probably want a clean-up to move the long shell + script embedded in yaml file into a separate file, but that can + come later. + + * Avoid unnecessary builds in CI, with settings configured in + ci-config. + + * Redefining system functions for a few functions did not follow our + usual "implement git_foo() and #define foo(args) git_foo(args)" + pattern, which has broken build for some folks. + + * Deal with a few deprecation warning from cURL library. + + * Newer regex library macOS stopped enabling GNU-like enhanced BRE, + where '\(A\|B\)' works as alternation, unless explicitly asked with + the REG_ENHANCED flag. "git grep" now can be compiled to do so, to + retain the old behaviour. + + * When given a pattern that matches an empty string at the end of a + line, the code to parse the "git diff" line-ranges fell into an + infinite loop, which has been corrected. + + * Fix the sequence to fsync $GIT_DIR/packed-refs file that forgot to + flush its output to the disk.. + + * "git diff --relative" did not mix well with "git diff --ext-diff", + which has been corrected. + + * The logic to see if we are using the "cone" mode by checking the + sparsity patterns has been tightened to avoid mistaking a pattern + that names a single file as specifying a cone. + + * Doc update for environment variables set when hooks are invoked. + + * Document ORIG_HEAD a bit more. + + * "git ls-tree --format='%(path) %(path)' $tree $path" showed the + path three times, which has been corrected. + + * Document that "branch -f " disables only the safety to + avoid recreating an existing branch. + + * Clarify how "checkout -b/-B" and "git branch [-f]" are similar but + different in the documentation. + +Also contains minor documentation updates and code clean-ups. diff -Nru git-2.39.2/Documentation/RelNotes/2.39.4.txt git-2.39.5/Documentation/RelNotes/2.39.4.txt --- git-2.39.2/Documentation/RelNotes/2.39.4.txt 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/Documentation/RelNotes/2.39.4.txt 2024-05-31 00:35:55.000000000 +0000 @@ -0,0 +1,79 @@ +Git v2.39.4 Release Notes +========================= + +This addresses the security issues CVE-2024-32002, CVE-2024-32004, +CVE-2024-32020 and CVE-2024-32021. + +This release also backports fixes necessary to let the CI builds pass +successfully. + +Fixes since v2.39.3 +------------------- + + * CVE-2024-32002: + + Recursive clones on case-insensitive filesystems that support symbolic + links are susceptible to case confusion that can be exploited to + execute just-cloned code during the clone operation. + + * CVE-2024-32004: + + Repositories can be configured to execute arbitrary code during local + clones. To address this, the ownership checks introduced in v2.30.3 + are now extended to cover cloning local repositories. + + * CVE-2024-32020: + + Local clones may end up hardlinking files into the target repository's + object database when source and target repository reside on the same + disk. If the source repository is owned by a different user, then + those hardlinked files may be rewritten at any point in time by the + untrusted user. + + * CVE-2024-32021: + + When cloning a local source repository that contains symlinks via the + filesystem, Git may create hardlinks to arbitrary user-readable files + on the same filesystem as the target repository in the objects/ + directory. + + * CVE-2024-32465: + + It is supposed to be safe to clone untrusted repositories, even those + unpacked from zip archives or tarballs originating from untrusted + sources, but Git can be tricked to run arbitrary code as part of the + clone. + + * Defense-in-depth: submodule: require the submodule path to contain + directories only. + + * Defense-in-depth: clone: when symbolic links collide with directories, keep + the latter. + + * Defense-in-depth: clone: prevent hooks from running during a clone. + + * Defense-in-depth: core.hooksPath: add some protection while cloning. + + * Defense-in-depth: fsck: warn about symlink pointing inside a gitdir. + + * Various fix-ups on HTTP tests. + + * Test update. + + * HTTP Header redaction code has been adjusted for a newer version of + cURL library that shows its traces differently from earlier + versions. + + * Fix was added to work around a regression in libcURL 8.7.0 (which has + already been fixed in their tip of the tree). + + * Replace macos-12 used at GitHub CI with macos-13. + + * ci(linux-asan/linux-ubsan): let's save some time + + * Tests with LSan from time to time seem to emit harmless message that makes + our tests unnecessarily flakey; we work it around by filtering the + uninteresting output. + + * Update GitHub Actions jobs to avoid warnings against using deprecated + version of Node.js. diff -Nru git-2.39.2/Documentation/RelNotes/2.39.5.txt git-2.39.5/Documentation/RelNotes/2.39.5.txt --- git-2.39.2/Documentation/RelNotes/2.39.5.txt 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/Documentation/RelNotes/2.39.5.txt 2024-05-31 00:35:55.000000000 +0000 @@ -0,0 +1,26 @@ +Git v2.39.5 Release Notes +========================= + +In preparing security fixes for four CVEs, we made overly aggressive +"defense in depth" changes that broke legitimate use cases like 'git +lfs' and 'git annex.' This release is to revert these misguided, if +well-intentioned, changes that were shipped in 2.39.4 and were not +direct security fixes. + +Jeff King (5): + send-email: drop FakeTerm hack + send-email: avoid creating more than one Term::ReadLine object + ci: drop mention of BREW_INSTALL_PACKAGES variable + ci: avoid bare "gcc" for osx-gcc job + ci: stop installing "gcc-13" for osx-gcc + +Johannes Schindelin (6): + hook: plug a new memory leak + init: use the correct path of the templates directory again + Revert "core.hooksPath: add some protection while cloning" + tests: verify that `clone -c core.hooksPath=/dev/null` works again + clone: drop the protections where hooks aren't run + Revert "Add a helper function to compare file contents" + +Junio C Hamano (1): + Revert "fsck: warn about symlink pointing inside a gitdir" diff -Nru git-2.39.2/Documentation/git-branch.txt git-2.39.5/Documentation/git-branch.txt --- git-2.39.2/Documentation/git-branch.txt 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/Documentation/git-branch.txt 2024-05-31 00:35:55.000000000 +0000 @@ -123,6 +123,10 @@ points to a valid commit. In combination with `-m` (or `--move`), allow renaming the branch even if the new branch name already exists, the same applies for `-c` (or `--copy`). ++ +Note that 'git branch -f []', even with '-f', +refuses to change an existing branch `` that is checked out +in another worktree linked to the same repository. -m:: --move:: diff -Nru git-2.39.2/Documentation/git-checkout.txt git-2.39.5/Documentation/git-checkout.txt --- git-2.39.2/Documentation/git-checkout.txt 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/Documentation/git-checkout.txt 2024-05-31 00:35:55.000000000 +0000 @@ -146,14 +146,16 @@ of it"). -b :: - Create a new branch named `` and start it at - ``; see linkgit:git-branch[1] for details. + Create a new branch named ``, start it at + ``, and check the resulting branch out; + see linkgit:git-branch[1] for details. -B :: - Creates the branch `` and start it at ``; - if it already exists, then reset it to ``. This is - equivalent to running "git branch" with "-f"; see - linkgit:git-branch[1] for details. + Creates the branch ``, start it at ``; + if it already exists, then reset it to ``. And then + check the resulting branch out. This is equivalent to running + "git branch" with "-f" followed by "git checkout" of that branch; + see linkgit:git-branch[1] for details. -t:: --track[=(direct|inherit)]:: diff -Nru git-2.39.2/Documentation/git-cherry-pick.txt git-2.39.5/Documentation/git-cherry-pick.txt --- git-2.39.2/Documentation/git-cherry-pick.txt 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/Documentation/git-cherry-pick.txt 2024-05-31 00:35:55.000000000 +0000 @@ -219,7 +219,7 @@ ------------ $ git cherry-pick topic^ <1> $ git diff <2> -$ git reset --merge ORIG_HEAD <3> +$ git cherry-pick --abort <3> $ git cherry-pick -Xpatience topic^ <4> ------------ <1> apply the change that would be shown by `git show topic^`. diff -Nru git-2.39.2/Documentation/git-merge.txt git-2.39.5/Documentation/git-merge.txt --- git-2.39.2/Documentation/git-merge.txt 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/Documentation/git-merge.txt 2024-05-31 00:35:55.000000000 +0000 @@ -37,7 +37,8 @@ `topic` branch since it diverged from `master` (i.e., `E`) until its current commit (`C`) on top of `master`, and record the result in a new commit along with the names of the two parent commits and -a log message from the user describing the changes. +a log message from the user describing the changes. Before the operation, +`ORIG_HEAD` is set to the tip of the current branch (`C`). ------------ A---B---C topic diff -Nru git-2.39.2/Documentation/git-rebase.txt git-2.39.5/Documentation/git-rebase.txt --- git-2.39.2/Documentation/git-rebase.txt 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/Documentation/git-rebase.txt 2024-05-31 00:35:55.000000000 +0000 @@ -38,6 +38,13 @@ `git reset --hard ` (or ``). `ORIG_HEAD` is set to point at the tip of the branch before the reset. +[NOTE] +`ORIG_HEAD` is not guaranteed to still point to the previous branch tip +at the end of the rebase if other commands that write that pseudo-ref +(e.g. `git reset`) are used during the rebase. The previous branch tip, +however, is accessible using the reflog of the current branch +(i.e. `@{1}`, see linkgit:gitrevisions[7]). + The commits that were previously saved into the temporary area are then reapplied to the current branch, one by one, in order. Note that any commits in `HEAD` which introduce the same textual changes as a commit diff -Nru git-2.39.2/Documentation/git-reset.txt git-2.39.5/Documentation/git-reset.txt --- git-2.39.2/Documentation/git-reset.txt 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/Documentation/git-reset.txt 2024-05-31 00:35:55.000000000 +0000 @@ -49,7 +49,8 @@ 'git reset' [] []:: This form resets the current branch head to `` and possibly updates the index (resetting it to the tree of ``) and - the working tree depending on ``. If `` is omitted, + the working tree depending on ``. Before the operation, `ORIG_HEAD` + is set to the tip of the current branch. If `` is omitted, defaults to `--mixed`. The `` must be one of the following: + -- diff -Nru git-2.39.2/Documentation/git-upload-pack.txt git-2.39.5/Documentation/git-upload-pack.txt --- git-2.39.2/Documentation/git-upload-pack.txt 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/Documentation/git-upload-pack.txt 2024-05-31 00:35:55.000000000 +0000 @@ -55,6 +55,37 @@ admins may need to configure some transports to allow this variable to be passed. See the discussion in linkgit:git[1]. +`GIT_NO_LAZY_FETCH`:: + When cloning or fetching from a partial repository (i.e., one + itself cloned with `--filter`), the server-side `upload-pack` + may need to fetch extra objects from its upstream in order to + complete the request. By default, `upload-pack` will refuse to + perform such a lazy fetch, because `git fetch` may run arbitrary + commands specified in configuration and hooks of the source + repository (and `upload-pack` tries to be safe to run even in + untrusted `.git` directories). ++ +This is implemented by having `upload-pack` internally set the +`GIT_NO_LAZY_FETCH` variable to `1`. If you want to override it +(because you are fetching from a partial clone, and you are sure +you trust it), you can explicitly set `GIT_NO_LAZY_FETCH` to +`0`. + +SECURITY +-------- + +Most Git commands should not be run in an untrusted `.git` directory +(see the section `SECURITY` in linkgit:git[1]). `upload-pack` tries to +avoid any dangerous configuration options or hooks from the repository +it's serving, making it safe to clone an untrusted directory and run +commands on the resulting clone. + +For an extra level of safety, you may be able to run `upload-pack` as an +alternate user. The details will be platform dependent, but on many +systems you can run: + + git clone --no-local --upload-pack='sudo -u nobody git-upload-pack' ... + SEE ALSO -------- linkgit:gitnamespaces[7] diff -Nru git-2.39.2/Documentation/git.txt git-2.39.5/Documentation/git.txt --- git-2.39.2/Documentation/git.txt 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/Documentation/git.txt 2024-05-31 00:35:55.000000000 +0000 @@ -1032,6 +1032,37 @@ for a given pathname. These stages are used to hold the various unmerged version of a file when a merge is in progress. +SECURITY +-------- + +Some configuration options and hook files may cause Git to run arbitrary +shell commands. Because configuration and hooks are not copied using +`git clone`, it is generally safe to clone remote repositories with +untrusted content, inspect them with `git log`, and so on. + +However, it is not safe to run Git commands in a `.git` directory (or +the working tree that surrounds it) when that `.git` directory itself +comes from an untrusted source. The commands in its config and hooks +are executed in the usual way. + +By default, Git will refuse to run when the repository is owned by +someone other than the user running the command. See the entry for +`safe.directory` in linkgit:git-config[1]. While this can help protect +you in a multi-user environment, note that you can also acquire +untrusted repositories that are owned by you (for example, if you +extract a zip file or tarball from an untrusted source). In such cases, +you'd need to "sanitize" the untrusted repository first. + +If you have an untrusted `.git` directory, you should first clone it +with `git clone --no-local` to obtain a clean copy. Git does restrict +the set of options and hooks that will be run by `upload-pack`, which +handles the server side of a clone or fetch, but beware that the +surface area for attack against `upload-pack` is large, so this does +carry some risk. The safest thing is to serve the repository as an +unprivileged user (either via linkgit:git-daemon[1], ssh, or using +other tools to change user ids). See the discussion in the `SECURITY` +section of linkgit:git-upload-pack[1]. + FURTHER DOCUMENTATION --------------------- diff -Nru git-2.39.2/Documentation/githooks.txt git-2.39.5/Documentation/githooks.txt --- git-2.39.2/Documentation/githooks.txt 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/Documentation/githooks.txt 2024-05-31 00:35:55.000000000 +0000 @@ -27,6 +27,18 @@ 'update', 'post-receive', 'post-update', 'push-to-checkout') which are always executed in $GIT_DIR. +Environment variables, such as `GIT_DIR`, `GIT_WORK_TREE`, etc., are exported +so that Git commands run by the hook can correctly locate the repository. If +your hook needs to invoke Git commands in a foreign repository or in a +different working tree of the same repository, then it should clear these +environment variables so they do not interfere with Git operations at the +foreign location. For example: + +------------ +local_desc=$(git describe) +foreign_desc=$(unset $(git rev-parse --local-env-vars); git -C ../foreign-repo describe) +------------ + Hooks can get their arguments via the environment, command-line arguments, and stdin. See the documentation for each hook below for details. diff -Nru git-2.39.2/Documentation/revisions.txt git-2.39.5/Documentation/revisions.txt --- git-2.39.2/Documentation/revisions.txt 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/Documentation/revisions.txt 2024-05-31 00:35:55.000000000 +0000 @@ -49,7 +49,8 @@ `FETCH_HEAD` records the branch which you fetched from a remote repository with your last `git fetch` invocation. `ORIG_HEAD` is created by commands that move your `HEAD` in a drastic -way, to record the position of the `HEAD` before their operation, so that +way (`git am`, `git merge`, `git rebase`, `git reset`), +to record the position of the `HEAD` before their operation, so that you can easily change the tip of the branch back to the state before you ran them. `MERGE_HEAD` records the commit(s) which you are merging into your branch diff -Nru git-2.39.2/GIT-VERSION-GEN git-2.39.5/GIT-VERSION-GEN --- git-2.39.2/GIT-VERSION-GEN 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/GIT-VERSION-GEN 2024-05-31 00:35:55.000000000 +0000 @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.39.2 +DEF_VER=v2.39.5 LF=' ' diff -Nru git-2.39.2/INSTALL git-2.39.5/INSTALL --- git-2.39.2/INSTALL 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/INSTALL 2024-05-31 00:35:55.000000000 +0000 @@ -139,7 +139,7 @@ not need that functionality, use NO_CURL to build without it. - Git requires version "7.19.5" or later of "libcurl" to build + Git requires version "7.21.3" or later of "libcurl" to build without NO_CURL. This version requirement may be bumped in the future. diff -Nru git-2.39.2/Makefile git-2.39.5/Makefile --- git-2.39.2/Makefile 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/Makefile 2024-05-31 00:35:55.000000000 +0000 @@ -289,6 +289,10 @@ # Define NO_REGEX if your C library lacks regex support with REG_STARTEND # feature. # +# Define USE_ENHANCED_BASIC_REGULAR_EXPRESSIONS if your C library provides +# the flag REG_ENHANCED and you'd like to use it to enable enhanced basic +# regular expressions. +# # Define HAVE_DEV_TTY if your system can open /dev/tty to interact with the # user. # @@ -2040,6 +2044,11 @@ ifdef NO_REGEX COMPAT_CFLAGS += -Icompat/regex COMPAT_OBJS += compat/regex/regex.o +else +ifdef USE_ENHANCED_BASIC_REGULAR_EXPRESSIONS + COMPAT_CFLAGS += -DUSE_ENHANCED_BASIC_REGULAR_EXPRESSIONS + COMPAT_OBJS += compat/regcomp_enhanced.o +endif endif ifdef NATIVE_CRLF BASIC_CFLAGS += -DNATIVE_CRLF @@ -2742,7 +2751,7 @@ '-DFALLBACK_RUNTIME_PREFIX="$(prefix_SQ)"' builtin/init-db.sp builtin/init-db.s builtin/init-db.o: GIT-PREFIX -builtin/init-db.sp builtin/init-db.s builtin/init-db.o: EXTRA_CPPFLAGS = \ +setup.sp setup.s setup.o: EXTRA_CPPFLAGS = \ -DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"' config.sp config.s config.o: GIT-PREFIX diff -Nru git-2.39.2/RelNotes git-2.39.5/RelNotes --- git-2.39.2/RelNotes 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/RelNotes 2024-05-31 00:35:55.000000000 +0000 @@ -1,7 +1,26 @@ -Git v2.39.2 Release Notes +Git v2.39.5 Release Notes ========================= -This release merges up the fixes that appear in v2.30.8, v2.31.7, -v2.32.6, v2.33.7, v2.34.7, v2.35.7, v2.36.5, v2.37.6 and v2.38.4 -to address the security issues CVE-2023-22490 and CVE-2023-23946; -see the release notes for these versions for details. +In preparing security fixes for four CVEs, we made overly aggressive +"defense in depth" changes that broke legitimate use cases like 'git +lfs' and 'git annex.' This release is to revert these misguided, if +well-intentioned, changes that were shipped in 2.39.4 and were not +direct security fixes. + +Jeff King (5): + send-email: drop FakeTerm hack + send-email: avoid creating more than one Term::ReadLine object + ci: drop mention of BREW_INSTALL_PACKAGES variable + ci: avoid bare "gcc" for osx-gcc job + ci: stop installing "gcc-13" for osx-gcc + +Johannes Schindelin (6): + hook: plug a new memory leak + init: use the correct path of the templates directory again + Revert "core.hooksPath: add some protection while cloning" + tests: verify that `clone -c core.hooksPath=/dev/null` works again + clone: drop the protections where hooks aren't run + Revert "Add a helper function to compare file contents" + +Junio C Hamano (1): + Revert "fsck: warn about symlink pointing inside a gitdir" diff -Nru git-2.39.2/add-interactive.c git-2.39.5/add-interactive.c --- git-2.39.2/add-interactive.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/add-interactive.c 2024-05-31 00:35:55.000000000 +0000 @@ -724,7 +724,7 @@ } static void revert_from_diff(struct diff_queue_struct *q, - struct diff_options *opt, void *data) + struct diff_options *opt, void *data UNUSED) { int i, add_flags = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE; diff -Nru git-2.39.2/apply.c git-2.39.5/apply.c --- git-2.39.2/apply.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/apply.c 2024-05-31 00:35:55.000000000 +0000 @@ -2913,7 +2913,7 @@ break; case ' ': if (plen && (ws_rule & WS_BLANK_AT_EOF) && - ws_blank_line(patch + 1, plen, ws_rule)) + ws_blank_line(patch + 1, plen)) is_blank_context = 1; /* fallthrough */ case '-': @@ -2942,7 +2942,7 @@ (first == '+' ? 0 : LINE_COMMON)); if (first == '+' && (ws_rule & WS_BLANK_AT_EOF) && - ws_blank_line(patch + 1, plen, ws_rule)) + ws_blank_line(patch + 1, plen)) added_blank_line = 1; break; case '@': case '\\': @@ -4576,7 +4576,7 @@ FILE *rej; char namebuf[PATH_MAX]; struct fragment *frag; - int cnt = 0; + int fd, cnt = 0; struct strbuf sb = STRBUF_INIT; for (cnt = 0, frag = patch->fragments; frag; frag = frag->next) { @@ -4616,7 +4616,17 @@ memcpy(namebuf, patch->new_name, cnt); memcpy(namebuf + cnt, ".rej", 5); - rej = fopen(namebuf, "w"); + fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666); + if (fd < 0) { + if (errno != EEXIST) + return error_errno(_("cannot open %s"), namebuf); + if (unlink(namebuf)) + return error_errno(_("cannot unlink '%s'"), namebuf); + fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666); + if (fd < 0) + return error_errno(_("cannot open %s"), namebuf); + } + rej = fdopen(fd, "w"); if (!rej) return error_errno(_("cannot open %s"), namebuf); diff -Nru git-2.39.2/blob.c git-2.39.5/blob.c --- git-2.39.2/blob.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/blob.c 2024-05-31 00:35:55.000000000 +0000 @@ -13,8 +13,7 @@ return object_as_type(obj, OBJ_BLOB, 0); } -int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size) +void parse_blob_buffer(struct blob *item) { item->object.parsed = 1; - return 0; } diff -Nru git-2.39.2/blob.h git-2.39.5/blob.h --- git-2.39.2/blob.h 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/blob.h 2024-05-31 00:35:55.000000000 +0000 @@ -11,8 +11,6 @@ struct blob *lookup_blob(struct repository *r, const struct object_id *oid); -int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size); - /** * Blobs do not contain references to other objects and do not have * structured data that needs parsing. However, code may use the @@ -21,5 +19,6 @@ * parse_blob_buffer() is used (by object.c) to flag that the object * has been read successfully from the database. **/ +void parse_blob_buffer(struct blob *item); #endif /* BLOB_H */ diff -Nru git-2.39.2/builtin/add.c git-2.39.5/builtin/add.c --- git-2.39.2/builtin/add.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/builtin/add.c 2024-05-31 00:35:55.000000000 +0000 @@ -88,7 +88,7 @@ } static void update_callback(struct diff_queue_struct *q, - struct diff_options *opt, void *cbdata) + struct diff_options *opt UNUSED, void *cbdata) { int i; struct update_callback_data *data = cbdata; diff -Nru git-2.39.2/builtin/am.c git-2.39.5/builtin/am.c --- git-2.39.2/builtin/am.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/builtin/am.c 2024-05-31 00:35:55.000000000 +0000 @@ -1476,6 +1476,7 @@ int res, opts_left; int force_apply = 0; int options = 0; + const char **apply_argv; if (init_apply_state(&apply_state, the_repository, NULL)) BUG("init_apply_state() failed"); @@ -1483,7 +1484,15 @@ strvec_push(&apply_opts, "apply"); strvec_pushv(&apply_opts, state->git_apply_opts.v); - opts_left = apply_parse_options(apply_opts.nr, apply_opts.v, + /* + * Build a copy that apply_parse_options() can rearrange. + * apply_opts.v keeps referencing the allocated strings for + * strvec_clear() to release. + */ + ALLOC_ARRAY(apply_argv, apply_opts.nr); + COPY_ARRAY(apply_argv, apply_opts.v, apply_opts.nr); + + opts_left = apply_parse_options(apply_opts.nr, apply_argv, &apply_state, &force_apply, &options, NULL); @@ -1513,6 +1522,7 @@ strvec_clear(&apply_paths); strvec_clear(&apply_opts); clear_apply_state(&apply_state); + free(apply_argv); if (res) return res; diff -Nru git-2.39.2/builtin/branch.c git-2.39.5/builtin/branch.c --- git-2.39.2/builtin/branch.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/builtin/branch.c 2024-05-31 00:35:55.000000000 +0000 @@ -581,13 +581,13 @@ strbuf_release(&logmsg); strbuf_addf(&oldsection, "branch.%s", interpreted_oldname); - strbuf_release(&oldref); strbuf_addf(&newsection, "branch.%s", interpreted_newname); - strbuf_release(&newref); if (!copy && git_config_rename_section(oldsection.buf, newsection.buf) < 0) die(_("Branch is renamed, but update of config-file failed")); - if (copy && strcmp(oldname, newname) && git_config_copy_section(oldsection.buf, newsection.buf) < 0) + if (copy && strcmp(interpreted_oldname, interpreted_newname) && git_config_copy_section(oldsection.buf, newsection.buf) < 0) die(_("Branch is copied, but update of config-file failed")); + strbuf_release(&oldref); + strbuf_release(&newref); strbuf_release(&oldsection); strbuf_release(&newsection); } diff -Nru git-2.39.2/builtin/bundle.c git-2.39.5/builtin/bundle.c --- git-2.39.2/builtin/bundle.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/builtin/bundle.c 2024-05-31 00:35:55.000000000 +0000 @@ -55,13 +55,12 @@ const char * const usagestr[], const struct option options[], char **bundle_file) { - int newargc; - newargc = parse_options(argc, argv, NULL, options, usagestr, + argc = parse_options(argc, argv, NULL, options, usagestr, PARSE_OPT_STOP_AT_NON_OPTION); - if (argc < 1) - usage_with_options(usagestr, options); + if (!argc) + usage_msg_opt(_("need a argument"), usagestr, options); *bundle_file = prefix_filename(prefix, argv[0]); - return newargc; + return argc; } static int cmd_bundle_create(int argc, const char **argv, const char *prefix) { diff -Nru git-2.39.2/builtin/clone.c git-2.39.5/builtin/clone.c --- git-2.39.2/builtin/clone.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/builtin/clone.c 2024-05-31 00:35:55.000000000 +0000 @@ -320,7 +320,20 @@ int src_len, dest_len; struct dir_iterator *iter; int iter_status; - struct strbuf realpath = STRBUF_INIT; + + /* + * Refuse copying directories by default which aren't owned by us. The + * code that performs either the copying or hardlinking is not prepared + * to handle various edge cases where an adversary may for example + * racily swap out files for symlinks. This can cause us to + * inadvertently use the wrong source file. + * + * Furthermore, even if we were prepared to handle such races safely, + * creating hardlinks across user boundaries is an inherently unsafe + * operation as the hardlinked files can be rewritten at will by the + * potentially-untrusted user. We thus refuse to do so by default. + */ + die_upon_dubious_ownership(NULL, NULL, src_repo); mkdir_if_missing(dest->buf, 0777); @@ -358,9 +371,27 @@ if (unlink(dest->buf) && errno != ENOENT) die_errno(_("failed to unlink '%s'"), dest->buf); if (!option_no_hardlinks) { - strbuf_realpath(&realpath, src->buf, 1); - if (!link(realpath.buf, dest->buf)) + if (!link(src->buf, dest->buf)) { + struct stat st; + + /* + * Sanity-check whether the created hardlink + * actually links to the expected file now. This + * catches time-of-check-time-of-use bugs in + * case the source file was meanwhile swapped. + */ + if (lstat(dest->buf, &st)) + die(_("hardlink cannot be checked at '%s'"), dest->buf); + if (st.st_mode != iter->st.st_mode || + st.st_ino != iter->st.st_ino || + st.st_dev != iter->st.st_dev || + st.st_size != iter->st.st_size || + st.st_uid != iter->st.st_uid || + st.st_gid != iter->st.st_gid) + die(_("hardlink different from source at '%s'"), dest->buf); + continue; + } if (option_local > 0) die_errno(_("failed to create link '%s'"), dest->buf); option_no_hardlinks = 1; @@ -373,8 +404,6 @@ strbuf_setlen(src, src_len); die(_("failed to iterate over '%s'"), src->buf); } - - strbuf_release(&realpath); } static void clone_local(const char *src_repo, const char *dest_repo) diff -Nru git-2.39.2/builtin/fast-export.c git-2.39.5/builtin/fast-export.c --- git-2.39.2/builtin/fast-export.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/builtin/fast-export.c 2024-05-31 00:35:55.000000000 +0000 @@ -409,7 +409,7 @@ } static void show_filemodify(struct diff_queue_struct *q, - struct diff_options *options, void *data) + struct diff_options *options UNUSED, void *data) { int i; struct string_list *changed = data; diff -Nru git-2.39.2/builtin/init-db.c git-2.39.5/builtin/init-db.c --- git-2.39.2/builtin/init-db.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/builtin/init-db.c 2024-05-31 00:35:55.000000000 +0000 @@ -11,10 +11,6 @@ #include "parse-options.h" #include "worktree.h" -#ifndef DEFAULT_GIT_TEMPLATE_DIR -#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates" -#endif - #ifdef NO_TRUSTABLE_FILEMODE #define TEST_FILEMODE 0 #else @@ -93,8 +89,9 @@ } } -static void copy_templates(const char *template_dir, const char *init_template_dir) +static void copy_templates(const char *option_template) { + const char *template_dir = get_template_dir(option_template); struct strbuf path = STRBUF_INIT; struct strbuf template_path = STRBUF_INIT; size_t template_len; @@ -103,16 +100,8 @@ DIR *dir; char *to_free = NULL; - if (!template_dir) - template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT); - if (!template_dir) - template_dir = init_template_dir; - if (!template_dir) - template_dir = to_free = system_path(DEFAULT_GIT_TEMPLATE_DIR); - if (!template_dir[0]) { - free(to_free); + if (!template_dir || !*template_dir) return; - } strbuf_addstr(&template_path, template_dir); strbuf_complete(&template_path, '/'); @@ -200,7 +189,6 @@ int reinit; int filemode; struct strbuf err = STRBUF_INIT; - const char *init_template_dir = NULL; const char *work_tree = get_git_work_tree(); /* @@ -212,9 +200,7 @@ * values (since we've just potentially changed what's available on * disk). */ - git_config_get_pathname("init.templatedir", &init_template_dir); - copy_templates(template_path, init_template_dir); - free((char *)init_template_dir); + copy_templates(template_path); git_config_clear(); reset_shared_repository(); git_config(git_default_config, NULL); diff -Nru git-2.39.2/builtin/ls-tree.c git-2.39.5/builtin/ls-tree.c --- git-2.39.2/builtin/ls-tree.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/builtin/ls-tree.c 2024-05-31 00:35:55.000000000 +0000 @@ -94,16 +94,16 @@ } else if (skip_prefix(start, "(objectname)", &p)) { strbuf_add_unique_abbrev(sb, data->oid, abbrev); } else if (skip_prefix(start, "(path)", &p)) { - const char *name = data->base->buf; + const char *name; const char *prefix = chomp_prefix ? ls_tree_prefix : NULL; - struct strbuf quoted = STRBUF_INIT; struct strbuf sbuf = STRBUF_INIT; + size_t baselen = data->base->len; + strbuf_addstr(data->base, data->pathname); name = relative_path(data->base->buf, prefix, &sbuf); - quote_c_style(name, "ed, NULL, 0); - strbuf_addbuf(sb, "ed); + quote_c_style(name, sb, NULL, 0); + strbuf_setlen(data->base, baselen); strbuf_release(&sbuf); - strbuf_release("ed); } else { errlen = (unsigned long)len; die(_("bad ls-tree format: %%%.*s"), errlen, start); @@ -144,7 +144,6 @@ static int show_tree_fmt(const struct object_id *oid, struct strbuf *base, const char *pathname, unsigned mode, void *context UNUSED) { - size_t baselen; int recurse = 0; struct strbuf sb = STRBUF_INIT; enum object_type type = object_type(mode); @@ -164,12 +163,10 @@ if (type == OBJ_BLOB && (ls_options & LS_TREE_ONLY)) return 0; - baselen = base->len; strbuf_expand(&sb, format, expand_show_tree, &data); strbuf_addch(&sb, line_termination); fwrite(sb.buf, sb.len, 1, stdout); strbuf_release(&sb); - strbuf_setlen(base, baselen); return recurse; } diff -Nru git-2.39.2/builtin/merge-tree.c git-2.39.5/builtin/merge-tree.c --- git-2.39.2/builtin/merge-tree.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/builtin/merge-tree.c 2024-05-31 00:35:55.000000000 +0000 @@ -98,7 +98,7 @@ return NULL; } -static int show_outf(void *priv_, mmbuffer_t *mb, int nbuf) +static int show_outf(void *priv UNUSED, mmbuffer_t *mb, int nbuf) { int i; for (i = 0; i < nbuf; i++) diff -Nru git-2.39.2/builtin/merge.c git-2.39.5/builtin/merge.c --- git-2.39.2/builtin/merge.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/builtin/merge.c 2024-05-31 00:35:55.000000000 +0000 @@ -776,7 +776,7 @@ } static void count_diff_files(struct diff_queue_struct *q, - struct diff_options *opt, void *data) + struct diff_options *opt UNUSED, void *data) { int *count = data; diff -Nru git-2.39.2/builtin/rerere.c git-2.39.5/builtin/rerere.c --- git-2.39.2/builtin/rerere.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/builtin/rerere.c 2024-05-31 00:35:55.000000000 +0000 @@ -14,7 +14,7 @@ NULL, }; -static int outf(void *dummy, mmbuffer_t *ptr, int nbuf) +static int outf(void *dummy UNUSED, mmbuffer_t *ptr, int nbuf) { int i; for (i = 0; i < nbuf; i++) diff -Nru git-2.39.2/builtin/reset.c git-2.39.5/builtin/reset.c --- git-2.39.2/builtin/reset.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/builtin/reset.c 2024-05-31 00:35:55.000000000 +0000 @@ -133,7 +133,8 @@ } static void update_index_from_diff(struct diff_queue_struct *q, - struct diff_options *opt, void *data) + struct diff_options *opt UNUSED, + void *data) { int i; int intent_to_add = *(int *)data; diff -Nru git-2.39.2/builtin/submodule--helper.c git-2.39.5/builtin/submodule--helper.c --- git-2.39.2/builtin/submodule--helper.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/builtin/submodule--helper.c 2024-05-31 00:35:55.000000000 +0000 @@ -294,6 +294,9 @@ struct child_process cp = CHILD_PROCESS_INIT; char *displaypath; + if (validate_submodule_path(path) < 0) + exit(128); + displaypath = get_submodule_displaypath(path, info->prefix); sub = submodule_from_path(the_repository, null_oid(), path); @@ -620,6 +623,9 @@ .free_removed_argv_elements = 1, }; + if (validate_submodule_path(path) < 0) + exit(128); + if (!submodule_from_path(the_repository, null_oid(), path)) die(_("no submodule mapping found in .gitmodules for path '%s'"), path); @@ -1043,7 +1049,7 @@ } static void submodule_summary_callback(struct diff_queue_struct *q, - struct diff_options *options, + struct diff_options *options UNUSED, void *data) { int i; @@ -1220,6 +1226,9 @@ if (!is_submodule_active(the_repository, path)) return; + if (validate_submodule_path(path) < 0) + exit(128); + sub = submodule_from_path(the_repository, null_oid(), path); if (sub && sub->url) { @@ -1360,6 +1369,9 @@ struct strbuf sb_config = STRBUF_INIT; char *sub_git_dir = xstrfmt("%s/.git", path); + if (validate_submodule_path(path) < 0) + exit(128); + sub = submodule_from_path(the_repository, null_oid(), path); if (!sub || !sub->name) @@ -1641,16 +1653,42 @@ return sm_gitdir; } +static int dir_contains_only_dotgit(const char *path) +{ + DIR *dir = opendir(path); + struct dirent *e; + int ret = 1; + + if (!dir) + return 0; + + e = readdir_skip_dot_and_dotdot(dir); + if (!e) + ret = 0; + else if (strcmp(DEFAULT_GIT_DIR_ENVIRONMENT, e->d_name) || + (e = readdir_skip_dot_and_dotdot(dir))) { + error("unexpected item '%s' in '%s'", e->d_name, path); + ret = 0; + } + + closedir(dir); + return ret; +} + static int clone_submodule(const struct module_clone_data *clone_data, struct string_list *reference) { char *p; char *sm_gitdir = clone_submodule_sm_gitdir(clone_data->name); char *sm_alternate = NULL, *error_strategy = NULL; + struct stat st; struct child_process cp = CHILD_PROCESS_INIT; const char *clone_data_path = clone_data->path; char *to_free = NULL; + if (validate_submodule_path(clone_data_path) < 0) + exit(128); + if (!is_absolute_path(clone_data->path)) clone_data_path = to_free = xstrfmt("%s/%s", get_git_work_tree(), clone_data->path); @@ -1660,6 +1698,10 @@ "git dir"), sm_gitdir); if (!file_exists(sm_gitdir)) { + if (clone_data->require_init && !stat(clone_data_path, &st) && + !is_empty_dir(clone_data_path)) + die(_("directory not empty: '%s'"), clone_data_path); + if (safe_create_leading_directories_const(sm_gitdir) < 0) die(_("could not create directory '%s'"), sm_gitdir); @@ -1704,10 +1746,18 @@ if(run_command(&cp)) die(_("clone of '%s' into submodule path '%s' failed"), clone_data->url, clone_data_path); + + if (clone_data->require_init && !stat(clone_data_path, &st) && + !dir_contains_only_dotgit(clone_data_path)) { + char *dot_git = xstrfmt("%s/.git", clone_data_path); + unlink(dot_git); + free(dot_git); + die(_("directory not empty: '%s'"), clone_data_path); + } } else { char *path; - if (clone_data->require_init && !access(clone_data_path, X_OK) && + if (clone_data->require_init && !stat(clone_data_path, &st) && !is_empty_dir(clone_data_path)) die(_("directory not empty: '%s'"), clone_data_path); if (safe_create_leading_directories_const(clone_data_path) < 0) @@ -1717,6 +1767,23 @@ free(path); } + /* + * We already performed this check at the beginning of this function, + * before cloning the objects. This tries to detect racy behavior e.g. + * in parallel clones, where another process could easily have made the + * gitdir nested _after_ it was created. + * + * To prevent further harm coming from this unintentionally-nested + * gitdir, let's disable it by deleting the `HEAD` file. + */ + if (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0) { + char *head = xstrfmt("%s/HEAD", sm_gitdir); + unlink(head); + free(head); + die(_("refusing to create/use '%s' in another submodule's " + "git dir"), sm_gitdir); + } + connect_work_tree_and_git_dir(clone_data_path, sm_gitdir, 0); p = git_pathdup_submodule(clone_data_path, "config"); @@ -2490,6 +2557,9 @@ { int ret; + if (validate_submodule_path(update_data->sm_path) < 0) + return -1; + ret = determine_submodule_update_strategy(the_repository, update_data->just_cloned, update_data->sm_path, @@ -2597,12 +2667,21 @@ for (i = 0; i < suc.update_clone_nr; i++) { struct update_clone_data ucd = suc.update_clone[i]; - int code; + int code = 128; oidcpy(&update_data->oid, &ucd.oid); update_data->just_cloned = ucd.just_cloned; update_data->sm_path = ucd.sub->path; + /* + * Verify that the submodule path does not contain any + * symlinks; if it does, it might have been tampered with. + * TODO: allow exempting it via + * `safe.submodule.path` or something + */ + if (validate_submodule_path(update_data->sm_path) < 0) + goto fail; + code = ensure_core_worktree(update_data->sm_path); if (code) goto fail; @@ -3309,6 +3388,9 @@ normalize_path_copy(add_data.sm_path, add_data.sm_path); strip_dir_trailing_slashes(add_data.sm_path); + if (validate_submodule_path(add_data.sm_path) < 0) + exit(128); + die_on_index_match(add_data.sm_path, force); die_on_repo_without_commits(add_data.sm_path); diff -Nru git-2.39.2/builtin/upload-pack.c git-2.39.5/builtin/upload-pack.c --- git-2.39.2/builtin/upload-pack.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/builtin/upload-pack.c 2024-05-31 00:35:55.000000000 +0000 @@ -35,6 +35,8 @@ packet_trace_identity("upload-pack"); read_replace_refs = 0; + /* TODO: This should use NO_LAZY_FETCH_ENVIRONMENT */ + xsetenv("GIT_NO_LAZY_FETCH", "1", 0); argc = parse_options(argc, argv, prefix, options, upload_pack_usage, 0); diff -Nru git-2.39.2/cache.h git-2.39.5/cache.h --- git-2.39.2/cache.h 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/cache.h 2024-05-31 00:35:55.000000000 +0000 @@ -606,6 +606,18 @@ #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES" +/* + * Check if a repository is safe and die if it is not, by verifying the + * ownership of the worktree (if any), the git directory, and the gitfile (if + * any). + * + * Exemptions for known-safe repositories can be added via `safe.directory` + * config settings; for non-bare repositories, their worktree needs to be + * added, for bare ones their git directory. + */ +void die_upon_dubious_ownership(const char *gitfile, const char *worktree, + const char *gitdir); + void setup_work_tree(void); /* * Find the commondir and gitdir of the repository that contains the current @@ -644,6 +656,7 @@ #define INIT_DB_QUIET 0x0001 #define INIT_DB_EXIST_OK 0x0002 +const char *get_template_dir(const char *option_template); int init_db(const char *git_dir, const char *real_git_dir, const char *template_dir, int hash_algo, const char *initial_branch, unsigned int flags); @@ -1865,7 +1878,7 @@ void ws_check_emit(const char *line, int len, unsigned ws_rule, FILE *stream, const char *set, const char *reset, const char *ws); char *whitespace_error_string(unsigned ws); void ws_fix_copy(struct strbuf *, const char *, int, unsigned, int *); -int ws_blank_line(const char *line, int len, unsigned ws_rule); +int ws_blank_line(const char *line, int len); #define ws_tab_width(rule) ((rule) & WS_TAB_WIDTH_MASK) /* ls-files */ diff -Nru git-2.39.2/ci/install-dependencies.sh git-2.39.5/ci/install-dependencies.sh --- git-2.39.2/ci/install-dependencies.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/ci/install-dependencies.sh 2024-05-31 00:35:55.000000000 +0000 @@ -34,8 +34,6 @@ export HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_CLEANUP=1 # Uncomment this if you want to run perf tests: # brew install gnu-time - test -z "$BREW_INSTALL_PACKAGES" || - brew install $BREW_INSTALL_PACKAGES brew link --force gettext mkdir -p $HOME/bin ( diff -Nru git-2.39.2/ci/lib.sh git-2.39.5/ci/lib.sh --- git-2.39.2/ci/lib.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/ci/lib.sh 2024-05-31 00:35:55.000000000 +0000 @@ -253,11 +253,9 @@ export PATH="$GIT_LFS_PATH:$P4_PATH:$PATH" ;; macos-*) - if [ "$jobname" = osx-gcc ] + MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=$(which python3)" + if [ "$jobname" != osx-gcc ] then - MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=$(which python3)" - else - MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=$(which python2)" MAKEFLAGS="$MAKEFLAGS NO_APPLE_COMMON_CRYPTO=NoThanks" MAKEFLAGS="$MAKEFLAGS NO_OPENSSL=NoThanks" fi @@ -281,9 +279,13 @@ ;; linux-asan) export SANITIZE=address + export NO_SVN_TESTS=LetsSaveSomeTime + MAKEFLAGS="$MAKEFLAGS NO_PYTHON=YepBecauseP4FlakesTooOften" ;; linux-ubsan) export SANITIZE=undefined + export NO_SVN_TESTS=LetsSaveSomeTime + MAKEFLAGS="$MAKEFLAGS NO_PYTHON=YepBecauseP4FlakesTooOften" ;; esac diff -Nru git-2.39.2/combine-diff.c git-2.39.5/combine-diff.c --- git-2.39.2/combine-diff.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/combine-diff.c 2024-05-31 00:35:55.000000000 +0000 @@ -372,7 +372,7 @@ static void consume_hunk(void *state_, long ob, long on, long nb, long nn, - const char *funcline, long funclen) + const char *func UNUSED, long funclen UNUSED) { struct combine_diff_state *state = state_; diff -Nru git-2.39.2/commit.c git-2.39.5/commit.c --- git-2.39.2/commit.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/commit.c 2024-05-31 00:35:55.000000000 +0000 @@ -701,8 +701,10 @@ if (!parents) return; - while ((parents = parents->next)) - commit_list_insert(parents->item, plist); + while ((parents = parents->next)) { + if (parents->item->object.flags & mark) + commit_list_insert(parents->item, plist); + } commit = commit->parents->item; } diff -Nru git-2.39.2/compat/fsmonitor/fsm-darwin-gcc.h git-2.39.5/compat/fsmonitor/fsm-darwin-gcc.h --- git-2.39.2/compat/fsmonitor/fsm-darwin-gcc.h 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/compat/fsmonitor/fsm-darwin-gcc.h 2024-05-31 00:35:55.000000000 +0000 @@ -80,9 +80,7 @@ void CFRunLoopStop(CFRunLoopRef run_loop); CFRunLoopRef CFRunLoopGetCurrent(void); extern CFStringRef kCFRunLoopDefaultMode; -void FSEventStreamScheduleWithRunLoop(FSEventStreamRef stream, - CFRunLoopRef run_loop, - CFStringRef run_loop_mode); +void FSEventStreamSetDispatchQueue(FSEventStreamRef stream, dispatch_queue_t q); unsigned char FSEventStreamStart(FSEventStreamRef stream); void FSEventStreamStop(FSEventStreamRef stream); void FSEventStreamInvalidate(FSEventStreamRef stream); diff -Nru git-2.39.2/compat/fsmonitor/fsm-listen-darwin.c git-2.39.5/compat/fsmonitor/fsm-listen-darwin.c --- git-2.39.2/compat/fsmonitor/fsm-listen-darwin.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/compat/fsmonitor/fsm-listen-darwin.c 2024-05-31 00:35:55.000000000 +0000 @@ -1,4 +1,5 @@ #ifndef __clang__ +#include #include "fsm-darwin-gcc.h" #else #include @@ -38,7 +39,9 @@ FSEventStreamRef stream; - CFRunLoopRef rl; + dispatch_queue_t dq; + pthread_cond_t dq_finished; + pthread_mutex_t dq_lock; enum shutdown_style { SHUTDOWN_EVENT = 0, @@ -379,8 +382,11 @@ fsmonitor_batch__free_list(batch); string_list_clear(&cookie_list, 0); + pthread_mutex_lock(&data->dq_lock); data->shutdown_style = FORCE_SHUTDOWN; - CFRunLoopStop(data->rl); + pthread_cond_broadcast(&data->dq_finished); + pthread_mutex_unlock(&data->dq_lock); + strbuf_release(&tmp); return; } @@ -441,10 +447,6 @@ if (!data->stream) goto failed; - /* - * `data->rl` needs to be set inside the listener thread. - */ - return 0; failed: @@ -471,6 +473,11 @@ FSEventStreamRelease(data->stream); } + if (data->dq) + dispatch_release(data->dq); + pthread_cond_destroy(&data->dq_finished); + pthread_mutex_destroy(&data->dq_lock); + FREE_AND_NULL(state->listen_data); } @@ -479,9 +486,11 @@ struct fsm_listen_data *data; data = state->listen_data; - data->shutdown_style = SHUTDOWN_EVENT; - CFRunLoopStop(data->rl); + pthread_mutex_lock(&data->dq_lock); + data->shutdown_style = SHUTDOWN_EVENT; + pthread_cond_broadcast(&data->dq_finished); + pthread_mutex_unlock(&data->dq_lock); } void fsm_listen__loop(struct fsmonitor_daemon_state *state) @@ -490,9 +499,11 @@ data = state->listen_data; - data->rl = CFRunLoopGetCurrent(); + pthread_mutex_init(&data->dq_lock, NULL); + pthread_cond_init(&data->dq_finished, NULL); + data->dq = dispatch_queue_create("FSMonitor", NULL); - FSEventStreamScheduleWithRunLoop(data->stream, data->rl, kCFRunLoopDefaultMode); + FSEventStreamSetDispatchQueue(data->stream, data->dq); data->stream_scheduled = 1; if (!FSEventStreamStart(data->stream)) { @@ -501,7 +512,9 @@ } data->stream_started = 1; - CFRunLoopRun(); + pthread_mutex_lock(&data->dq_lock); + pthread_cond_wait(&data->dq_finished, &data->dq_lock); + pthread_mutex_unlock(&data->dq_lock); switch (data->shutdown_style) { case FORCE_ERROR_STOP: diff -Nru git-2.39.2/compat/regcomp_enhanced.c git-2.39.5/compat/regcomp_enhanced.c --- git-2.39.2/compat/regcomp_enhanced.c 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/compat/regcomp_enhanced.c 2024-05-31 00:35:55.000000000 +0000 @@ -0,0 +1,9 @@ +#include "../git-compat-util.h" +#undef regcomp + +int git_regcomp(regex_t *preg, const char *pattern, int cflags) +{ + if (!(cflags & REG_EXTENDED)) + cflags |= REG_ENHANCED; + return regcomp(preg, pattern, cflags); +} diff -Nru git-2.39.2/config.c git-2.39.5/config.c --- git-2.39.2/config.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/config.c 2024-05-31 00:35:55.000000000 +0000 @@ -3487,9 +3487,10 @@ flags); } -static int section_name_match (const char *buf, const char *name) +static size_t section_name_match (const char *buf, const char *name) { - int i = 0, j = 0, dot = 0; + size_t i = 0, j = 0; + int dot = 0; if (buf[i] != '[') return 0; for (i = 1; buf[i] && buf[i] != ']'; i++) { @@ -3542,6 +3543,8 @@ return 1; } +#define GIT_CONFIG_MAX_LINE_LEN (512 * 1024) + /* if new_name == NULL, the section is removed instead */ static int git_config_copy_or_rename_section_in_file(const char *config_filename, const char *old_name, @@ -3551,11 +3554,12 @@ char *filename_buf = NULL; struct lock_file lock = LOCK_INIT; int out_fd; - char buf[1024]; + struct strbuf buf = STRBUF_INIT; FILE *config_file = NULL; struct stat st; struct strbuf copystr = STRBUF_INIT; struct config_store_data store; + uint32_t line_nr = 0; memset(&store, 0, sizeof(store)); @@ -3592,16 +3596,25 @@ goto out; } - while (fgets(buf, sizeof(buf), config_file)) { - unsigned i; - int length; + while (!strbuf_getwholeline(&buf, config_file, '\n')) { + size_t i, length; int is_section = 0; - char *output = buf; - for (i = 0; buf[i] && isspace(buf[i]); i++) + char *output = buf.buf; + + line_nr++; + + if (buf.len >= GIT_CONFIG_MAX_LINE_LEN) { + ret = error(_("refusing to work with overly long line " + "in '%s' on line %"PRIuMAX), + config_filename, (uintmax_t)line_nr); + goto out; + } + + for (i = 0; buf.buf[i] && isspace(buf.buf[i]); i++) ; /* do nothing */ - if (buf[i] == '[') { + if (buf.buf[i] == '[') { /* it's a section */ - int offset; + size_t offset; is_section = 1; /* @@ -3618,7 +3631,7 @@ strbuf_reset(©str); } - offset = section_name_match(&buf[i], old_name); + offset = section_name_match(&buf.buf[i], old_name); if (offset > 0) { ret++; if (!new_name) { @@ -3693,6 +3706,7 @@ out_no_rollback: free(filename_buf); config_store_data_clear(&store); + strbuf_release(&buf); return ret; } diff -Nru git-2.39.2/config.mak.uname git-2.39.5/config.mak.uname --- git-2.39.2/config.mak.uname 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/config.mak.uname 2024-05-31 00:35:55.000000000 +0000 @@ -147,6 +147,7 @@ FREAD_READS_DIRECTORIES = UnfortunatelyYes HAVE_NS_GET_EXECUTABLE_PATH = YesPlease CSPRNG_METHOD = arc4random + USE_ENHANCED_BASIC_REGULAR_EXPRESSIONS = YesPlease # Workaround for `gettext` being keg-only and not even being linked via # `brew link --force gettext`, should be obsolete as of diff -Nru git-2.39.2/configure git-2.39.5/configure --- git-2.39.2/configure 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/configure 2024-05-31 00:35:55.000000000 +0000 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for git 2.39.2. +# Generated by GNU Autoconf 2.71 for git 2.39.5. # # Report bugs to . # @@ -611,8 +611,8 @@ # Identity of this package. PACKAGE_NAME='git' PACKAGE_TARNAME='git' -PACKAGE_VERSION='2.39.2' -PACKAGE_STRING='git 2.39.2' +PACKAGE_VERSION='2.39.5' +PACKAGE_STRING='git 2.39.5' PACKAGE_BUGREPORT='git@vger.kernel.org' PACKAGE_URL='' @@ -1290,7 +1290,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures git 2.39.2 to adapt to many kinds of systems. +\`configure' configures git 2.39.5 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1352,7 +1352,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of git 2.39.2:";; + short | recursive ) echo "Configuration of git 2.39.5:";; esac cat <<\_ACEOF @@ -1495,7 +1495,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -git configure 2.39.2 +git configure 2.39.5 generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. @@ -1911,7 +1911,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by git $as_me 2.39.2, which was +It was created by git $as_me 2.39.5, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw @@ -8883,7 +8883,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by git $as_me 2.39.2, which was +This file was extended by git $as_me 2.39.5, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -8942,7 +8942,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -git config.status 2.39.2 +git config.status 2.39.5 configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" diff -Nru git-2.39.2/connect.c git-2.39.5/connect.c --- git-2.39.2/connect.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/connect.c 2024-05-31 00:35:55.000000000 +0000 @@ -66,7 +66,7 @@ } /* Checks if the server supports the capability 'c' */ -int server_supports_v2(const char *c, int die_on_error) +int server_supports_v2(const char *c) { int i; @@ -76,11 +76,13 @@ (!*out || *out == '=')) return 1; } + return 0; +} - if (die_on_error) +void ensure_server_supports_v2(const char *c) +{ + if (!server_supports_v2(c)) die(_("server doesn't support '%s'"), c); - - return 0; } int server_feature_v2(const char *c, const char **v) @@ -477,7 +479,7 @@ { const char *hash_name; - if (server_supports_v2("agent", 0)) + if (server_supports_v2("agent")) packet_write_fmt(fd_out, "agent=%s", git_user_agent_sanitized()); if (server_feature_v2("object-format", &hash_name)) { @@ -504,17 +506,18 @@ &transport_options->unborn_head_target : NULL; *list = NULL; - if (server_supports_v2("ls-refs", 1)) - packet_write_fmt(fd_out, "command=ls-refs\n"); + ensure_server_supports_v2("ls-refs"); + packet_write_fmt(fd_out, "command=ls-refs\n"); /* Send capabilities */ send_capabilities(fd_out, reader); - if (server_options && server_options->nr && - server_supports_v2("server-option", 1)) + if (server_options && server_options->nr) { + ensure_server_supports_v2("server-option"); for (i = 0; i < server_options->nr; i++) packet_write_fmt(fd_out, "server-option=%s", server_options->items[i].string); + } packet_delim(fd_out); /* When pushing we don't want to request the peeled tags */ diff -Nru git-2.39.2/connect.h git-2.39.5/connect.h --- git-2.39.2/connect.h 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/connect.h 2024-05-31 00:35:55.000000000 +0000 @@ -20,7 +20,8 @@ int server_supports_hash(const char *desired, int *feature_supported); const char *parse_feature_value(const char *feature_list, const char *feature, int *lenp, int *offset); -int server_supports_v2(const char *c, int die_on_error); +int server_supports_v2(const char *c); +void ensure_server_supports_v2(const char *c); int server_feature_v2(const char *c, const char **v); int server_supports_feature(const char *c, const char *feature, int die_on_error); diff -Nru git-2.39.2/debian/changelog git-2.39.5/debian/changelog --- git-2.39.2/debian/changelog 2023-02-28 09:25:32.000000000 +0000 +++ git-2.39.5/debian/changelog 2024-06-16 17:37:10.000000000 +0000 @@ -1,3 +1,13 @@ +git (1:2.39.5-0+deb12u1) bookworm-security; urgency=medium + + * new upstream point release (see RelNotes/2.39.3.txt, + RelNotes/2.39.4.txt, RelNotes/2.39.5.txt). Addresses + CVE-2023-25652, CVE-2023-25815, CVE-2023-29007, CVE-2024-32002, + CVE-2024-32004, CVE-2024-32020, CVE-2023-32021 (closes: + #1071160). + + -- Jonathan Nieder Sun, 16 Jun 2024 17:37:10 +0000 + git (1:2.39.2-1.1) unstable; urgency=medium * Non-maintainer upload (only changes to git-doc). diff -Nru git-2.39.2/debian/changelog.upstream git-2.39.5/debian/changelog.upstream --- git-2.39.2/debian/changelog.upstream 2023-02-28 09:25:32.000000000 +0000 +++ git-2.39.5/debian/changelog.upstream 2024-06-16 17:35:20.000000000 +0000 @@ -1,3 +1,232 @@ +Version v2.39.5; changes since v2.39.4: +--------------------------------------- + +Jeff King (5): + send-email: drop FakeTerm hack + send-email: avoid creating more than one Term::ReadLine object + ci: drop mention of BREW_INSTALL_PACKAGES variable + ci: avoid bare "gcc" for osx-gcc job + ci: stop installing "gcc-13" for osx-gcc + +Johannes Schindelin (6): + hook: plug a new memory leak + init: use the correct path of the templates directory again + Revert "core.hooksPath: add some protection while cloning" + tests: verify that `clone -c core.hooksPath=/dev/null` works again + clone: drop the protections where hooks aren't run + Revert "Add a helper function to compare file contents" + +Junio C Hamano (2): + Revert "fsck: warn about symlink pointing inside a gitdir" + Git 2.39.5 + + +Version v2.39.4; changes since v2.39.3: +--------------------------------------- + +Filip Hejsek (4): + t0411: add tests for cloning from partial repo + has_dir_name(): do not get confused by characters < '/' + t7423: add tests for symlinked submodule directories + clone: prevent clashing git dirs when cloning submodule in parallel + +Jeff Hostetler (1): + fsmonitor: eliminate call to deprecated FSEventStream function + +Jeff King (29): + t/lib-httpd: bump required apache version to 2.2 + t/lib-httpd: bump required apache version to 2.4 + t/lib-httpd: drop SSLMutex config + t/lib-httpd: increase ssl key size to 2048 bits + t5541: run "used receive-pack service" test earlier + t5541: stop marking "used receive-pack service" test as v0 only + t5541: simplify and move "no empty path components" test + t5551: drop redundant grep for Accept-Language + t5551: lower-case headers in expected curl trace + t5551: handle HTTP/2 when checking curl trace + t5551: stop forcing clone to run with v0 protocol + t5551: handle v2 protocol when checking curl trace + t5551: handle v2 protocol in upload-pack service test + t5551: simplify expected cookie file + t5551: handle v2 protocol in cookie test + t5551: drop curl trace lines without headers + t/lib-httpd: respect $HTTPD_PROTO in expect_askpass() + t/lib-httpd: enable HTTP/2 "h2" protocol, not just h2c + t5559: fix test failures with LIB_HTTPD_SSL + t5559: make SSL/TLS the default + http: handle both "h2" and "h2h3" in curl info lines + http: factor out matching of curl http/2 trace lines + http: update curl http/2 info matching for curl 8.3.0 + http: reset POSTFIELDSIZE when clearing curl handle + INSTALL: bump libcurl version to 7.21.3 + remote-curl: add Transfer-Encoding header only for older curl + test-lib: ignore uninteresting LSan output + upload-pack: disable lazy-fetching by default + docs: document security issues around untrusted .git dirs + +Johannes Schindelin (19): + ci: upgrade to using macos-13 + ci(linux-asan/linux-ubsan): let's save some time + ci: bump remaining outdated Actions versions + ci(linux32): add a note about Actions that must not be updated + fetch/clone: detect dubious ownership of local repositories + submodules: submodule paths must not contain symlinks + clone_submodule: avoid using `access()` on directories + submodule: require the submodule path to contain directories only + t5510: verify that D/F confusion cannot lead to an RCE + entry: report more colliding paths + clone: when symbolic links collide with directories, keep the latter + find_hook(): refactor the `STRIP_EXTENSION` logic + init: refactor the template directory discovery into its own function + Add a helper function to compare file contents + clone: prevent hooks from running during a clone + init.templateDir: consider this config setting protected + core.hooksPath: add some protection while cloning + fsck: warn about symlink pointing inside a gitdir + Git 2.39.4 + +Junio C Hamano (2): + GitHub Actions: update to checkout@v4 + GitHub Actions: update to github-script@v7 + +Patrick Steinhardt (4): + builtin/clone: stop resolving symlinks when copying files + builtin/clone: abort when hardlinked source and target file differ + setup.c: introduce `die_upon_dubious_ownership()` + builtin/clone: refuse local clones of unsafe repositories + + +Version v2.39.3; changes since v2.39.2: +--------------------------------------- + +Chris. Webster (3): + ci (check-whitespace): suggest fixes for errors + ci (check-whitespace): add links to job output + ci (check-whitespace): move to actions/checkout@v3 + +Derrick Stolee (1): + ci: update 'static-analysis' to Ubuntu 22.04 + +Eric Sunshine (1): + githooks: discuss Git operations in foreign repositories + +Jeff King (25): + git-compat-util: avoid redefining system function names + git-compat-util: undefine system names before redeclaring them + server_supports_v2(): use a separate function for die_on_error + ls-refs: use repository parameter to iterate refs + blob: drop unused parts of parse_blob_buffer() + list-objects: drop process_gitlink() function + ws: drop unused parameter from ws_blank_line() + xdiff: drop unused parameter in def_ff() + xdiff: mark unused parameter in xdl_call_hunk_func() + diff: mark unused parameters in callbacks + list-objects-filter: mark unused parameters in virtual functions + userdiff: mark unused parameter in internal callback + diff: use filespec path to set up tempfiles for ext-diff + diff: clean up external-diff argv setup + diff: drop "name" parameter from prepare_temp_file() + http-push: prefer CURLOPT_UPLOAD to CURLOPT_PUT + http: prefer CURLOPT_SEEKFUNCTION to CURLOPT_IOCTLFUNCTION + http: support CURLOPT_PROTOCOLS_STR + http-push: prefer CURLOPT_UPLOAD to CURLOPT_PUT + http: prefer CURLOPT_SEEKFUNCTION to CURLOPT_IOCTLFUNCTION + range-diff: drop useless "offset" variable from read_patches() + http: support CURLOPT_PROTOCOLS_STR + range-diff: handle unterminated lines in read_patches() + range-diff: use ssize_t for parsed "len" in read_patches() + Makefile: force -O0 when compiling with SANITIZE=leak + +Jiang Xin (4): + github-actions: run gcc-8 on ubuntu-20.04 image + ci: remove the pipe after "p4 -V" to catch errors + ci: use the same version of p4 on both Linux and macOS + ci: install python on ubuntu + +Johannes Schindelin (22): + ci: only run win+VS build & tests in Git for Windows' fork + compat/win32/syslog: fix use-after-realloc + nedmalloc: avoid new compile error + t0033: GETTEXT_POISON fix + t0003: GETTEXT_POISON fix, part 1 + t0003: GETTEXT_POISON fix, conclusion + t5619: GETTEXT_POISON fix + t5604: GETTEXT_POISON fix, part 1 + t5604: GETTEXT_POISON fix, conclusion + clone.c: avoid "exceeds maximum object size" error with GCC v12.x + apply --reject: overwrite existing `.rej` symlink if it exists + gettext: avoid using gettext if the locale dir is not present + tests: avoid using `test_i18ncmp` + Git 2.31.8 + Git 2.32.7 + Git 2.33.8 + Git 2.34.8 + Git 2.35.8 + Git 2.36.6 + Git 2.37.7 + Git 2.38.5 + Git 2.39.3 + +Johannes Sixt (1): + t3920: don't ignore errors of more than one command with `|| true` + +Junio C Hamano (4): + branch: document `-f` and linked worktree behaviour + checkout: document -b/-B to highlight the differences from "git branch" + Prepare for 2.39.3 just in case + http.c: clear the 'finished' member once we are done with it + +Lars Kellogg-Stedman (1): + line-range: fix infinite loop bug with '$' regex + +Patrick Steinhardt (1): + refs: fix corruption by not correctly syncing packed-refs to disk + +Philippe Blain (5): + git-cherry-pick.txt: do not use 'ORIG_HEAD' in example + git-reset.txt: mention 'ORIG_HEAD' in the Description + git-merge.txt: mention 'ORIG_HEAD' in the Description + revisions.txt: be explicit about commands writing 'ORIG_HEAD' + git-rebase.txt: add a note about 'ORIG_HEAD' being overwritten + +RenĂ© Scharfe (10): + t4205: don't exit test script on failure + list-objects-filter: plug pattern_list leak + t3920: support CR-eating grep + reflog: clear leftovers in reflog_expiry_cleanup() + commit: skip already cleared parents in clear_commit_marks_1() + am: don't pass strvec to apply_parse_options() + object-file: inline write_buffer() + use enhanced basic regular expressions on macOS + ls-tree: fix expansion of repeated %(path) + ls-tree: remove dead store and strbuf for quote_c_style() + +RubĂ©n Justo (1): + branch: force-copy a branch to itself via @{-1} is a no-op + +Seija Kijin (1): + git: remove duplicate includes + +Taylor Blau (6): + ci: avoid unnecessary builds + t1300: demonstrate failure when renaming sections with long lines + config: avoid fixed-sized buffer when renaming/deleting a section + config.c: avoid integer truncation in `copy_or_rename_section_in_file()` + config.c: disallow overly-long lines in `copy_or_rename_section_in_file()` + Git 2.30.9 + +William Sprent (1): + dir: check for single file cone patterns + +Ævar ArnfjörĂ° Bjarmason (6): + t5314: check exit code of "git" + t7600: don't ignore "rev-parse" exit code in helper + t4023: fix ignored exit codes of git + bundle: don't segfault on "git bundle " + builtin/bundle.c: remove superfluous "newargc" variable + bundle : have usage_msg_opt() note the missing "" + + Version v2.39.2; changes since v2.39.1: --------------------------------------- diff -Nru git-2.39.2/debian/versions.upstream git-2.39.5/debian/versions.upstream --- git-2.39.2/debian/versions.upstream 2023-02-28 09:25:32.000000000 +0000 +++ git-2.39.5/debian/versions.upstream 2024-06-16 17:34:39.000000000 +0000 @@ -821,3 +821,6 @@ v2.39.0 v2.39.1 v2.39.2 +v2.39.3 +v2.39.4 +v2.39.5 diff -Nru git-2.39.2/diff-lib.c git-2.39.5/diff-lib.c --- git-2.39.2/diff-lib.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/diff-lib.c 2024-05-31 00:35:55.000000000 +0000 @@ -673,7 +673,7 @@ return (has_changes != 0); } -static struct strbuf *idiff_prefix_cb(struct diff_options *opt, void *data) +static struct strbuf *idiff_prefix_cb(struct diff_options *opt UNUSED, void *data) { return data; } diff -Nru git-2.39.2/diff.c git-2.39.5/diff.c --- git-2.39.2/diff.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/diff.c 2024-05-31 00:35:55.000000000 +0000 @@ -604,7 +604,7 @@ return one->size; } -static int count_trailing_blank(mmfile_t *mf, unsigned ws_rule) +static int count_trailing_blank(mmfile_t *mf) { char *ptr = mf->ptr; long size = mf->size; @@ -622,7 +622,7 @@ for (prev_eol = ptr; mf->ptr <= prev_eol; prev_eol--) if (*prev_eol == '\n') break; - if (!ws_blank_line(prev_eol + 1, ptr - prev_eol, ws_rule)) + if (!ws_blank_line(prev_eol + 1, ptr - prev_eol)) break; cnt++; ptr = prev_eol - 1; @@ -634,9 +634,8 @@ struct emit_callback *ecbdata) { int l1, l2, at; - unsigned ws_rule = ecbdata->ws_rule; - l1 = count_trailing_blank(mf1, ws_rule); - l2 = count_trailing_blank(mf2, ws_rule); + l1 = count_trailing_blank(mf1); + l2 = count_trailing_blank(mf2); if (l2 <= l1) { ecbdata->blank_at_eof_in_preimage = 0; ecbdata->blank_at_eof_in_postimage = 0; @@ -1583,7 +1582,7 @@ ecbdata->blank_at_eof_in_preimage <= ecbdata->lno_in_preimage && ecbdata->blank_at_eof_in_postimage <= ecbdata->lno_in_postimage)) return 0; - return ws_blank_line(line, len, ecbdata->ws_rule); + return ws_blank_line(line, len); } static void emit_add_line(struct emit_callback *ecbdata, @@ -1955,7 +1954,7 @@ static void fn_out_diff_words_aux(void *priv, long minus_first, long minus_len, long plus_first, long plus_len, - const char *func, long funclen) + const char *func UNUSED, long funclen UNUSED) { struct diff_words_data *diff_words = priv; struct diff_words_style *style = diff_words->style; @@ -3185,8 +3184,9 @@ } static void checkdiff_consume_hunk(void *priv, - long ob, long on, long nb, long nn, - const char *func, long funclen) + long ob UNUSED, long on UNUSED, + long nb, long nn UNUSED, + const char *func UNUSED, long funclen UNUSED) { struct checkdiff_t *data = priv; @@ -4213,7 +4213,6 @@ } static struct diff_tempfile *prepare_temp_file(struct repository *r, - const char *name, struct diff_filespec *one) { struct diff_tempfile *temp = claim_diff_tempfile(); @@ -4231,18 +4230,18 @@ if (!S_ISGITLINK(one->mode) && (!one->oid_valid || - reuse_worktree_file(r->index, name, &one->oid, 1))) { + reuse_worktree_file(r->index, one->path, &one->oid, 1))) { struct stat st; - if (lstat(name, &st) < 0) { + if (lstat(one->path, &st) < 0) { if (errno == ENOENT) goto not_a_valid_file; - die_errno("stat(%s)", name); + die_errno("stat(%s)", one->path); } if (S_ISLNK(st.st_mode)) { struct strbuf sb = STRBUF_INIT; - if (strbuf_readlink(&sb, name, st.st_size) < 0) - die_errno("readlink(%s)", name); - prep_temp_blob(r->index, name, temp, sb.buf, sb.len, + if (strbuf_readlink(&sb, one->path, st.st_size) < 0) + die_errno("readlink(%s)", one->path); + prep_temp_blob(r->index, one->path, temp, sb.buf, sb.len, (one->oid_valid ? &one->oid : null_oid()), (one->oid_valid ? @@ -4251,7 +4250,7 @@ } else { /* we can borrow from the file in the work tree */ - temp->name = name; + temp->name = one->path; if (!one->oid_valid) oid_to_hex_r(temp->hex, null_oid()); else @@ -4269,7 +4268,7 @@ else { if (diff_populate_filespec(r, one, NULL)) die("cannot read data blob for %s", one->path); - prep_temp_blob(r->index, name, temp, + prep_temp_blob(r->index, one->path, temp, one->data, one->size, &one->oid, one->mode); } @@ -4278,10 +4277,9 @@ static void add_external_diff_name(struct repository *r, struct strvec *argv, - const char *name, struct diff_filespec *df) { - struct diff_tempfile *temp = prepare_temp_file(r, name, df); + struct diff_tempfile *temp = prepare_temp_file(r, df); strvec_push(argv, temp->name); strvec_push(argv, temp->hex); strvec_push(argv, temp->mode); @@ -4308,11 +4306,9 @@ strvec_push(&cmd.args, name); if (one && two) { - add_external_diff_name(o->repo, &cmd.args, name, one); - if (!other) - add_external_diff_name(o->repo, &cmd.args, name, two); - else { - add_external_diff_name(o->repo, &cmd.args, other, two); + add_external_diff_name(o->repo, &cmd.args, one); + add_external_diff_name(o->repo, &cmd.args, two); + if (other) { strvec_push(&cmd.args, other); strvec_push(&cmd.args, xfrm_msg); } @@ -7037,7 +7033,7 @@ struct strbuf buf = STRBUF_INIT; int err = 0; - temp = prepare_temp_file(r, spec->path, spec); + temp = prepare_temp_file(r, spec); strvec_push(&child.args, pgm); strvec_push(&child.args, temp->name); diff -Nru git-2.39.2/dir.c git-2.39.5/dir.c --- git-2.39.2/dir.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/dir.c 2024-05-31 00:35:55.000000000 +0000 @@ -88,6 +88,18 @@ return ignore_case ? strncasecmp(a, b, count) : strncmp(a, b, count); } +int paths_collide(const char *a, const char *b) +{ + size_t len_a = strlen(a), len_b = strlen(b); + + if (len_a == len_b) + return fspatheq(a, b); + + if (len_a < len_b) + return is_dir_sep(b[len_a]) && !fspathncmp(a, b, len_a); + return is_dir_sep(a[len_b]) && !fspathncmp(a, b, len_b); +} + unsigned int fspathhash(const char *str) { return ignore_case ? strihash(str) : strhash(str); @@ -730,6 +742,13 @@ /* Not a cone pattern. */ warning(_("unrecognized pattern: '%s'"), given->pattern); goto clear_hashmaps; + } + + if (!(given->flags & PATTERN_FLAG_MUSTBEDIR) && + strcmp(given->pattern, "/*")) { + /* Not a cone pattern. */ + warning(_("unrecognized pattern: '%s'"), given->pattern); + goto clear_hashmaps; } prev = given->pattern; diff -Nru git-2.39.2/dir.h git-2.39.5/dir.h --- git-2.39.2/dir.h 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/dir.h 2024-05-31 00:35:55.000000000 +0000 @@ -520,6 +520,13 @@ unsigned int fspathhash(const char *str); /* + * Reports whether paths collide. This may be because the paths differ only in + * case on a case-sensitive filesystem, or that one path refers to a symlink + * that collides with one of the parent directories of the other. + */ +int paths_collide(const char *a, const char *b); + +/* * The prefix part of pattern must not contains wildcards. */ struct pathspec_item; diff -Nru git-2.39.2/entry.c git-2.39.5/entry.c --- git-2.39.2/entry.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/entry.c 2024-05-31 00:35:55.000000000 +0000 @@ -454,7 +454,7 @@ continue; if ((trust_ino && !match_stat_data(&dup->ce_stat_data, st)) || - (!trust_ino && !fspathcmp(ce->name, dup->name))) { + paths_collide(ce->name, dup->name)) { dup->ce_flags |= CE_MATCHED; break; } @@ -541,6 +541,20 @@ /* If it is a gitlink, leave it alone! */ if (S_ISGITLINK(ce->ce_mode)) return 0; + /* + * We must avoid replacing submodules' leading + * directories with symbolic links, lest recursive + * clones can write into arbitrary locations. + * + * Technically, this logic is not limited + * to recursive clones, or for that matter to + * submodules' paths colliding with symbolic links' + * paths. Yet it strikes a balance in favor of + * simplicity, and if paths are colliding, we might + * just as well keep the directories during a clone. + */ + if (state->clone && S_ISLNK(ce->ce_mode)) + return 0; remove_subtree(&path); } else if (unlink(path.buf)) return error_errno("unable to unlink old '%s'", path.buf); diff -Nru git-2.39.2/fetch-pack.c git-2.39.5/fetch-pack.c --- git-2.39.2/fetch-pack.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/fetch-pack.c 2024-05-31 00:35:55.000000000 +0000 @@ -1317,15 +1317,15 @@ { const char *hash_name; - if (server_supports_v2("fetch", 1)) - packet_buf_write(req_buf, "command=fetch"); - if (server_supports_v2("agent", 0)) + ensure_server_supports_v2("fetch"); + packet_buf_write(req_buf, "command=fetch"); + if (server_supports_v2("agent")) packet_buf_write(req_buf, "agent=%s", git_user_agent_sanitized()); - if (advertise_sid && server_supports_v2("session-id", 0)) + if (advertise_sid && server_supports_v2("session-id")) packet_buf_write(req_buf, "session-id=%s", trace2_session_id()); - if (server_options && server_options->nr && - server_supports_v2("server-option", 1)) { + if (server_options && server_options->nr) { int i; + ensure_server_supports_v2("server-option"); for (i = 0; i < server_options->nr; i++) packet_buf_write(req_buf, "server-option=%s", server_options->items[i].string); diff -Nru git-2.39.2/gettext.c git-2.39.5/gettext.c --- git-2.39.2/gettext.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/gettext.c 2024-05-31 00:35:55.000000000 +0000 @@ -100,6 +100,8 @@ setlocale(LC_CTYPE, "C"); } +int git_gettext_enabled = 0; + void git_setup_gettext(void) { const char *podir = getenv(GIT_TEXT_DOMAIN_DIR_ENVIRONMENT); @@ -119,6 +121,8 @@ init_gettext_charset("git"); textdomain("git"); + git_gettext_enabled = 1; + free(p); } diff -Nru git-2.39.2/gettext.h git-2.39.5/gettext.h --- git-2.39.2/gettext.h 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/gettext.h 2024-05-31 00:35:55.000000000 +0000 @@ -29,9 +29,11 @@ #define FORMAT_PRESERVING(n) __attribute__((format_arg(n))) #ifndef NO_GETTEXT +extern int git_gettext_enabled; void git_setup_gettext(void); int gettext_width(const char *s); #else +#define git_gettext_enabled (0) static inline void git_setup_gettext(void) { } @@ -45,12 +47,16 @@ { if (!*msgid) return ""; + if (!git_gettext_enabled) + return msgid; return gettext(msgid); } static inline FORMAT_PRESERVING(1) FORMAT_PRESERVING(2) const char *Q_(const char *msgid, const char *plu, unsigned long n) { + if (!git_gettext_enabled) + return n == 1 ? msgid : plu; return ngettext(msgid, plu, n); } diff -Nru git-2.39.2/git-compat-util.h git-2.39.5/git-compat-util.h --- git-2.39.2/git-compat-util.h 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/git-compat-util.h 2024-05-31 00:35:55.000000000 +0000 @@ -341,11 +341,13 @@ #endif #ifdef NO_SETITIMER -static inline int setitimer(int which UNUSED, - const struct itimerval *value UNUSED, - struct itimerval *newvalue UNUSED) { +static inline int git_setitimer(int which UNUSED, + const struct itimerval *value UNUSED, + struct itimerval *newvalue UNUSED) { return 0; /* pretend success */ } +#undef setitimer +#define setitimer(which,value,ovalue) git_setitimer(which,value,ovalue) #endif #ifndef NO_LIBGEN_H @@ -1344,6 +1346,11 @@ return regexec(preg, buf, nmatch, pmatch, eflags | REG_STARTEND); } +#ifdef USE_ENHANCED_BASIC_REGULAR_EXPRESSIONS +int git_regcomp(regex_t *preg, const char *pattern, int cflags); +#define regcomp git_regcomp +#endif + #ifndef DIR_HAS_BSD_GROUP_SEMANTICS # define FORCE_DIR_SET_GID S_ISGID #else @@ -1479,14 +1486,19 @@ #endif #ifndef _POSIX_THREAD_SAFE_FUNCTIONS -static inline void flockfile(FILE *fh UNUSED) +static inline void git_flockfile(FILE *fh UNUSED) { ; /* nothing */ } -static inline void funlockfile(FILE *fh UNUSED) +static inline void git_funlockfile(FILE *fh UNUSED) { ; /* nothing */ } +#undef flockfile +#undef funlockfile +#undef getc_unlocked +#define flockfile(fh) git_flockfile(fh) +#define funlockfile(fh) git_funlockfile(fh) #define getc_unlocked(fh) getc(fh) #endif diff -Nru git-2.39.2/git-curl-compat.h git-2.39.5/git-curl-compat.h --- git-2.39.2/git-curl-compat.h 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/git-curl-compat.h 2024-05-31 00:35:55.000000000 +0000 @@ -127,6 +127,15 @@ #endif /** + * Versions before curl 7.66.0 (September 2019) required manually setting the + * transfer-encoding for a streaming POST; after that this is handled + * automatically. + */ +#if LIBCURL_VERSION_NUM < 0x074200 +#define GIT_CURL_NEED_TRANSFER_ENCODING_HEADER +#endif + +/** * CURLOPT_PROTOCOLS_STR and CURLOPT_REDIR_PROTOCOLS_STR were added in 7.85.0, * released in August 2022. */ diff -Nru git-2.39.2/git-send-email.perl git-2.39.5/git-send-email.perl --- git-2.39.2/git-send-email.perl 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/git-send-email.perl 2024-05-31 00:35:55.000000000 +0000 @@ -26,18 +26,6 @@ Getopt::Long::Configure qw/ pass_through /; -package FakeTerm; -sub new { - my ($class, $reason) = @_; - return bless \$reason, shift; -} -sub readline { - my $self = shift; - die "Cannot use readline on FakeTerm: $$self"; -} -package main; - - sub usage { print <] @@ -929,17 +917,19 @@ do_edit(@files); } -sub term { - my $term = eval { +{ + # Only instantiate one $term per program run, since some + # Term::ReadLine providers refuse to create a second instance. + my $term; + sub term { require Term::ReadLine; - $ENV{"GIT_SEND_EMAIL_NOTTY"} - ? Term::ReadLine->new('git-send-email', \*STDIN, \*STDOUT) - : Term::ReadLine->new('git-send-email'); - }; - if ($@) { - $term = FakeTerm->new("$@: going non-interactive"); + if (!defined $term) { + $term = $ENV{"GIT_SEND_EMAIL_NOTTY"} + ? Term::ReadLine->new('git-send-email', \*STDIN, \*STDOUT) + : Term::ReadLine->new('git-send-email'); + } + return $term; } - return $term; } sub ask { diff -Nru git-2.39.2/hook.c git-2.39.5/hook.c --- git-2.39.2/hook.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/hook.c 2024-05-31 00:35:55.000000000 +0000 @@ -7,20 +7,24 @@ { static struct strbuf path = STRBUF_INIT; + int found_hook; + strbuf_reset(&path); strbuf_git_path(&path, "hooks/%s", name); - if (access(path.buf, X_OK) < 0) { + found_hook = access(path.buf, X_OK) >= 0; +#ifdef STRIP_EXTENSION + if (!found_hook) { int err = errno; -#ifdef STRIP_EXTENSION strbuf_addstr(&path, STRIP_EXTENSION); - if (access(path.buf, X_OK) >= 0) - return path.buf; - if (errno == EACCES) - err = errno; + found_hook = access(path.buf, X_OK) >= 0; + if (!found_hook) + errno = err; + } #endif - if (err == EACCES && advice_enabled(ADVICE_IGNORED_HOOK)) { + if (!found_hook) { + if (errno == EACCES && advice_enabled(ADVICE_IGNORED_HOOK)) { static struct string_list advise_given = STRING_LIST_INIT_DUP; if (!string_list_lookup(&advise_given, name)) { diff -Nru git-2.39.2/http.c git-2.39.5/http.c --- git-2.39.2/http.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/http.c 2024-05-31 00:35:55.000000000 +0000 @@ -618,17 +618,43 @@ return ret; } +static int match_curl_h2_trace(const char *line, const char **out) +{ + const char *p; + + /* + * curl prior to 8.1.0 gives us: + * + * h2h3 [: ] + * + * Starting in 8.1.0, the first token became just "h2". + */ + if (skip_iprefix(line, "h2h3 [", out) || + skip_iprefix(line, "h2 [", out)) + return 1; + + /* + * curl 8.3.0 uses: + * [HTTP/2] [] [: ] + * where is numeric. + */ + if (skip_iprefix(line, "[HTTP/2] [", &p)) { + while (isdigit(*p)) + p++; + if (skip_prefix(p, "] [", out)) + return 1; + } + + return 0; +} + /* Redact headers in info */ static void redact_sensitive_info_header(struct strbuf *header) { const char *sensitive_header; - /* - * curl's h2h3 prints headers in info, e.g.: - * h2h3 [: ] - */ if (trace_curl_redact && - skip_iprefix(header->buf, "h2h3 [", &sensitive_header)) { + match_curl_h2_trace(header->buf, &sensitive_header)) { if (redact_sensitive_header(header, sensitive_header - header->buf)) { /* redaction ate our closing bracket */ strbuf_addch(header, ']'); @@ -1300,6 +1326,7 @@ curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, NULL); curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, NULL); curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, NULL); + curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, -1L); curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0); curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1); curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1); diff -Nru git-2.39.2/line-range.c git-2.39.5/line-range.c --- git-2.39.2/line-range.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/line-range.c 2024-05-31 00:35:55.000000000 +0000 @@ -135,7 +135,7 @@ { int reg_error; regmatch_t match[1]; - while (1) { + while (*start) { const char *bol, *eol; reg_error = regexec(regexp, start, 1, match, 0); if (reg_error == REG_NOMATCH) @@ -148,8 +148,8 @@ /* determine extent of line matched */ bol = start+match[0].rm_so; eol = start+match[0].rm_eo; - while (bol > start && *bol != '\n') - bol--; + while (bol > start && *--bol != '\n') + ; /* nothing */ if (*bol == '\n') bol++; while (*eol && *eol != '\n') @@ -161,6 +161,7 @@ return bol; start = eol; } + return NULL; } static const char *parse_range_funcname( diff -Nru git-2.39.2/list-objects-filter.c git-2.39.5/list-objects-filter.c --- git-2.39.2/list-objects-filter.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/list-objects-filter.c 2024-05-31 00:35:55.000000000 +0000 @@ -70,13 +70,13 @@ }; static enum list_objects_filter_result filter_blobs_none( - struct repository *r, + struct repository *r UNUSED, enum list_objects_filter_situation filter_situation, struct object *obj, - const char *pathname, - const char *filename, + const char *pathname UNUSED, + const char *filename UNUSED, struct oidset *omits, - void *filter_data_) + void *filter_data_ UNUSED) { switch (filter_situation) { default: @@ -112,7 +112,7 @@ } static void filter_blobs_none__init( - struct list_objects_filter_options *filter_options, + struct list_objects_filter_options *filter_options UNUSED, struct filter *filter) { filter->filter_object_fn = filter_blobs_none; @@ -159,11 +159,11 @@ } static enum list_objects_filter_result filter_trees_depth( - struct repository *r, + struct repository *r UNUSED, enum list_objects_filter_situation filter_situation, struct object *obj, - const char *pathname, - const char *filename, + const char *pathname UNUSED, + const char *filename UNUSED, struct oidset *omits, void *filter_data_) { @@ -274,8 +274,8 @@ struct repository *r, enum list_objects_filter_situation filter_situation, struct object *obj, - const char *pathname, - const char *filename, + const char *pathname UNUSED, + const char *filename UNUSED, struct oidset *omits, void *filter_data_) { @@ -514,6 +514,7 @@ static void filter_sparse_free(void *filter_data) { struct filter_sparse_data *d = filter_data; + clear_pattern_list(&d->pl); free(d->array_frame); free(d); } @@ -554,12 +555,12 @@ }; static enum list_objects_filter_result filter_object_type( - struct repository *r, + struct repository *r UNUSED, enum list_objects_filter_situation filter_situation, struct object *obj, - const char *pathname, - const char *filename, - struct oidset *omits, + const char *pathname UNUSED, + const char *filename UNUSED, + struct oidset *omits UNUSED, void *filter_data_) { struct filter_object_type_data *filter_data = filter_data_; @@ -675,7 +676,7 @@ struct object *obj, const char *pathname, const char *filename, - struct oidset *omits, + struct oidset *omits UNUSED, void *filter_data) { struct combine_filter_data *d = filter_data; diff -Nru git-2.39.2/list-objects.c git-2.39.5/list-objects.c --- git-2.39.2/list-objects.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/list-objects.c 2024-05-31 00:35:55.000000000 +0000 @@ -81,36 +81,6 @@ strbuf_setlen(path, pathlen); } -/* - * Processing a gitlink entry currently does nothing, since - * we do not recurse into the subproject. - * - * We *could* eventually add a flag that actually does that, - * which would involve: - * - is the subproject actually checked out? - * - if so, see if the subproject has already been added - * to the alternates list, and add it if not. - * - process the commit (or tag) the gitlink points to - * recursively. - * - * However, it's unclear whether there is really ever any - * reason to see superprojects and subprojects as such a - * "unified" object pool (potentially resulting in a totally - * humongous pack - avoiding which was the whole point of - * having gitlinks in the first place!). - * - * So for now, there is just a note that we *could* follow - * the link, and how to do it. Whether it necessarily makes - * any sense what-so-ever to ever do that is another issue. - */ -static void process_gitlink(struct traversal_context *ctx, - const unsigned char *sha1, - struct strbuf *path, - const char *name) -{ - /* Nothing to do */ -} - static void process_tree(struct traversal_context *ctx, struct tree *tree, struct strbuf *base, @@ -149,8 +119,7 @@ process_tree(ctx, t, base, entry.path); } else if (S_ISGITLINK(entry.mode)) - process_gitlink(ctx, entry.oid.hash, - base, entry.path); + ; /* ignore gitlink */ else { struct blob *b = lookup_blob(ctx->revs->repo, &entry.oid); if (!b) { diff -Nru git-2.39.2/ls-refs.c git-2.39.5/ls-refs.c --- git-2.39.2/ls-refs.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/ls-refs.c 2024-05-31 00:35:55.000000000 +0000 @@ -194,8 +194,9 @@ send_possibly_unborn_head(&data); if (!data.prefixes.nr) strvec_push(&data.prefixes, ""); - for_each_fullref_in_prefixes(get_git_namespace(), data.prefixes.v, - send_ref, &data); + refs_for_each_fullref_in_prefixes(get_main_ref_store(r), + get_git_namespace(), data.prefixes.v, + send_ref, &data); packet_fflush(stdout); strvec_clear(&data.prefixes); strbuf_release(&data.buf); diff -Nru git-2.39.2/object-file.c git-2.39.5/object-file.c --- git-2.39.2/object-file.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/object-file.c 2024-05-31 00:35:55.000000000 +0000 @@ -1864,13 +1864,6 @@ return 0; } -static int write_buffer(int fd, const void *buf, size_t len) -{ - if (write_in_full(fd, buf, len) < 0) - return error_errno(_("file write error")); - return 0; -} - static void hash_object_file_literally(const struct git_hash_algo *algo, const void *buf, unsigned long len, const char *type, struct object_id *oid) @@ -2015,8 +2008,8 @@ ret = git_deflate(stream, flush ? Z_FINISH : 0); the_hash_algo->update_fn(c, in0, stream->next_in - in0); - if (write_buffer(fd, compressed, stream->next_out - compressed) < 0) - die(_("unable to write loose object file")); + if (write_in_full(fd, compressed, stream->next_out - compressed) < 0) + die_errno(_("unable to write loose object file")); stream->next_out = compressed; stream->avail_out = compressed_len; diff -Nru git-2.39.2/object.c git-2.39.5/object.c --- git-2.39.2/object.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/object.c 2024-05-31 00:35:55.000000000 +0000 @@ -212,8 +212,7 @@ if (type == OBJ_BLOB) { struct blob *blob = lookup_blob(r, oid); if (blob) { - if (parse_blob_buffer(blob, buffer, size)) - return NULL; + parse_blob_buffer(blob); obj = &blob->object; } } else if (type == OBJ_TREE) { @@ -292,7 +291,7 @@ error(_("hash mismatch %s"), oid_to_hex(oid)); return NULL; } - parse_blob_buffer(lookup_blob(r, oid), NULL, 0); + parse_blob_buffer(lookup_blob(r, oid)); return lookup_object(r, oid); } diff -Nru git-2.39.2/pack-write.c git-2.39.5/pack-write.c --- git-2.39.2/pack-write.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/pack-write.c 2024-05-31 00:35:55.000000000 +0000 @@ -5,7 +5,6 @@ #include "chunk-format.h" #include "pack-mtimes.h" #include "oidmap.h" -#include "chunk-format.h" #include "pack-objects.h" void reset_pack_idx_option(struct pack_idx_option *opts) diff -Nru git-2.39.2/path.c git-2.39.5/path.c --- git-2.39.2/path.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/path.c 2024-05-31 00:35:55.000000000 +0000 @@ -840,6 +840,7 @@ if (!suffix[i]) return NULL; gitfile = read_gitfile(used_path.buf); + die_upon_dubious_ownership(gitfile, NULL, used_path.buf); if (gitfile) { strbuf_reset(&used_path); strbuf_addstr(&used_path, gitfile); @@ -850,6 +851,7 @@ } else { const char *gitfile = read_gitfile(path); + die_upon_dubious_ownership(gitfile, NULL, path); if (gitfile) path = gitfile; if (chdir(path)) diff -Nru git-2.39.2/promisor-remote.c git-2.39.5/promisor-remote.c --- git-2.39.2/promisor-remote.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/promisor-remote.c 2024-05-31 00:35:55.000000000 +0000 @@ -20,6 +20,16 @@ int i; FILE *child_in; + /* TODO: This should use NO_LAZY_FETCH_ENVIRONMENT */ + if (git_env_bool("GIT_NO_LAZY_FETCH", 0)) { + static int warning_shown; + if (!warning_shown) { + warning_shown = 1; + warning(_("lazy fetching disabled; some objects may not be available")); + } + return -1; + } + child.git_cmd = 1; child.in = -1; if (repo != the_repository) diff -Nru git-2.39.2/range-diff.c git-2.39.5/range-diff.c --- git-2.39.2/range-diff.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/range-diff.c 2024-05-31 00:35:55.000000000 +0000 @@ -269,14 +269,18 @@ hashmap_clear(&map); } -static int diffsize_consume(void *data, char *line, unsigned long len) +static int diffsize_consume(void *data, + char *line UNUSED, + unsigned long len UNUSED) { (*(int *)data)++; return 0; } -static void diffsize_hunk(void *data, long ob, long on, long nb, long nn, - const char *funcline, long funclen) +static void diffsize_hunk(void *data, + long ob UNUSED, long on UNUSED, + long nb UNUSED, long nn UNUSED, + const char *func UNUSED, long funclen UNUSED) { diffsize_consume(data, NULL, 0); } @@ -461,7 +465,7 @@ diff_flush(diffopt); } -static struct strbuf *output_prefix_cb(struct diff_options *opt, void *data) +static struct strbuf *output_prefix_cb(struct diff_options *opt UNUSED, void *data) { return data; } diff -Nru git-2.39.2/read-cache.c git-2.39.5/read-cache.c --- git-2.39.2/read-cache.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/read-cache.c 2024-05-31 00:35:55.000000000 +0000 @@ -1186,19 +1186,32 @@ istate->cache[istate->cache_nr - 1]->name, &len_eq_last); if (cmp_last > 0) { - if (len_eq_last == 0) { + if (name[len_eq_last] != '/') { /* * The entry sorts AFTER the last one in the - * index and their paths have no common prefix, - * so there cannot be a F/D conflict. + * index. + * + * If there were a conflict with "file", then our + * name would start with "file/" and the last index + * entry would start with "file" but not "file/". + * + * The next character after common prefix is + * not '/', so there can be no conflict. */ return retval; } else { /* * The entry sorts AFTER the last one in the - * index, but has a common prefix. Fall through - * to the loop below to disect the entry's path - * and see where the difference is. + * index, and the next character after common + * prefix is '/'. + * + * Either the last index entry is a file in + * conflict with this entry, or it has a name + * which sorts between this entry and the + * potential conflicting file. + * + * In both cases, we fall through to the loop + * below and let the regular search code handle it. */ } } else if (cmp_last == 0) { @@ -1222,53 +1235,6 @@ } len = slash - name; - if (cmp_last > 0) { - /* - * (len + 1) is a directory boundary (including - * the trailing slash). And since the loop is - * decrementing "slash", the first iteration is - * the longest directory prefix; subsequent - * iterations consider parent directories. - */ - - if (len + 1 <= len_eq_last) { - /* - * The directory prefix (including the trailing - * slash) also appears as a prefix in the last - * entry, so the remainder cannot collide (because - * strcmp said the whole path was greater). - * - * EQ: last: xxx/A - * this: xxx/B - * - * LT: last: xxx/file_A - * this: xxx/file_B - */ - return retval; - } - - if (len > len_eq_last) { - /* - * This part of the directory prefix (excluding - * the trailing slash) is longer than the known - * equal portions, so this sub-directory cannot - * collide with a file. - * - * GT: last: xxxA - * this: xxxB/file - */ - return retval; - } - - /* - * This is a possible collision. Fall through and - * let the regular search code handle it. - * - * last: xxx - * this: xxx/file - */ - } - pos = index_name_stage_pos(istate, name, len, stage, EXPAND_SPARSE); if (pos >= 0) { /* diff -Nru git-2.39.2/ref-filter.c git-2.39.5/ref-filter.c --- git-2.39.2/ref-filter.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/ref-filter.c 2024-05-31 00:35:55.000000000 +0000 @@ -2128,8 +2128,9 @@ return for_each_fullref_in("", cb, cb_data); } - return for_each_fullref_in_prefixes(NULL, filter->name_patterns, - cb, cb_data); + return refs_for_each_fullref_in_prefixes(get_main_ref_store(the_repository), + NULL, filter->name_patterns, + cb, cb_data); } /* diff -Nru git-2.39.2/reflog.c git-2.39.5/reflog.c --- git-2.39.2/reflog.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/reflog.c 2024-05-31 00:35:55.000000000 +0000 @@ -193,7 +193,6 @@ commit_list_insert(commit, &leftover); continue; } - commit->object.flags |= REACHABLE; parent = commit->parents; while (parent) { commit = parent->item; @@ -371,6 +370,9 @@ clear_commit_marks(cb->tip_commit, REACHABLE); break; } + for (elem = cb->mark_list; elem; elem = elem->next) + clear_commit_marks(elem->item, REACHABLE); + free_commit_list(cb->mark_list); } int count_reflog_ent(struct object_id *ooid UNUSED, diff -Nru git-2.39.2/refs/packed-backend.c git-2.39.5/refs/packed-backend.c --- git-2.39.2/refs/packed-backend.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/refs/packed-backend.c 2024-05-31 00:35:55.000000000 +0000 @@ -1263,7 +1263,8 @@ goto error; } - if (fsync_component(FSYNC_COMPONENT_REFERENCE, get_tempfile_fd(refs->tempfile)) || + if (fflush(out) || + fsync_component(FSYNC_COMPONENT_REFERENCE, get_tempfile_fd(refs->tempfile)) || close_tempfile_gently(refs->tempfile)) { strbuf_addf(err, "error closing file %s: %s", get_tempfile_path(refs->tempfile), diff -Nru git-2.39.2/refs.c git-2.39.5/refs.c --- git-2.39.2/refs.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/refs.c 2024-05-31 00:35:55.000000000 +0000 @@ -1723,9 +1723,10 @@ strbuf_release(&prefix); } -int for_each_fullref_in_prefixes(const char *namespace, - const char **patterns, - each_ref_fn fn, void *cb_data) +int refs_for_each_fullref_in_prefixes(struct ref_store *ref_store, + const char *namespace, + const char **patterns, + each_ref_fn fn, void *cb_data) { struct string_list prefixes = STRING_LIST_INIT_DUP; struct string_list_item *prefix; @@ -1740,7 +1741,7 @@ for_each_string_list_item(prefix, &prefixes) { strbuf_addstr(&buf, prefix->string); - ret = for_each_fullref_in(buf.buf, fn, cb_data); + ret = refs_for_each_fullref_in(ref_store, buf.buf, fn, cb_data); if (ret) break; strbuf_setlen(&buf, namespace_len); diff -Nru git-2.39.2/refs.h git-2.39.5/refs.h --- git-2.39.2/refs.h 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/refs.h 2024-05-31 00:35:55.000000000 +0000 @@ -354,8 +354,10 @@ * * callers should be prepared to ignore references that they did not ask for. */ -int for_each_fullref_in_prefixes(const char *namespace, const char **patterns, - each_ref_fn fn, void *cb_data); +int refs_for_each_fullref_in_prefixes(struct ref_store *refs, + const char *namespace, const char **patterns, + each_ref_fn fn, void *cb_data); + /** * iterate refs from the respective area. */ diff -Nru git-2.39.2/remote-curl.c git-2.39.5/remote-curl.c --- git-2.39.2/remote-curl.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/remote-curl.c 2024-05-31 00:35:55.000000000 +0000 @@ -1,4 +1,5 @@ #include "cache.h" +#include "git-curl-compat.h" #include "config.h" #include "remote.h" #include "connect.h" @@ -953,7 +954,9 @@ /* The request body is large and the size cannot be predicted. * We must use chunked encoding to send it. */ +#ifdef GIT_CURL_NEED_TRANSFER_ENCODING_HEADER headers = curl_slist_append(headers, "Transfer-Encoding: chunked"); +#endif rpc->initial_buffer = 1; curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, rpc_out); curl_easy_setopt(slot->curl, CURLOPT_INFILE, rpc); diff -Nru git-2.39.2/revision.c git-2.39.5/revision.c --- git-2.39.2/revision.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/revision.c 2024-05-31 00:35:55.000000000 +0000 @@ -600,10 +600,12 @@ static int tree_difference = REV_TREE_SAME; static void file_add_remove(struct diff_options *options, - int addremove, unsigned mode, - const struct object_id *oid, - int oid_valid, - const char *fullpath, unsigned dirty_submodule) + int addremove, + unsigned mode UNUSED, + const struct object_id *oid UNUSED, + int oid_valid UNUSED, + const char *fullpath UNUSED, + unsigned dirty_submodule UNUSED) { int diff = addremove == '+' ? REV_TREE_NEW : REV_TREE_OLD; struct rev_info *revs = options->change_fn_data; @@ -614,12 +616,15 @@ } static void file_change(struct diff_options *options, - unsigned old_mode, unsigned new_mode, - const struct object_id *old_oid, - const struct object_id *new_oid, - int old_oid_valid, int new_oid_valid, - const char *fullpath, - unsigned old_dirty_submodule, unsigned new_dirty_submodule) + unsigned old_mode UNUSED, + unsigned new_mode UNUSED, + const struct object_id *old_oid UNUSED, + const struct object_id *new_oid UNUSED, + int old_oid_valid UNUSED, + int new_oid_valid UNUSED, + const char *fullpath UNUSED, + unsigned old_dirty_submodule UNUSED, + unsigned new_dirty_submodule UNUSED) { tree_difference = REV_TREE_DIFFERENT; options->flags.has_changes = 1; diff -Nru git-2.39.2/sequencer.c git-2.39.5/sequencer.c --- git-2.39.2/sequencer.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/sequencer.c 2024-05-31 00:35:55.000000000 +0000 @@ -36,7 +36,6 @@ #include "rebase-interactive.h" #include "reset.h" #include "branch.h" -#include "log-tree.h" #define GIT_REFLOG_ACTION "GIT_REFLOG_ACTION" diff -Nru git-2.39.2/setup.c git-2.39.5/setup.c --- git-2.39.2/setup.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/setup.c 2024-05-31 00:35:55.000000000 +0000 @@ -6,6 +6,7 @@ #include "chdir-notify.h" #include "promisor-remote.h" #include "quote.h" +#include "exec-cmd.h" static int inside_git_dir = -1; static int inside_work_tree = -1; @@ -1165,6 +1166,27 @@ return data.is_safe; } +void die_upon_dubious_ownership(const char *gitfile, const char *worktree, + const char *gitdir) +{ + struct strbuf report = STRBUF_INIT, quoted = STRBUF_INIT; + const char *path; + + if (ensure_valid_ownership(gitfile, worktree, gitdir, &report)) + return; + + strbuf_complete(&report, '\n'); + path = gitfile ? gitfile : gitdir; + sq_quote_buf_pretty("ed, path); + + die(_("detected dubious ownership in repository at '%s'\n" + "%s" + "To add an exception for this directory, call:\n" + "\n" + "\tgit config --global --add safe.directory %s"), + path, report.buf, quoted.buf); +} + static int allowed_bare_repo_cb(const char *key, const char *value, void *d) { enum allowed_bare_repo *allowed_bare_repo = d; @@ -1699,3 +1721,57 @@ return 0; #endif } + +#ifndef DEFAULT_GIT_TEMPLATE_DIR +#define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates" +#endif + +struct template_dir_cb_data { + char *path; + int initialized; +}; + +static int template_dir_cb(const char *key, const char *value, void *d) +{ + struct template_dir_cb_data *data = d; + + if (strcmp(key, "init.templatedir")) + return 0; + + if (!value) { + data->path = NULL; + } else { + char *path = NULL; + + FREE_AND_NULL(data->path); + if (!git_config_pathname((const char **)&path, key, value)) + data->path = path ? path : xstrdup(value); + } + + return 0; +} + +const char *get_template_dir(const char *option_template) +{ + const char *template_dir = option_template; + + if (!template_dir) + template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT); + if (!template_dir) { + static struct template_dir_cb_data data; + + if (!data.initialized) { + git_protected_config(template_dir_cb, &data); + data.initialized = 1; + } + template_dir = data.path; + } + if (!template_dir) { + static char *dir; + + if (!dir) + dir = system_path(DEFAULT_GIT_TEMPLATE_DIR); + template_dir = dir; + } + return template_dir; +} diff -Nru git-2.39.2/submodule.c git-2.39.5/submodule.c --- git-2.39.2/submodule.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/submodule.c 2024-05-31 00:35:55.000000000 +0000 @@ -832,7 +832,7 @@ } static void collect_changed_submodules_cb(struct diff_queue_struct *q, - struct diff_options *options, + struct diff_options *options UNUSED, void *data) { struct collect_changed_submodules_cb_data *me = data; @@ -1005,6 +1005,9 @@ .super_oid = super_oid }; + if (validate_submodule_path(path) < 0) + exit(128); + oid_array_for_each_unique(commits, check_has_commit, &has_commit); if (has_commit.result) { @@ -1127,6 +1130,9 @@ const struct string_list *push_options, int dry_run) { + if (validate_submodule_path(path) < 0) + exit(128); + if (for_each_remote_ref_submodule(path, has_remote, NULL) > 0) { struct child_process cp = CHILD_PROCESS_INIT; strvec_push(&cp.args, "push"); @@ -1176,6 +1182,9 @@ struct child_process cp = CHILD_PROCESS_INIT; int i; + if (validate_submodule_path(path) < 0) + exit(128); + strvec_push(&cp.args, "submodule--helper"); strvec_push(&cp.args, "push-check"); strvec_push(&cp.args, head); @@ -1507,6 +1516,9 @@ struct fetch_task *task = xmalloc(sizeof(*task)); memset(task, 0, sizeof(*task)); + if (validate_submodule_path(path) < 0) + exit(128); + task->sub = submodule_from_path(spf->r, treeish_name, path); if (!task->sub) { @@ -1879,6 +1891,9 @@ const char *git_dir; int ignore_cp_exit_code = 0; + if (validate_submodule_path(path) < 0) + exit(128); + strbuf_addf(&buf, "%s/.git", path); git_dir = read_gitfile(buf.buf); if (!git_dir) @@ -1955,6 +1970,9 @@ struct strbuf buf = STRBUF_INIT; const char *git_dir; + if (validate_submodule_path(path) < 0) + exit(128); + strbuf_addf(&buf, "%s/.git", path); git_dir = read_gitfile(buf.buf); if (!git_dir) { @@ -1994,6 +2012,9 @@ struct strbuf buf = STRBUF_INIT; int ret = 0; + if (validate_submodule_path(path) < 0) + exit(128); + if (!file_exists(path) || is_empty_dir(path)) return 0; @@ -2044,6 +2065,9 @@ { struct strbuf config_path = STRBUF_INIT; + if (validate_submodule_path(sub->path) < 0) + exit(128); + submodule_name_to_gitdir(&config_path, the_repository, sub->name); strbuf_addstr(&config_path, "/config"); @@ -2066,6 +2090,9 @@ { struct child_process cp = CHILD_PROCESS_INIT; + if (validate_submodule_path(sub->path) < 0) + exit(128); + prepare_submodule_repo_env(&cp.env); cp.git_cmd = 1; @@ -2083,6 +2110,10 @@ static void submodule_reset_index(const char *path) { struct child_process cp = CHILD_PROCESS_INIT; + + if (validate_submodule_path(path) < 0) + exit(128); + prepare_submodule_repo_env(&cp.env); cp.git_cmd = 1; @@ -2146,10 +2177,27 @@ if (old_head) { if (!submodule_uses_gitfile(path)) absorb_git_dir_into_superproject(path); + else { + char *dotgit = xstrfmt("%s/.git", path); + char *git_dir = xstrdup(read_gitfile(dotgit)); + + free(dotgit); + if (validate_submodule_git_dir(git_dir, + sub->name) < 0) + die(_("refusing to create/use '%s' in " + "another submodule's git dir"), + git_dir); + free(git_dir); + } } else { struct strbuf gitdir = STRBUF_INIT; submodule_name_to_gitdir(&gitdir, the_repository, sub->name); + if (validate_submodule_git_dir(gitdir.buf, + sub->name) < 0) + die(_("refusing to create/use '%s' in another " + "submodule's git dir"), + gitdir.buf); connect_work_tree_and_git_dir(path, gitdir.buf, 0); strbuf_release(&gitdir); @@ -2270,6 +2318,34 @@ return 0; } +int validate_submodule_path(const char *path) +{ + char *p = xstrdup(path); + struct stat st; + int i, ret = 0; + char sep; + + for (i = 0; !ret && p[i]; i++) { + if (!is_dir_sep(p[i])) + continue; + + sep = p[i]; + p[i] = '\0'; + /* allow missing components, but no symlinks */ + ret = lstat(p, &st) || !S_ISLNK(st.st_mode) ? 0 : -1; + p[i] = sep; + if (ret) + error(_("expected '%.*s' in submodule path '%s' not to " + "be a symbolic link"), i, p, p); + } + if (!lstat(p, &st) && S_ISLNK(st.st_mode)) + ret = error(_("expected submodule path '%s' not to be a " + "symbolic link"), p); + free(p); + return ret; +} + + /* * Embeds a single submodules git directory into the superprojects git dir, * non recursively. @@ -2280,6 +2356,9 @@ struct strbuf new_gitdir = STRBUF_INIT; const struct submodule *sub; + if (validate_submodule_path(path) < 0) + exit(128); + if (submodule_uses_worktrees(path)) die(_("relocate_gitdir for submodule '%s' with " "more than one worktree not supported"), path); @@ -2320,6 +2399,9 @@ struct child_process cp = CHILD_PROCESS_INIT; + if (validate_submodule_path(path) < 0) + exit(128); + cp.dir = path; cp.git_cmd = 1; cp.no_stdin = 1; @@ -2342,6 +2424,10 @@ int err_code; const char *sub_git_dir; struct strbuf gitdir = STRBUF_INIT; + + if (validate_submodule_path(path) < 0) + exit(128); + strbuf_addf(&gitdir, "%s/.git", path); sub_git_dir = resolve_gitdir_gently(gitdir.buf, &err_code); @@ -2484,6 +2570,9 @@ const char *git_dir; int ret = 0; + if (validate_submodule_path(submodule) < 0) + exit(128); + strbuf_reset(buf); strbuf_addstr(buf, submodule); strbuf_complete(buf, '/'); diff -Nru git-2.39.2/submodule.h git-2.39.5/submodule.h --- git-2.39.2/submodule.h 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/submodule.h 2024-05-31 00:35:55.000000000 +0000 @@ -148,6 +148,11 @@ */ int validate_submodule_git_dir(char *git_dir, const char *submodule_name); +/* + * Make sure that the given submodule path does not follow symlinks. + */ +int validate_submodule_path(const char *path); + #define SUBMODULE_MOVE_HEAD_DRY_RUN (1<<0) #define SUBMODULE_MOVE_HEAD_FORCE (1<<1) int submodule_move_head(const char *path, diff -Nru git-2.39.2/t/lib-httpd/apache.conf git-2.39.5/t/lib-httpd/apache.conf --- git-2.39.2/t/lib-httpd/apache.conf 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/lib-httpd/apache.conf 2024-05-31 00:35:55.000000000 +0000 @@ -31,20 +31,9 @@ LoadModule http2_module modules/mod_http2.so -Protocols h2c +Protocols h2 h2c - -LockFile accept.lock - - - - - LoadModule auth_module modules/mod_auth.so - - - -= 2.1> LoadModule auth_basic_module modules/mod_auth_basic.so @@ -57,9 +46,7 @@ LoadModule authz_host_module modules/mod_authz_host.so - -= 2.4> LoadModule authn_core_module modules/mod_authn_core.so @@ -83,7 +70,6 @@ LoadModule mpm_prefork_module modules/mod_mpm_prefork.so - PassEnv GIT_VALGRIND PassEnv GIT_VALGRIND_OPTIONS @@ -123,6 +109,10 @@ Header set Set-Cookie name=value + + Require expr %{HTTP:x-magic-one} == 'abra' + Require expr %{HTTP:x-magic-two} == 'cadabra' + SetEnv GIT_EXEC_PATH ${GIT_EXEC_PATH} SetEnv GIT_HTTP_EXPORT_ALL @@ -205,18 +195,6 @@ RewriteRule ^/redir-objects/(.*/info/refs)$ /dumb/$1 [PT] RewriteRule ^/redir-objects/(.*/objects/.*)$ /dumb/$1 [R=301] -# Apache 2.2 does not understand , so we use RewriteCond. -# And as RewriteCond does not allow testing for non-matches, we match -# the desired case first (one has abra, two has cadabra), and let it -# pass by marking the RewriteRule as [L], "last rule, do not process -# any other matching RewriteRules after this"), and then have another -# RewriteRule that matches all other cases and lets them fail via '[F]', -# "fail the request". -RewriteCond %{HTTP:x-magic-one} =abra -RewriteCond %{HTTP:x-magic-two} =cadabra -RewriteRule ^/smart_headers/.* - [L] -RewriteRule ^/smart_headers/.* - [F] - LoadModule ssl_module modules/mod_ssl.so @@ -225,7 +203,6 @@ SSLRandomSeed startup file:/dev/urandom 512 SSLRandomSeed connect file:/dev/urandom 512 SSLSessionCache none -SSLMutex file:ssl_mutex SSLEngine On diff -Nru git-2.39.2/t/lib-httpd/ssl.cnf git-2.39.5/t/lib-httpd/ssl.cnf --- git-2.39.2/t/lib-httpd/ssl.cnf 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/lib-httpd/ssl.cnf 2024-05-31 00:35:55.000000000 +0000 @@ -1,7 +1,7 @@ RANDFILE = $ENV::RANDFILE_PATH [ req ] -default_bits = 1024 +default_bits = 2048 distinguished_name = req_distinguished_name prompt = no [ req_distinguished_name ] diff -Nru git-2.39.2/t/lib-httpd.sh git-2.39.5/t/lib-httpd.sh --- git-2.39.2/t/lib-httpd.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/lib-httpd.sh 2024-05-31 00:35:55.000000000 +0000 @@ -99,16 +99,19 @@ fi HTTPD_VERSION=$($LIB_HTTPD_PATH -v | \ - sed -n 's/^Server version: Apache\/\([0-9]*\)\..*$/\1/p; q') + sed -n 's/^Server version: Apache\/\([0-9.]*\).*$/\1/p; q') +HTTPD_VERSION_MAJOR=$(echo $HTTPD_VERSION | cut -d. -f1) +HTTPD_VERSION_MINOR=$(echo $HTTPD_VERSION | cut -d. -f2) -if test -n "$HTTPD_VERSION" +if test -n "$HTTPD_VERSION_MAJOR" then if test -z "$LIB_HTTPD_MODULE_PATH" then - if ! test $HTTPD_VERSION -ge 2 + if ! test "$HTTPD_VERSION_MAJOR" -eq 2 || + ! test "$HTTPD_VERSION_MINOR" -ge 4 then test_skip_or_die GIT_TEST_HTTPD \ - "at least Apache version 2 is required" + "at least Apache version 2.4 is required" fi if ! test -d "$DEFAULT_HTTPD_MODULE_PATH" then @@ -280,11 +283,11 @@ none) ;; pass) - echo "askpass: Password for 'http://$2@$dest': " + echo "askpass: Password for '$HTTPD_PROTO://$2@$dest': " ;; both) - echo "askpass: Username for 'http://$dest': " - echo "askpass: Password for 'http://$2@$dest': " + echo "askpass: Username for '$HTTPD_PROTO://$dest': " + echo "askpass: Password for '$HTTPD_PROTO://$2@$dest': " ;; *) false diff -Nru git-2.39.2/t/t0000-basic.sh git-2.39.5/t/t0000-basic.sh --- git-2.39.2/t/t0000-basic.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t0000-basic.sh 2024-05-31 00:35:55.000000000 +0000 @@ -1200,6 +1200,34 @@ test $len = 4098 ' +# D/F conflict checking uses an optimization when adding to the end. +# make sure it does not get confused by `a-` sorting _between_ +# `a` and `a/`. +test_expect_success 'more update-index D/F conflicts' ' + # empty the index to make sure our entry is last + git read-tree --empty && + cacheinfo=100644,$(test_oid empty_blob) && + git update-index --add --cacheinfo $cacheinfo,path5/a && + + test_must_fail git update-index --add --cacheinfo $cacheinfo,path5/a/file && + test_must_fail git update-index --add --cacheinfo $cacheinfo,path5/a/b/file && + test_must_fail git update-index --add --cacheinfo $cacheinfo,path5/a/b/c/file && + + # "a-" sorts between "a" and "a/" + git update-index --add --cacheinfo $cacheinfo,path5/a- && + + test_must_fail git update-index --add --cacheinfo $cacheinfo,path5/a/file && + test_must_fail git update-index --add --cacheinfo $cacheinfo,path5/a/b/file && + test_must_fail git update-index --add --cacheinfo $cacheinfo,path5/a/b/c/file && + + cat >expected <<-\EOF && + path5/a + path5/a- + EOF + git ls-files >actual && + test_cmp expected actual +' + test_expect_success 'test_must_fail on a failing git command' ' test_must_fail git notacommand ' diff -Nru git-2.39.2/t/t0033-safe-directory.sh git-2.39.5/t/t0033-safe-directory.sh --- git-2.39.2/t/t0033-safe-directory.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t0033-safe-directory.sh 2024-05-31 00:35:55.000000000 +0000 @@ -80,4 +80,28 @@ git status ' +test_expect_success 'local clone of unowned repo refused in unsafe directory' ' + test_when_finished "rm -rf source" && + git init source && + ( + sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER && + test_commit -C source initial + ) && + test_must_fail git clone --local source target && + test_path_is_missing target +' + +test_expect_success 'local clone of unowned repo accepted in safe directory' ' + test_when_finished "rm -rf source" && + git init source && + ( + sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER && + test_commit -C source initial + ) && + test_must_fail git clone --local source target && + git config --global --add safe.directory "$(pwd)/source/.git" && + git clone --local source target && + test_path_is_dir target +' + test_done diff -Nru git-2.39.2/t/t0411-clone-from-partial.sh git-2.39.5/t/t0411-clone-from-partial.sh --- git-2.39.2/t/t0411-clone-from-partial.sh 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/t/t0411-clone-from-partial.sh 2024-05-31 00:35:55.000000000 +0000 @@ -0,0 +1,78 @@ +#!/bin/sh + +test_description='check that local clone does not fetch from promisor remotes' + +. ./test-lib.sh + +test_expect_success 'create evil repo' ' + git init tmp && + test_commit -C tmp a && + git -C tmp config uploadpack.allowfilter 1 && + git clone --filter=blob:none --no-local --no-checkout tmp evil && + rm -rf tmp && + + git -C evil config remote.origin.uploadpack \"\$TRASH_DIRECTORY/fake-upload-pack\" && + write_script fake-upload-pack <<-\EOF && + echo >&2 "fake-upload-pack running" + >"$TRASH_DIRECTORY/script-executed" + exit 1 + EOF + export TRASH_DIRECTORY && + + # empty shallow file disables local clone optimization + >evil/.git/shallow +' + +test_expect_success 'local clone must not fetch from promisor remote and execute script' ' + rm -f script-executed && + test_must_fail git clone \ + --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \ + evil clone1 2>err && + grep "detected dubious ownership" err && + ! grep "fake-upload-pack running" err && + test_path_is_missing script-executed +' + +test_expect_success 'clone from file://... must not fetch from promisor remote and execute script' ' + rm -f script-executed && + test_must_fail git clone \ + --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \ + "file://$(pwd)/evil" clone2 2>err && + grep "detected dubious ownership" err && + ! grep "fake-upload-pack running" err && + test_path_is_missing script-executed +' + +test_expect_success 'fetch from file://... must not fetch from promisor remote and execute script' ' + rm -f script-executed && + test_must_fail git fetch \ + --upload-pack="GIT_TEST_ASSUME_DIFFERENT_OWNER=true git-upload-pack" \ + "file://$(pwd)/evil" 2>err && + grep "detected dubious ownership" err && + ! grep "fake-upload-pack running" err && + test_path_is_missing script-executed +' + +test_expect_success 'pack-objects should fetch from promisor remote and execute script' ' + rm -f script-executed && + echo "HEAD" | test_must_fail git -C evil pack-objects --revs --stdout >/dev/null 2>err && + grep "fake-upload-pack running" err && + test_path_is_file script-executed +' + +test_expect_success 'clone from promisor remote does not lazy-fetch by default' ' + rm -f script-executed && + test_must_fail git clone evil no-lazy 2>err && + grep "lazy fetching disabled" err && + test_path_is_missing script-executed +' + +test_expect_success 'promisor lazy-fetching can be re-enabled' ' + rm -f script-executed && + test_must_fail env GIT_NO_LAZY_FETCH=0 \ + git clone evil lazy-ok 2>err && + grep "fake-upload-pack running" err && + test_path_is_file script-executed +' + +test_done diff -Nru git-2.39.2/t/t1091-sparse-checkout-builtin.sh git-2.39.5/t/t1091-sparse-checkout-builtin.sh --- git-2.39.2/t/t1091-sparse-checkout-builtin.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t1091-sparse-checkout-builtin.sh 2024-05-31 00:35:55.000000000 +0000 @@ -238,7 +238,7 @@ test_expect_success 'cone mode: warn on bad pattern' ' test_when_finished mv sparse-checkout repo/.git/info/ && cp repo/.git/info/sparse-checkout . && - echo "!/deep/deeper/*" >>repo/.git/info/sparse-checkout && + echo "!/deep/deeper/*/" >>repo/.git/info/sparse-checkout && git -C repo read-tree -mu HEAD 2>err && test_i18ngrep "unrecognized negative pattern" err ' @@ -667,6 +667,15 @@ check_read_tree_errors repo "a deep" "disabling cone pattern matching" ' +test_expect_success 'pattern-checks: non directory pattern' ' + cat >repo/.git/info/sparse-checkout <<-\EOF && + /deep/deeper1/a + EOF + check_read_tree_errors repo deep "disabling cone pattern matching" && + check_files repo/deep deeper1 && + check_files repo/deep/deeper1 a +' + test_expect_success 'pattern-checks: contained glob characters' ' for c in "[a]" "\\" "?" "*" do diff -Nru git-2.39.2/t/t1300-config.sh git-2.39.5/t/t1300-config.sh --- git-2.39.2/t/t1300-config.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t1300-config.sh 2024-05-31 00:35:55.000000000 +0000 @@ -617,6 +617,36 @@ test_must_fail git config --rename-section branch.zwei "bogus name" ' +test_expect_success 'renaming a section with a long line' ' + { + printf "[b]\\n" && + printf " c = d %1024s [a] e = f\\n" " " && + printf "[a] g = h\\n" + } >y && + git config -f y --rename-section a xyz && + test_must_fail git config -f y b.e +' + +test_expect_success 'renaming an embedded section with a long line' ' + { + printf "[b]\\n" && + printf " c = d %1024s [a] [foo] e = f\\n" " " && + printf "[a] g = h\\n" + } >y && + git config -f y --rename-section a xyz && + test_must_fail git config -f y foo.e +' + +test_expect_success 'renaming a section with an overly-long line' ' + { + printf "[b]\\n" && + printf " c = d %525000s e" " " && + printf "[a] g = h\\n" + } >y && + test_must_fail git config -f y --rename-section a xyz 2>err && + grep "refusing to work with overly long line in .y. on line 2" err +' + cat >> .git/config << EOF [branch "zwei"] a = 1 [branch "vier"] EOF diff -Nru git-2.39.2/t/t1350-config-hooks-path.sh git-2.39.5/t/t1350-config-hooks-path.sh --- git-2.39.2/t/t1350-config-hooks-path.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t1350-config-hooks-path.sh 2024-05-31 00:35:55.000000000 +0000 @@ -41,4 +41,11 @@ test .git/custom-hooks/abc = "$(cat actual)" ' +test_expect_success 'core.hooksPath=/dev/null' ' + git clone -c core.hooksPath=/dev/null . no-templates && + value="$(git -C no-templates config --local core.hooksPath)" && + # The Bash used by Git for Windows rewrites `/dev/null` to `nul` + { test /dev/null = "$value" || test nul = "$value"; } +' + test_done diff -Nru git-2.39.2/t/t3104-ls-tree-format.sh git-2.39.5/t/t3104-ls-tree-format.sh --- git-2.39.2/t/t3104-ls-tree-format.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t3104-ls-tree-format.sh 2024-05-31 00:35:55.000000000 +0000 @@ -36,6 +36,12 @@ ' } +test_expect_success "ls-tree --format='%(path) %(path) %(path)' HEAD top-file" ' + git ls-tree --format="%(path) %(path) %(path)" HEAD top-file.t >actual && + echo top-file.t top-file.t top-file.t >expect && + test_cmp expect actual +' + test_ls_tree_format \ "%(objectmode) %(objecttype) %(objectname)%x09%(path)" \ "" diff -Nru git-2.39.2/t/t3204-branch-name-interpretation.sh git-2.39.5/t/t3204-branch-name-interpretation.sh --- git-2.39.2/t/t3204-branch-name-interpretation.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t3204-branch-name-interpretation.sh 2024-05-31 00:35:55.000000000 +0000 @@ -57,6 +57,16 @@ expect_branch refs/heads/refs/heads/qualified two ' +test_expect_success 'force-copy a branch to itself via @{-1} is no-op' ' + git branch -t copiable main && + git checkout copiable && + git checkout - && + git branch -C @{-1} copiable && + git config --get-all branch.copiable.merge >actual && + echo refs/heads/main >expect && + test_cmp expect actual +' + test_expect_success 'delete branch via @{-1}' ' git branch previous-del && diff -Nru git-2.39.2/t/t3920-crlf-messages.sh git-2.39.5/t/t3920-crlf-messages.sh --- git-2.39.2/t/t3920-crlf-messages.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t3920-crlf-messages.sh 2024-05-31 00:35:55.000000000 +0000 @@ -12,7 +12,7 @@ cat >.crlf-orig-$branch.txt && cat .crlf-orig-$branch.txt | append_cr >.crlf-message-$branch.txt && grep 'Subject' .crlf-orig-$branch.txt | tr '\n' ' ' | sed 's/[ ]*$//' | tr -d '\n' >.crlf-subject-$branch.txt && - grep 'Body' .crlf-message-$branch.txt >.crlf-body-$branch.txt || true && + grep 'Body' .crlf-orig-$branch.txt | append_cr >.crlf-body-$branch.txt && LIB_CRLF_BRANCHES="${LIB_CRLF_BRANCHES} ${branch}" && test_tick && hash=$(git commit-tree HEAD^{tree} -p HEAD -F .crlf-message-${branch}.txt) && diff -Nru git-2.39.2/t/t4023-diff-rename-typechange.sh git-2.39.5/t/t4023-diff-rename-typechange.sh --- git-2.39.2/t/t4023-diff-rename-typechange.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t4023-diff-rename-typechange.sh 2024-05-31 00:35:55.000000000 +0000 @@ -52,8 +52,8 @@ ' test_expect_success 'cross renames to be detected for regular files' ' - - git diff-tree five six -r --name-status -B -M | sort >actual && + git diff-tree five six -r --name-status -B -M >out && + sort out >actual && { echo "R100 foo bar" && echo "R100 bar foo" @@ -63,8 +63,8 @@ ' test_expect_success 'cross renames to be detected for typechange' ' - - git diff-tree one two -r --name-status -B -M | sort >actual && + git diff-tree one two -r --name-status -B -M >out && + sort out >actual && { echo "R100 foo bar" && echo "R100 bar foo" @@ -74,8 +74,8 @@ ' test_expect_success 'moves and renames' ' - - git diff-tree three four -r --name-status -B -M | sort >actual && + git diff-tree three four -r --name-status -B -M >out && + sort out >actual && { # see -B -M (#6) in t4008 echo "C100 foo bar" && diff -Nru git-2.39.2/t/t4045-diff-relative.sh git-2.39.5/t/t4045-diff-relative.sh --- git-2.39.2/t/t4045-diff-relative.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t4045-diff-relative.sh 2024-05-31 00:35:55.000000000 +0000 @@ -162,6 +162,35 @@ check_diff_relative_option . file2 false --no-relative --relative=subdir check_diff_relative_option . file2 true --no-relative --relative=subdir +test_expect_success 'external diff with --relative' ' + test_when_finished "git reset --hard" && + echo changed >file1 && + echo changed >subdir/file2 && + + write_script mydiff <<-\EOF && + # hacky pretend diff; the goal here is just to make sure we got + # passed sensible input that we _could_ diff, without relying on + # the specific output of a system diff tool. + echo "diff a/$1 b/$1" && + echo "--- a/$1" && + echo "+++ b/$1" && + echo "@@ -1 +0,0 @@" && + sed "s/^/-/" "$2" && + sed "s/^/+/" "$5" + EOF + + cat >expect <<-\EOF && + diff a/file2 b/file2 + --- a/file2 + +++ b/file2 + @@ -1 +0,0 @@ + -other content + +changed + EOF + GIT_EXTERNAL_DIFF=./mydiff git diff --relative=subdir >actual && + test_cmp expect actual +' + test_expect_success 'setup diff --relative unmerged' ' test_commit zero file0 && test_commit base subdir/file0 && diff -Nru git-2.39.2/t/t4115-apply-symlink.sh git-2.39.5/t/t4115-apply-symlink.sh --- git-2.39.2/t/t4115-apply-symlink.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t4115-apply-symlink.sh 2024-05-31 00:35:55.000000000 +0000 @@ -126,4 +126,19 @@ test_path_is_file .git/delete-me ' +test_expect_success SYMLINKS '--reject removes .rej symlink if it exists' ' + test_when_finished "git reset --hard && git clean -dfx" && + + test_commit file && + echo modified >file.t && + git diff -- file.t >patch && + echo modified-again >file.t && + + ln -s foo file.t.rej && + test_must_fail git apply patch --reject 2>err && + test_i18ngrep "Rejected hunk" err && + test_path_is_missing foo && + test_path_is_file file.t.rej +' + test_done diff -Nru git-2.39.2/t/t4205-log-pretty-formats.sh git-2.39.5/t/t4205-log-pretty-formats.sh --- git-2.39.2/t/t4205-log-pretty-formats.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t4205-log-pretty-formats.sh 2024-05-31 00:35:55.000000000 +0000 @@ -156,7 +156,7 @@ for r in $revs do git show -s --pretty=oneline "$r" >raw && - cat raw | lf_to_nul || exit 1 + cat raw | lf_to_nul || return 1 done >expect && # the trailing NUL is already produced so we do not need to # output another one diff -Nru git-2.39.2/t/t4211-line-log.sh git-2.39.5/t/t4211-line-log.sh --- git-2.39.2/t/t4211-line-log.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t4211-line-log.sh 2024-05-31 00:35:55.000000000 +0000 @@ -315,4 +315,26 @@ test_cmp expect actual ' +test_expect_success 'setup tests for zero-width regular expressions' ' + cat >expect <<-EOF + Modify func1() in file.c + Add func1() and func2() in file.c + EOF +' + +test_expect_success 'zero-width regex $ matches any function name' ' + git log --format="%s" --no-patch "-L:$:file.c" >actual && + test_cmp expect actual +' + +test_expect_success 'zero-width regex ^ matches any function name' ' + git log --format="%s" --no-patch "-L:^:file.c" >actual && + test_cmp expect actual +' + +test_expect_success 'zero-width regex .* matches any function name' ' + git log --format="%s" --no-patch "-L:.*:file.c" >actual && + test_cmp expect actual +' + test_done diff -Nru git-2.39.2/t/t5314-pack-cycle-detection.sh git-2.39.5/t/t5314-pack-cycle-detection.sh --- git-2.39.2/t/t5314-pack-cycle-detection.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t5314-pack-cycle-detection.sh 2024-05-31 00:35:55.000000000 +0000 @@ -63,13 +63,16 @@ # Note that the two variants of "file" must be similar enough to convince git # to create the delta. make_pack () { - { - printf '%s\n' "-$(git rev-parse $2)" - printf '%s dummy\n' "$(git rev-parse $1:dummy)" - printf '%s file\n' "$(git rev-parse $1:file)" - } | - git pack-objects --stdout | - git index-pack --stdin --fix-thin + ln1=$(git rev-parse "$2") && + ln2=$(git rev-parse "$1:dummy") && + ln3=$(git rev-parse "$1:file") && + cat >list <<-EOF + -$ln1 + $ln2 dummy + $ln3 file + EOF + git pack-objects --stdout pack && + git index-pack --stdin --fix-thin &2 + echo whoopsie >"$TRASH_DIRECTORY"/whoops + EOF + git add a/hooks/post-checkout && + test_tick && + git commit -m post-checkout + ) && + git clone df-conflict clone 2>err && + ! grep WHOOPS err && + test_path_is_missing whoops +' + . "$TEST_DIRECTORY"/lib-httpd.sh start_httpd diff -Nru git-2.39.2/t/t5541-http-push-smart.sh git-2.39.5/t/t5541-http-push-smart.sh --- git-2.39.2/t/t5541-http-push-smart.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t5541-http-push-smart.sh 2024-05-31 00:35:55.000000000 +0000 @@ -36,28 +36,6 @@ setup_askpass_helper -cat >exp <\"\$HTTPD_ROOT_PATH\"/access.log" && - - # In the URL, add a trailing slash, and see if git appends yet another - # slash. - cd "$ROOT_PATH" && - git clone $HTTPD_URL/smart/test_repo.git/ test_repo_clone && - - # NEEDSWORK: If the overspecification of the expected result is reduced, we - # might be able to run this test in all protocol versions. - if test "$GIT_TEST_PROTOCOL_VERSION" = 0 - then - check_access_log exp - fi -' - test_expect_success 'clone remote repository' ' rm -rf test_repo_clone && git clone $HTTPD_URL/smart/test_repo.git test_repo_clone && @@ -67,6 +45,10 @@ ' test_expect_success 'push to remote repository (standard)' ' + # Clear the log, so that the "used receive-pack service" test below + # sees just what we did here. + >"$HTTPD_ROOT_PATH"/access.log && + cd "$ROOT_PATH"/test_repo_clone && : >path2 && git add path2 && @@ -80,6 +62,15 @@ test $HEAD = $(git rev-parse --verify HEAD)) ' +test_expect_success 'used receive-pack service' ' + cat >exp <<-\EOF && + GET /smart/test_repo.git/info/refs?service=git-receive-pack HTTP/1.1 200 + POST /smart/test_repo.git/git-receive-pack HTTP/1.1 200 + EOF + + check_access_log exp +' + test_expect_success 'push to remote repository (standard) with sending Accept-Language' ' cat >exp <<-\EOF && => Send header: Accept-Language: ko-KR, *;q=0.9 @@ -141,28 +132,6 @@ ' rm -f "$HTTPD_DOCUMENT_ROOT_PATH/test_repo.git/hooks/update" -cat >exp <exp <<-\EOF && - > GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1 - > Accept: */* - > Accept-Encoding: ENCODINGS - > Accept-Language: ko-KR, *;q=0.9 - > Pragma: no-cache - < HTTP/1.1 200 OK - < Pragma: no-cache - < Cache-Control: no-cache, max-age=0, must-revalidate - < Content-Type: application/x-git-upload-pack-advertisement - > POST /smart/repo.git/git-upload-pack HTTP/1.1 - > Accept-Encoding: ENCODINGS - > Content-Type: application/x-git-upload-pack-request - > Accept: application/x-git-upload-pack-result - > Accept-Language: ko-KR, *;q=0.9 - > Content-Length: xxx - < HTTP/1.1 200 OK - < Pragma: no-cache - < Cache-Control: no-cache, max-age=0, must-revalidate - < Content-Type: application/x-git-upload-pack-result + if test_have_prereq HTTP2 && test "$HTTPD_PROTO" = "https" + then + # ALPN lets us immediately use HTTP/2; likewise, POSTs with + # bodies can use it because they do not need to upgrade + INITIAL_PROTO=HTTP/2 + else + # either we are not using HTTP/2, or the initial + # request is sent via HTTP/1.1 and asks for upgrade + INITIAL_PROTO=HTTP/1.1 + fi && + + cat >exp.raw <<-EOF && + > GET /smart/repo.git/info/refs?service=git-upload-pack $INITIAL_PROTO + > accept: */* + > accept-encoding: ENCODINGS + > accept-language: ko-KR, *;q=0.9 + > pragma: no-cache + {V2} > git-protocol: version=2 + < $HTTP_PROTO 200 OK + < pragma: no-cache + < cache-control: no-cache, max-age=0, must-revalidate + < content-type: application/x-git-upload-pack-advertisement + > POST /smart/repo.git/git-upload-pack $INITIAL_PROTO + > accept-encoding: ENCODINGS + > content-type: application/x-git-upload-pack-request + > accept: application/x-git-upload-pack-result + > accept-language: ko-KR, *;q=0.9 + {V2} > git-protocol: version=2 + > content-length: xxx + < $INITIAL_PROTO 200 OK + < pragma: no-cache + < cache-control: no-cache, max-age=0, must-revalidate + < content-type: application/x-git-upload-pack-result + {V2} > POST /smart/repo.git/git-upload-pack $INITIAL_PROTO + {V2} > accept-encoding: ENCODINGS + {V2} > content-type: application/x-git-upload-pack-request + {V2} > accept: application/x-git-upload-pack-result + {V2} > accept-language: ko-KR, *;q=0.9 + {V2} > git-protocol: version=2 + {V2} > content-length: xxx + {V2} < $INITIAL_PROTO 200 OK + {V2} < pragma: no-cache + {V2} < cache-control: no-cache, max-age=0, must-revalidate + {V2} < content-type: application/x-git-upload-pack-result EOF - GIT_TRACE_CURL=true GIT_TEST_PROTOCOL_VERSION=0 LANGUAGE="ko_KR.UTF-8" \ + if test "$GIT_TEST_PROTOCOL_VERSION" = 0 + then + sed "/^{V2}/d" exp + else + sed "s/^{V2} //" exp + fi && + + GIT_TRACE_CURL=true LANGUAGE="ko_KR.UTF-8" \ git clone --quiet $HTTPD_URL/smart/repo.git clone 2>err && test_cmp file clone/file && tr '\''\015'\'' Q Send header, /d /^=> Send header:$/d @@ -71,6 +107,8 @@ s/= Recv header:// /^<= Recv data/d /^=> Send data/d + /^<= Recv SSL data/d + /^=> Send SSL data/d /^$/d /^< $/d @@ -78,36 +116,35 @@ s/^/> / } - /^> User-Agent: /d - /^> Host: /d + /^< HTTP/ { + s/200$/200 OK/ + } + /^< HTTP\\/1.1 101/d + /^[><] connection: /d + /^[><] upgrade: /d + /^> http2-settings: /d + + /^> user-agent: /d + /^> host: /d /^> POST /,$ { /^> Accept: [*]\\/[*]/d } - s/^> Content-Length: .*/> Content-Length: xxx/ + s/^> content-length: .*/> content-length: xxx/ /^> 00..want /d /^> 00.*done/d - /^< Server: /d - /^< Expires: /d - /^< Date: /d - /^< Content-Length: /d - /^< Transfer-Encoding: /d + /^< server: /d + /^< expires: /d + /^< date: /d + /^< content-length: /d + /^< transfer-encoding: /d " >actual && - # NEEDSWORK: If the overspecification of the expected result is reduced, we - # might be able to run this test in all protocol versions. - if test "$GIT_TEST_PROTOCOL_VERSION" = 0 - then - sed -e "s/^> Accept-Encoding: .*/> Accept-Encoding: ENCODINGS/" \ - actual >actual.smudged && - test_cmp exp actual.smudged && - - grep "Accept-Encoding:.*gzip" actual >actual.gzip && - test_line_count = 2 actual.gzip && - - grep "Accept-Language: ko-KR, *" actual >actual.language && - test_line_count = 2 actual.language - fi + sed -e "s/^> accept-encoding: .*/> accept-encoding: ENCODINGS/" \ + actual >actual.smudged && + test_cmp exp actual.smudged && + + grep "accept-encoding:.*gzip" actual >actual.gzip ' test_expect_success 'fetch changes via http' ' @@ -119,19 +156,9 @@ ' test_expect_success 'used upload-pack service' ' - cat >exp <<-\EOF && - GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1 200 - POST /smart/repo.git/git-upload-pack HTTP/1.1 200 - GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/1.1 200 - POST /smart/repo.git/git-upload-pack HTTP/1.1 200 - EOF - - # NEEDSWORK: If the overspecification of the expected result is reduced, we - # might be able to run this test in all protocol versions. - if test "$GIT_TEST_PROTOCOL_VERSION" = 0 - then - check_access_log exp - fi + strip_access_log >log && + grep "GET /smart/repo.git/info/refs?service=git-upload-pack HTTP/[0-9.]* 200" log && + grep "POST /smart/repo.git/git-upload-pack HTTP/[0-9.]* 200" log ' test_expect_success 'follow redirects (301)' ' @@ -280,21 +307,23 @@ 127.0.0.1 FALSE /smart_cookies/ FALSE 0 othername othervalue EOF sort >expect_cookies.txt <<-\EOF && - 127.0.0.1 FALSE /smart_cookies/ FALSE 0 othername othervalue + 127.0.0.1 FALSE /smart_cookies/repo.git/ FALSE 0 name value 127.0.0.1 FALSE /smart_cookies/repo.git/info/ FALSE 0 name value EOF git config http.cookiefile cookies.txt && git config http.savecookies true && - git ls-remote $HTTPD_URL/smart_cookies/repo.git main && - # NEEDSWORK: If the overspecification of the expected result is reduced, we - # might be able to run this test in all protocol versions. - if test "$GIT_TEST_PROTOCOL_VERSION" = 0 - then - tail -3 cookies.txt | sort >cookies_tail.txt && - test_cmp expect_cookies.txt cookies_tail.txt - fi + test_when_finished " + git --git-dir=\"\$HTTPD_DOCUMENT_ROOT_PATH/repo.git\" \ + tag -d cookie-tag + " && + git --git-dir="$HTTPD_DOCUMENT_ROOT_PATH/repo.git" \ + tag -m "foo" cookie-tag && + git fetch $HTTPD_URL/smart_cookies/repo.git cookie-tag && + + grep "^[^#]" cookies.txt | sort >cookies_stripped.txt && + test_cmp expect_cookies.txt cookies_stripped.txt ' test_expect_success 'transfer.hiderefs works over smart-http' ' @@ -666,4 +695,13 @@ test_line_count -ge 1 warnings ' +test_expect_success 'no empty path components' ' + # In the URL, add a trailing slash, and see if git appends yet another + # slash. + git clone $HTTPD_URL/smart/repo.git/ clone-with-slash && + + strip_access_log >log && + ! grep "//" log +' + test_done diff -Nru git-2.39.2/t/t5559-http-fetch-smart-http2.sh git-2.39.5/t/t5559-http-fetch-smart-http2.sh --- git-2.39.2/t/t5559-http-fetch-smart-http2.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t5559-http-fetch-smart-http2.sh 2024-05-31 00:35:55.000000000 +0000 @@ -1,4 +1,5 @@ #!/bin/sh HTTP_PROTO=HTTP/2 +LIB_HTTPD_SSL=1 . ./t5551-http-fetch-smart.sh diff -Nru git-2.39.2/t/t5601-clone.sh git-2.39.5/t/t5601-clone.sh --- git-2.39.2/t/t5601-clone.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t5601-clone.sh 2024-05-31 00:35:55.000000000 +0000 @@ -633,6 +633,21 @@ test_i18ngrep "the following paths have collided" icasefs/warning ' +test_expect_success CASE_INSENSITIVE_FS,SYMLINKS \ + 'colliding symlink/directory keeps directory' ' + git init icasefs-colliding-symlink && + ( + cd icasefs-colliding-symlink && + a=$(printf a | git hash-object -w --stdin) && + printf "100644 %s 0\tA/dir/b\n120000 %s 0\ta\n" $a $a >idx && + git update-index --index-info &2 + echo I was here >hook.run + exit 1 + EOF + + test_config init.templateDir "$(pwd)/tmpl" && + test_when_finished \ + "git config --global --unset init.templateDir || true" && + ( + sane_unset GIT_TEMPLATE_DIR && + NO_SET_GIT_TEMPLATE_DIR=t && + export NO_SET_GIT_TEMPLATE_DIR && + + git config --global init.templateDir "$(pwd)/tmpl" && + test_must_fail git submodule \ + add "$submodurl" sub-global 2>err && + git config --global --unset init.templateDir && + grep HOOK-RUN err && + test_path_is_file sub-global/hook.run && + + git config init.templateDir "$(pwd)/tmpl" && + git submodule add "$submodurl" sub-local 2>err && + git config --unset init.templateDir && + ! grep HOOK-RUN err && + test_path_is_missing sub-local/hook.run + ) +' + test_done diff -Nru git-2.39.2/t/t7406-submodule-update.sh git-2.39.5/t/t7406-submodule-update.sh --- git-2.39.2/t/t7406-submodule-update.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t7406-submodule-update.sh 2024-05-31 00:35:55.000000000 +0000 @@ -1179,4 +1179,52 @@ test_cmp expect.err actual.err ' +test_expect_success CASE_INSENSITIVE_FS,SYMLINKS \ + 'submodule paths must not follow symlinks' ' + + # This is only needed because we want to run this in a self-contained + # test without having to spin up an HTTP server; However, it would not + # be needed in a real-world scenario where the submodule is simply + # hosted on a public site. + test_config_global protocol.file.allow always && + + # Make sure that Git tries to use symlinks on Windows + test_config_global core.symlinks true && + + tell_tale_path="$PWD/tell.tale" && + git init hook && + ( + cd hook && + mkdir -p y/hooks && + write_script y/hooks/post-checkout <<-EOF && + echo HOOK-RUN >&2 + echo hook-run >"$tell_tale_path" + EOF + git add y/hooks/post-checkout && + test_tick && + git commit -m post-checkout + ) && + + hook_repo_path="$(pwd)/hook" && + git init captain && + ( + cd captain && + git submodule add --name x/y "$hook_repo_path" A/modules/x && + test_tick && + git commit -m add-submodule && + + printf .git >dotgit.txt && + git hash-object -w --stdin dot-git.hash && + printf "120000 %s 0\ta\n" "$(cat dot-git.hash)" >index.info && + git update-index --index-info err && + ! grep HOOK-RUN err && + test_path_is_missing "$tell_tale_path" +' + test_done diff -Nru git-2.39.2/t/t7423-submodule-symlinks.sh git-2.39.5/t/t7423-submodule-symlinks.sh --- git-2.39.2/t/t7423-submodule-symlinks.sh 1970-01-01 00:00:00.000000000 +0000 +++ git-2.39.5/t/t7423-submodule-symlinks.sh 2024-05-31 00:35:55.000000000 +0000 @@ -0,0 +1,67 @@ +#!/bin/sh + +test_description='check that submodule operations do not follow symlinks' + +. ./test-lib.sh + +test_expect_success 'prepare' ' + git config --global protocol.file.allow always && + test_commit initial && + git init upstream && + test_commit -C upstream upstream submodule_file && + git submodule add ./upstream a/sm && + test_tick && + git commit -m submodule +' + +test_expect_success SYMLINKS 'git submodule update must not create submodule behind symlink' ' + rm -rf a b && + mkdir b && + ln -s b a && + test_path_is_missing b/sm && + test_must_fail git submodule update && + test_path_is_missing b/sm +' + +test_expect_success SYMLINKS,CASE_INSENSITIVE_FS 'git submodule update must not create submodule behind symlink on case insensitive fs' ' + rm -rf a b && + mkdir b && + ln -s b A && + test_must_fail git submodule update && + test_path_is_missing b/sm +' + +prepare_symlink_to_repo() { + rm -rf a && + mkdir a && + git init a/target && + git -C a/target fetch ../../upstream && + ln -s target a/sm +} + +test_expect_success SYMLINKS 'git restore --recurse-submodules must not be confused by a symlink' ' + prepare_symlink_to_repo && + test_must_fail git restore --recurse-submodules a/sm && + test_path_is_missing a/sm/submodule_file && + test_path_is_dir a/target/.git && + test_path_is_missing a/target/submodule_file +' + +test_expect_success SYMLINKS 'git restore --recurse-submodules must not migrate git dir of symlinked repo' ' + prepare_symlink_to_repo && + rm -rf .git/modules && + test_must_fail git restore --recurse-submodules a/sm && + test_path_is_dir a/target/.git && + test_path_is_missing .git/modules/a/sm && + test_path_is_missing a/target/submodule_file +' + +test_expect_success SYMLINKS 'git checkout -f --recurse-submodules must not migrate git dir of symlinked repo when removing submodule' ' + prepare_symlink_to_repo && + rm -rf .git/modules && + test_must_fail git checkout -f --recurse-submodules initial && + test_path_is_dir a/target/.git && + test_path_is_missing .git/modules/a/sm +' + +test_done diff -Nru git-2.39.2/t/t7450-bad-git-dotfiles.sh git-2.39.5/t/t7450-bad-git-dotfiles.sh --- git-2.39.2/t/t7450-bad-git-dotfiles.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t7450-bad-git-dotfiles.sh 2024-05-31 00:35:55.000000000 +0000 @@ -292,7 +292,7 @@ fi ' -test_expect_success 'git dirs of sibling submodules must not be nested' ' +test_expect_success 'setup submodules with nested git dirs' ' git init nested && test_commit -C nested nested && ( @@ -310,9 +310,39 @@ git add .gitmodules thing1 thing2 && test_tick && git commit -m nested - ) && + ) +' + +test_expect_success 'git dirs of sibling submodules must not be nested' ' test_must_fail git clone --recurse-submodules nested clone 2>err && test_i18ngrep "is inside git dir" err ' +test_expect_success 'submodule git dir nesting detection must work with parallel cloning' ' + test_must_fail git clone --recurse-submodules --jobs=2 nested clone_parallel 2>err && + cat err && + grep -E "(already exists|is inside git dir|not a git repository)" err && + { + test_path_is_missing .git/modules/hippo/HEAD || + test_path_is_missing .git/modules/hippo/hooks/HEAD + } +' + +test_expect_success 'checkout -f --recurse-submodules must not use a nested gitdir' ' + git clone nested nested_checkout && + ( + cd nested_checkout && + git submodule init && + git submodule update thing1 && + mkdir -p .git/modules/hippo/hooks/refs && + mkdir -p .git/modules/hippo/hooks/objects/info && + echo "../../../../objects" >.git/modules/hippo/hooks/objects/info/alternates && + echo "ref: refs/heads/master" >.git/modules/hippo/hooks/HEAD + ) && + test_must_fail git -C nested_checkout checkout -f --recurse-submodules HEAD 2>err && + cat err && + grep "is inside git dir" err && + test_path_is_missing nested_checkout/thing2/.git +' + test_done diff -Nru git-2.39.2/t/t7600-merge.sh git-2.39.5/t/t7600-merge.sh --- git-2.39.2/t/t7600-merge.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t7600-merge.sh 2024-05-31 00:35:55.000000000 +0000 @@ -105,7 +105,7 @@ test_write_lines "$@" >mergehead.expected && while read sha1 rest do - git rev-parse $sha1 + git rev-parse $sha1 || return 1 done <.git/MERGE_HEAD >mergehead.actual && test_cmp mergehead.expected mergehead.actual } diff -Nru git-2.39.2/t/t9001-send-email.sh git-2.39.5/t/t9001-send-email.sh --- git-2.39.2/t/t9001-send-email.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/t9001-send-email.sh 2024-05-31 00:35:55.000000000 +0000 @@ -337,13 +337,14 @@ test_expect_success $PREREQ 'Prompting works' ' clean_fake_sendmail && (echo "to@example.com" && - echo "" + echo "my-message-id@example.com" ) | GIT_SEND_EMAIL_NOTTY=1 git send-email \ --smtp-server="$(pwd)/fake.sendmail" \ $patches \ 2>errors && grep "^From: A U Thor \$" msgtxt1 && - grep "^To: to@example.com\$" msgtxt1 + grep "^To: to@example.com\$" msgtxt1 && + grep "^In-Reply-To: " msgtxt1 ' test_expect_success $PREREQ,AUTOIDENT 'implicit ident is allowed' ' diff -Nru git-2.39.2/t/test-lib.sh git-2.39.5/t/test-lib.sh --- git-2.39.2/t/test-lib.sh 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/t/test-lib.sh 2024-05-31 00:35:55.000000000 +0000 @@ -334,6 +334,7 @@ find "$TEST_RESULTS_SAN_DIR" \ -type f \ -name "$TEST_RESULTS_SAN_FILE_PFX.*" 2>/dev/null | + xargs grep -lv "Unable to get registers from thread" | wc -l } diff -Nru git-2.39.2/unpack-trees.c git-2.39.5/unpack-trees.c --- git-2.39.2/unpack-trees.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/unpack-trees.c 2024-05-31 00:35:55.000000000 +0000 @@ -19,7 +19,6 @@ #include "promisor-remote.h" #include "entry.h" #include "parallel-checkout.h" -#include "sparse-index.h" /* * Error messages expected by scripts out of plumbing commands such as diff -Nru git-2.39.2/userdiff.c git-2.39.5/userdiff.c --- git-2.39.2/userdiff.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/userdiff.c 2024-05-31 00:35:55.000000000 +0000 @@ -315,7 +315,8 @@ }; static int userdiff_find_by_namelen_cb(struct userdiff_driver *driver, - enum userdiff_driver_type type, void *priv) + enum userdiff_driver_type type UNUSED, + void *priv) { struct find_by_namelen_data *cb_data = priv; diff -Nru git-2.39.2/version git-2.39.5/version --- git-2.39.2/version 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/version 2024-05-31 00:35:55.000000000 +0000 @@ -1 +1 @@ -2.39.2 +2.39.5 diff -Nru git-2.39.2/ws.c git-2.39.5/ws.c --- git-2.39.2/ws.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/ws.c 2024-05-31 00:35:55.000000000 +0000 @@ -252,7 +252,7 @@ return ws_check_emit_1(line, len, ws_rule, NULL, NULL, NULL, NULL); } -int ws_blank_line(const char *line, int len, unsigned ws_rule) +int ws_blank_line(const char *line, int len) { /* * We _might_ want to treat CR differently from other diff -Nru git-2.39.2/wt-status.c git-2.39.5/wt-status.c --- git-2.39.2/wt-status.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/wt-status.c 2024-05-31 00:35:55.000000000 +0000 @@ -438,7 +438,7 @@ } static void wt_status_collect_changed_cb(struct diff_queue_struct *q, - struct diff_options *options, + struct diff_options *options UNUSED, void *data) { struct wt_status *s = data; @@ -525,7 +525,7 @@ } static void wt_status_collect_updated_cb(struct diff_queue_struct *q, - struct diff_options *options, + struct diff_options *options UNUSED, void *data) { struct wt_status *s = data; diff -Nru git-2.39.2/xdiff/xdiffi.c git-2.39.5/xdiff/xdiffi.c --- git-2.39.2/xdiff/xdiffi.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/xdiff/xdiffi.c 2024-05-31 00:35:55.000000000 +0000 @@ -973,7 +973,7 @@ } } -static int xdl_call_hunk_func(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, +static int xdl_call_hunk_func(xdfenv_t *xe UNUSED, xdchange_t *xscr, xdemitcb_t *ecb, xdemitconf_t const *xecfg) { xdchange_t *xch, *xche; diff -Nru git-2.39.2/xdiff/xemit.c git-2.39.5/xdiff/xemit.c --- git-2.39.2/xdiff/xemit.c 2023-02-07 22:45:28.000000000 +0000 +++ git-2.39.5/xdiff/xemit.c 2024-05-31 00:35:55.000000000 +0000 @@ -95,7 +95,7 @@ } -static long def_ff(const char *rec, long len, char *buf, long sz, void *priv) +static long def_ff(const char *rec, long len, char *buf, long sz) { if (len > 0 && (isalpha((unsigned char)*rec) || /* identifier? */ @@ -117,7 +117,7 @@ const char *rec; long len = xdl_get_rec(xdf, ri, &rec); if (!xecfg->find_func) - return def_ff(rec, len, buf, sz, xecfg->find_func_priv); + return def_ff(rec, len, buf, sz); return xecfg->find_func(rec, len, buf, sz, xecfg->find_func_priv); }