aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/check-whitespace.yml63
-rw-r--r--.github/workflows/l10n.yml6
-rw-r--r--.github/workflows/main.yml48
-rw-r--r--.gitignore2
-rw-r--r--Documentation/RelNotes/2.30.7.txt86
-rw-r--r--Documentation/RelNotes/2.31.6.txt5
-rw-r--r--Documentation/RelNotes/2.32.5.txt8
-rw-r--r--Documentation/RelNotes/2.33.6.txt5
-rw-r--r--Documentation/RelNotes/2.34.6.txt5
-rw-r--r--Documentation/RelNotes/2.35.6.txt5
-rw-r--r--Documentation/RelNotes/2.36.4.txt5
-rw-r--r--Documentation/RelNotes/2.37.5.txt5
-rw-r--r--Documentation/RelNotes/2.38.3.txt5
-rw-r--r--Documentation/RelNotes/2.39.1.txt5
-rw-r--r--Documentation/RelNotes/2.40.0.txt179
-rw-r--r--Documentation/config/feature.txt5
-rw-r--r--Documentation/config/format.txt4
-rw-r--r--Documentation/config/index.txt11
-rw-r--r--Documentation/config/transfer.txt6
-rw-r--r--Documentation/diff-generate-patch.txt1
-rw-r--r--Documentation/diff-options.txt8
-rw-r--r--Documentation/fsck-msgids.txt12
-rw-r--r--Documentation/git-am.txt8
-rw-r--r--Documentation/git-bisect-lk2009.txt4
-rw-r--r--Documentation/git-branch.txt2
-rw-r--r--Documentation/git-cat-file.txt53
-rw-r--r--Documentation/git-check-attr.txt9
-rw-r--r--Documentation/git-checkout.txt6
-rw-r--r--Documentation/git-cherry-pick.txt2
-rw-r--r--Documentation/git-fetch.txt8
-rw-r--r--Documentation/git-merge-tree.txt16
-rw-r--r--Documentation/git-merge.txt3
-rw-r--r--Documentation/git-rebase.txt7
-rw-r--r--Documentation/git-reset.txt3
-rw-r--r--Documentation/git-status.txt60
-rw-r--r--Documentation/git-var.txt11
-rw-r--r--Documentation/git.txt8
-rw-r--r--Documentation/gitattributes.txt2
-rw-r--r--Documentation/githooks.txt12
-rw-r--r--Documentation/gitprotocol-v2.txt201
-rw-r--r--Documentation/revisions.txt3
-rwxr-xr-xGIT-VERSION-GEN2
-rw-r--r--INSTALL2
-rw-r--r--Makefile15
l---------RelNotes2
-rw-r--r--add-interactive.c2
-rw-r--r--apply.c6
-rw-r--r--archive.c2
-rw-r--r--attr.c191
-rw-r--r--attr.h18
-rw-r--r--bisect.c3
-rw-r--r--blob.c3
-rw-r--r--blob.h3
-rw-r--r--builtin.h6
-rw-r--r--builtin/add.c4
-rw-r--r--builtin/am.c22
-rw-r--r--builtin/bisect.c (renamed from builtin/bisect--helper.c)174
-rw-r--r--builtin/branch.c6
-rw-r--r--builtin/bugreport.c9
-rw-r--r--builtin/bundle.c9
-rw-r--r--builtin/cat-file.c28
-rw-r--r--builtin/check-attr.c35
-rw-r--r--builtin/checkout.c6
-rw-r--r--builtin/clone.c21
-rw-r--r--builtin/commit.c13
-rw-r--r--builtin/config.c42
-rw-r--r--builtin/diff.c2
-rw-r--r--builtin/difftool.c4
-rw-r--r--builtin/fast-export.c2
-rw-r--r--builtin/fsmonitor--daemon.c6
-rw-r--r--builtin/log.c8
-rw-r--r--builtin/ls-files.c1
-rw-r--r--builtin/ls-tree.c268
-rw-r--r--builtin/merge-tree.c67
-rw-r--r--builtin/merge.c5
-rw-r--r--builtin/pack-objects.c29
-rw-r--r--builtin/range-diff.c2
-rw-r--r--builtin/read-tree.c1
-rw-r--r--builtin/rebase.c47
-rw-r--r--builtin/remote-ext.c6
-rw-r--r--builtin/remote-fd.c2
-rw-r--r--builtin/repack.c2
-rw-r--r--builtin/rerere.c2
-rw-r--r--builtin/reset.c5
-rw-r--r--builtin/rev-parse.c1
-rw-r--r--builtin/revert.c4
-rw-r--r--builtin/rm.c2
-rw-r--r--builtin/sparse-checkout.c1
-rw-r--r--builtin/stash.c18
-rw-r--r--builtin/submodule--helper.c94
-rw-r--r--builtin/unpack-file.c1
-rw-r--r--builtin/var.c33
-rw-r--r--builtin/worktree.c9
-rw-r--r--bundle-uri.c87
-rw-r--r--bundle-uri.h35
-rw-r--r--cache-tree.c2
-rw-r--r--cache.h17
-rwxr-xr-xci/lib.sh3
-rw-r--r--column.c2
-rw-r--r--combine-diff.c2
-rw-r--r--commit-graph.c3
-rw-r--r--commit-reach.c3
-rw-r--r--commit.c21
-rw-r--r--compat/fsmonitor/fsm-darwin-gcc.h4
-rw-r--r--compat/fsmonitor/fsm-listen-darwin.c35
-rw-r--r--compat/mingw.c12
-rw-r--r--compat/win32/pthread.h2
-rw-r--r--config.c2
-rw-r--r--connect.c65
-rw-r--r--connect.h3
-rw-r--r--connected.c6
-rw-r--r--contrib/coccinelle/array.cocci7
-rw-r--r--contrib/completion/git-completion.bash26
-rw-r--r--contrib/git-jump/README10
-rwxr-xr-xcontrib/git-jump/git-jump45
-rw-r--r--convert.c2
-rw-r--r--csum-file.c14
-rw-r--r--csum-file.h7
-rw-r--r--date.c37
-rw-r--r--diff-lib.c2
-rw-r--r--diff-no-index.c3
-rw-r--r--diff.c69
-rw-r--r--diff.h2
-rw-r--r--dir.c17
-rw-r--r--dir.h1
-rw-r--r--entry.c12
-rw-r--r--entry.h6
-rw-r--r--environment.c13
-rw-r--r--fetch-pack.c12
-rw-r--r--fsck.c137
-rw-r--r--fsck.h12
-rwxr-xr-xgit-bisect.sh67
-rw-r--r--git-compat-util.h40
-rw-r--r--git-curl-compat.h8
-rwxr-xr-xgit-submodule.sh3
-rw-r--r--git.c44
-rw-r--r--help.c2
-rw-r--r--http-fetch.c3
-rw-r--r--http-push.c6
-rw-r--r--http.c79
-rw-r--r--http.h2
-rw-r--r--line-range.c7
-rw-r--r--list-objects-filter-options.c4
-rw-r--r--list-objects-filter-options.h18
-rw-r--r--list-objects-filter.c31
-rw-r--r--list-objects.c33
-rw-r--r--ll-merge.c4
-rw-r--r--ls-refs.c5
-rw-r--r--merge-recursive.c2
-rw-r--r--object-file.c159
-rw-r--r--object-store.h25
-rw-r--r--object.c5
-rw-r--r--pack-bitmap.c39
-rw-r--r--pack-write.c1
-rw-r--r--packfile.c26
-rw-r--r--parse-options.c3
-rw-r--r--parse-options.h4
-rw-r--r--pathspec.c8
-rw-r--r--pretty.c63
-rw-r--r--range-diff.c12
-rw-r--r--read-cache.c62
-rw-r--r--ref-filter.c52
-rw-r--r--reflog.c4
-rw-r--r--refs.c9
-rw-r--r--refs.h6
-rw-r--r--refs/packed-backend.c3
-rw-r--r--remote-curl.c28
-rw-r--r--remote.h5
-rw-r--r--repo-settings.c2
-rw-r--r--repository.c6
-rw-r--r--repository.h1
-rw-r--r--revision.c28
-rw-r--r--run-command.c4
-rw-r--r--scalar.c1
-rw-r--r--sequencer.c6
-rw-r--r--serve.c6
-rw-r--r--sparse-index.c6
-rw-r--r--split-index.c3
-rw-r--r--strbuf.c6
-rw-r--r--strbuf.h11
-rw-r--r--streaming.c11
-rw-r--r--submodule.c52
-rw-r--r--submodule.h8
-rw-r--r--t/helper/test-bundle-uri.c41
-rw-r--r--t/helper/test-env-helper.c (renamed from builtin/env--helper.c)24
-rw-r--r--t/helper/test-fake-ssh.c1
-rw-r--r--t/helper/test-tool.c1
-rw-r--r--t/helper/test-tool.h1
-rw-r--r--t/interop/interop-lib.sh2
-rw-r--r--t/lib-bundle-uri-protocol.sh216
-rwxr-xr-xt/t0000-basic.sh7
-rwxr-xr-xt/t0003-attributes.sh107
-rwxr-xr-xt/t0006-date.sh8
-rwxr-xr-xt/t0007-git-var.sh100
-rwxr-xr-xt/t0017-env-helper.sh62
-rwxr-xr-xt/t0021-conversion.sh4
-rwxr-xr-xt/t0068-for-each-repo.sh1
-rwxr-xr-xt/t0070-fundamental.sh1
-rwxr-xr-xt/t1001-read-tree-m-2way.sh2
-rwxr-xr-xt/t1011-read-tree-sparse-checkout.sh1
-rwxr-xr-xt/t1022-read-tree-partial-clone.sh2
-rwxr-xr-xt/t1091-sparse-checkout-builtin.sh11
-rwxr-xr-xt/t1301-shared-repo.sh14
-rwxr-xr-xt/t1302-repo-version.sh2
-rwxr-xr-xt/t1404-update-ref-errors.sh2
-rwxr-xr-xt/t1409-avoid-packing-refs.sh1
-rwxr-xr-xt/t1413-reflog-detach.sh1
-rwxr-xr-xt/t1450-fsck.sh24
-rwxr-xr-xt/t1500-rev-parse.sh2
-rwxr-xr-xt/t1501-work-tree.sh2
-rwxr-xr-xt/t1509-root-work-tree.sh10
-rwxr-xr-xt/t1600-index.sh30
-rwxr-xr-xt/t2012-checkout-last.sh1
-rwxr-xr-xt/t2018-checkout-branch.sh1
-rwxr-xr-xt/t2025-checkout-no-overlay.sh1
-rwxr-xr-xt/t3009-ls-files-others-nonsubmodule.sh1
-rwxr-xr-xt/t3010-ls-files-killed-modified.sh2
-rwxr-xr-xt/t3050-subprojects-fetch.sh1
-rwxr-xr-xt/t3060-ls-files-with-tree.sh2
-rwxr-xr-xt/t3104-ls-tree-format.sh7
-rwxr-xr-xt/t3204-branch-name-interpretation.sh10
-rwxr-xr-xt/t3409-rebase-environ.sh1
-rwxr-xr-xt/t3413-rebase-hook.sh1
-rwxr-xr-xt/t3428-rebase-signoff.sh1
-rwxr-xr-xt/t3429-rebase-edit-todo.sh1
-rwxr-xr-xt/t3433-rebase-across-mode-change.sh1
-rwxr-xr-xt/t3920-crlf-messages.sh2
-rwxr-xr-xt/t4014-format-patch.sh6
-rwxr-xr-xt/t4015-diff-whitespace.sh4
-rwxr-xr-xt/t4023-diff-rename-typechange.sh12
-rwxr-xr-xt/t4044-diff-index-unique-abbrev.sh4
-rwxr-xr-xt/t4045-diff-relative.sh31
-rwxr-xr-xt/t4046-diff-unmerged.sh10
-rwxr-xr-xt/t4052-stat-output.sh1
-rwxr-xr-xt/t4053-diff-no-index.sh1
-rwxr-xr-xt/t4067-diff-partial-clone.sh1
-rwxr-xr-xt/t4111-apply-subdir.sh1
-rwxr-xr-xt/t4135-apply-weird-filenames.sh1
-rwxr-xr-xt/t4150-am.sh34
-rwxr-xr-xt/t4203-mailmap.sh65
-rwxr-xr-xt/t4205-log-pretty-formats.sh78
-rwxr-xr-xt/t4211-line-log.sh22
-rwxr-xr-xt/t4213-log-tabexpand.sh1
-rwxr-xr-xt/t4301-merge-tree-write-tree.sh66
-rwxr-xr-xt/t5310-pack-bitmaps.sh5
-rwxr-xr-xt/t5313-pack-bounds-checks.sh2
-rwxr-xr-xt/t5314-pack-cycle-detection.sh17
-rwxr-xr-xt/t5317-pack-objects-filter-objects.sh90
-rwxr-xr-xt/t5544-pack-objects-hook.sh2
-rwxr-xr-xt/t5554-noop-fetch-negotiator.sh2
-rwxr-xr-xt/t5601-clone.sh59
-rwxr-xr-xt/t5610-clone-detached.sh1
-rwxr-xr-xt/t5611-clone-config.sh1
-rwxr-xr-xt/t5614-clone-submodules-shallow.sh1
-rwxr-xr-xt/t5616-partial-clone.sh43
-rwxr-xr-xt/t5617-clone-submodules-remote.sh1
-rwxr-xr-xt/t5618-alternate-refs.sh2
-rwxr-xr-xt/t5701-git-serve.sh40
-rwxr-xr-xt/t5730-protocol-v2-bundle-uri-file.sh17
-rwxr-xr-xt/t5731-protocol-v2-bundle-uri-git.sh17
-rwxr-xr-xt/t5732-protocol-v2-bundle-uri-http.sh17
-rwxr-xr-xt/t5750-bundle-uri-parse.sh82
-rwxr-xr-xt/t6003-rev-list-topo-order.sh23
-rwxr-xr-xt/t6020-bundle-misc.sh7
-rwxr-xr-xt/t6030-bisect-porcelain.sh169
-rwxr-xr-xt/t6060-merge-index.sh2
-rwxr-xr-xt/t6300-for-each-ref.sh18
-rwxr-xr-xt/t6301-for-each-ref-errors.sh1
-rwxr-xr-xt/t6401-merge-criss-cross.sh2
-rwxr-xr-xt/t6406-merge-attr.sh1
-rwxr-xr-xt/t6407-merge-binary.sh1
-rwxr-xr-xt/t6415-merge-dir-to-symlink.sh1
-rwxr-xr-xt/t6421-merge-partial-clone.sh4
-rwxr-xr-xt/t6422-merge-rename-corner-cases.sh2
-rwxr-xr-xt/t6426-merge-skip-unneeded-updates.sh58
-rwxr-xr-xt/t6435-merge-sparse.sh1
-rwxr-xr-xt/t7103-reset-bare.sh2
-rwxr-xr-xt/t7412-submodule-absorbgitdirs.sh64
-rwxr-xr-xt/t7504-commit-msg-hook.sh1
-rwxr-xr-xt/t7508-status.sh70
-rwxr-xr-xt/t7517-per-repo-email.sh1
-rwxr-xr-xt/t7520-ignored-hook-warning.sh1
-rwxr-xr-xt/t7527-builtin-fsmonitor.sh44
-rwxr-xr-xt/t7600-merge.sh2
-rwxr-xr-xt/t7605-merge-resolve.sh1
-rwxr-xr-xt/t7614-merge-signoff.sh1
-rwxr-xr-xt/t9003-help-autocorrect.sh8
-rwxr-xr-xt/t9115-git-svn-dcommit-funky-renames.sh1
-rwxr-xr-xt/t9119-git-svn-info.sh2
-rwxr-xr-xt/t9146-git-svn-empty-dirs.sh1
-rwxr-xr-xt/t9148-git-svn-propset.sh1
-rwxr-xr-xt/t9160-git-svn-preserve-empty-dirs.sh1
-rwxr-xr-xt/t9902-completion.sh30
-rw-r--r--t/test-lib-functions.sh85
-rw-r--r--t/test-lib.sh8
-rw-r--r--transport-helper.c13
-rw-r--r--transport-internal.h7
-rw-r--r--transport.c87
-rw-r--r--transport.h19
-rw-r--r--unpack-trees.c30
-rw-r--r--unpack-trees.h1
-rw-r--r--urlmatch.c6
-rw-r--r--userdiff.c5
-rw-r--r--utf8.c77
-rw-r--r--utf8.h2
-rw-r--r--ws.c11
-rw-r--r--wt-status.c32
-rw-r--r--xdiff/xdiffi.c2
-rw-r--r--xdiff/xemit.c4
309 files changed, 4670 insertions, 1594 deletions
diff --git a/.github/workflows/check-whitespace.yml b/.github/workflows/check-whitespace.yml
index ad3466ad16..a58e2dc8ad 100644
--- a/.github/workflows/check-whitespace.yml
+++ b/.github/workflows/check-whitespace.yml
@@ -9,42 +9,83 @@ on:
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@v3
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 --git a/.github/workflows/l10n.yml b/.github/workflows/l10n.yml
index f7ea0f00a4..6c3849658a 100644
--- a/.github/workflows/l10n.yml
+++ b/.github/workflows/l10n.yml
@@ -2,6 +2,12 @@ name: git-l10n
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 --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index e67847a682..30492eacdd 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -11,6 +11,7 @@ jobs:
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,7 +35,15 @@ jobs:
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
@@ -82,6 +91,9 @@ jobs:
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: git-for-windows/setup-git-for-windows-sdk@v1
@@ -101,11 +113,14 @@ jobs:
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
@@ -132,11 +147,14 @@ jobs:
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: git-for-windows/setup-git-for-windows-sdk@v1
@@ -184,11 +202,14 @@ jobs:
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
@@ -218,6 +239,9 @@ jobs:
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:
@@ -265,8 +289,9 @@ jobs:
- uses: actions/checkout@v3
- run: ci/install-dependencies.sh
- run: ci/run-build-and-tests.sh
- - run: ci/print-test-failures.sh
+ - name: print test failures
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+ run: ci/print-test-failures.sh
- name: Upload failed tests' directories
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
uses: actions/upload-artifact@v3
@@ -277,6 +302,9 @@ jobs:
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:
@@ -298,8 +326,9 @@ jobs:
if: matrix.vector.jobname == 'linux32'
- run: ci/install-docker-dependencies.sh
- run: ci/run-build-and-tests.sh
- - run: ci/print-test-failures.sh
+ - name: print test failures
if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+ run: ci/print-test-failures.sh
- name: Upload failed tests' directories
if: failure() && env.FAILED_TEST_ARTIFACTS != '' && matrix.vector.jobname != 'linux32'
uses: actions/upload-artifact@v3
@@ -318,6 +347,9 @@ jobs:
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
- run: ci/install-dependencies.sh
@@ -329,6 +361,9 @@ jobs:
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
@@ -347,6 +382,9 @@ jobs:
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
diff --git a/.gitignore b/.gitignore
index 0832f1da77..6782f3ceca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,7 +21,6 @@
/git-archimport
/git-archive
/git-bisect
-/git-bisect--helper
/git-blame
/git-branch
/git-bugreport
@@ -60,7 +59,6 @@
/git-difftool
/git-difftool--helper
/git-describe
-/git-env--helper
/git-fast-export
/git-fast-import
/git-fetch
diff --git a/Documentation/RelNotes/2.30.7.txt b/Documentation/RelNotes/2.30.7.txt
new file mode 100644
index 0000000000..285beed232
--- /dev/null
+++ b/Documentation/RelNotes/2.30.7.txt
@@ -0,0 +1,86 @@
+Git v2.30.7 Release Notes
+=========================
+
+This release addresses the security issues CVE-2022-41903 and
+CVE-2022-23521.
+
+
+Fixes since v2.30.6
+-------------------
+
+ * CVE-2022-41903:
+
+ git log has the ability to display commits using an arbitrary
+ format with its --format specifiers. This functionality is also
+ exposed to git archive via the export-subst gitattribute.
+
+ When processing the padding operators (e.g., %<(, %<|(, %>(,
+ %>>(, or %><( ), an integer overflow can occur in
+ pretty.c::format_and_pad_commit() where a size_t is improperly
+ stored as an int, and then added as an offset to a subsequent
+ memcpy() call.
+
+ This overflow can be triggered directly by a user running a
+ command which invokes the commit formatting machinery (e.g., git
+ log --format=...). It may also be triggered indirectly through
+ git archive via the export-subst mechanism, which expands format
+ specifiers inside of files within the repository during a git
+ archive.
+
+ This integer overflow can result in arbitrary heap writes, which
+ may result in remote code execution.
+
+* CVE-2022-23521:
+
+ gitattributes are a mechanism to allow defining attributes for
+ paths. These attributes can be defined by adding a `.gitattributes`
+ file to the repository, which contains a set of file patterns and
+ the attributes that should be set for paths matching this pattern.
+
+ When parsing gitattributes, multiple integer overflows can occur
+ when there is a huge number of path patterns, a huge number of
+ attributes for a single pattern, or when the declared attribute
+ names are huge.
+
+ These overflows can be triggered via a crafted `.gitattributes` file
+ that may be part of the commit history. Git silently splits lines
+ longer than 2KB when parsing gitattributes from a file, but not when
+ parsing them from the index. Consequentially, the failure mode
+ depends on whether the file exists in the working tree, the index or
+ both.
+
+ This integer overflow can result in arbitrary heap reads and writes,
+ which may result in remote code execution.
+
+Credit for finding CVE-2022-41903 goes to Joern Schneeweisz of GitLab.
+An initial fix was authored by Markus Vervier of X41 D-Sec. Credit for
+finding CVE-2022-23521 goes to Markus Vervier and Eric Sesterhenn of X41
+D-Sec. This work was sponsored by OSTIF.
+
+The proposed fixes have been polished and extended to cover additional
+findings by Patrick Steinhardt of GitLab, with help from others on the
+Git security mailing list.
+
+Patrick Steinhardt (21):
+ attr: fix overflow when upserting attribute with overly long name
+ attr: fix out-of-bounds read with huge attribute names
+ attr: fix integer overflow when parsing huge attribute names
+ attr: fix out-of-bounds write when parsing huge number of attributes
+ attr: fix out-of-bounds read with unreasonable amount of patterns
+ attr: fix integer overflow with more than INT_MAX macros
+ attr: harden allocation against integer overflows
+ attr: fix silently splitting up lines longer than 2048 bytes
+ attr: ignore attribute lines exceeding 2048 bytes
+ attr: ignore overly large gitattributes files
+ pretty: fix out-of-bounds write caused by integer overflow
+ pretty: fix out-of-bounds read when left-flushing with stealing
+ pretty: fix out-of-bounds read when parsing invalid padding format
+ pretty: fix adding linefeed when placeholder is not expanded
+ pretty: fix integer overflow in wrapping format
+ utf8: fix truncated string lengths in `utf8_strnwidth()`
+ utf8: fix returning negative string width
+ utf8: fix overflow when returning string width
+ utf8: fix checking for glyph width in `strbuf_utf8_replace()`
+ utf8: refactor `strbuf_utf8_replace` to not rely on preallocated buffer
+ pretty: restrict input lengths for padding and wrapping formats
+
diff --git a/Documentation/RelNotes/2.31.6.txt b/Documentation/RelNotes/2.31.6.txt
new file mode 100644
index 0000000000..425a51875a
--- /dev/null
+++ b/Documentation/RelNotes/2.31.6.txt
@@ -0,0 +1,5 @@
+Git v2.31.6 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.7; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.32.5.txt b/Documentation/RelNotes/2.32.5.txt
new file mode 100644
index 0000000000..a8cad1a05b
--- /dev/null
+++ b/Documentation/RelNotes/2.32.5.txt
@@ -0,0 +1,8 @@
+Git v2.32.5 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.7; see
+the release notes for that version for details.
+
+In addition, included are additional code for "git fsck" to check
+for questionable .gitattributes files.
diff --git a/Documentation/RelNotes/2.33.6.txt b/Documentation/RelNotes/2.33.6.txt
new file mode 100644
index 0000000000..b63e4e6256
--- /dev/null
+++ b/Documentation/RelNotes/2.33.6.txt
@@ -0,0 +1,5 @@
+Git v2.33.6 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.7; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.34.6.txt b/Documentation/RelNotes/2.34.6.txt
new file mode 100644
index 0000000000..b32080dba8
--- /dev/null
+++ b/Documentation/RelNotes/2.34.6.txt
@@ -0,0 +1,5 @@
+Git v2.34.6 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.7; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.35.6.txt b/Documentation/RelNotes/2.35.6.txt
new file mode 100644
index 0000000000..e7ca57bb41
--- /dev/null
+++ b/Documentation/RelNotes/2.35.6.txt
@@ -0,0 +1,5 @@
+Git v2.35.6 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.7; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.36.4.txt b/Documentation/RelNotes/2.36.4.txt
new file mode 100644
index 0000000000..58fb93a35f
--- /dev/null
+++ b/Documentation/RelNotes/2.36.4.txt
@@ -0,0 +1,5 @@
+Git v2.36.4 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.7; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.37.5.txt b/Documentation/RelNotes/2.37.5.txt
new file mode 100644
index 0000000000..faa1447292
--- /dev/null
+++ b/Documentation/RelNotes/2.37.5.txt
@@ -0,0 +1,5 @@
+Git v2.37.5 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.7; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.38.3.txt b/Documentation/RelNotes/2.38.3.txt
new file mode 100644
index 0000000000..4a46bb4300
--- /dev/null
+++ b/Documentation/RelNotes/2.38.3.txt
@@ -0,0 +1,5 @@
+Git v2.38.3 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.7; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.39.1.txt b/Documentation/RelNotes/2.39.1.txt
new file mode 100644
index 0000000000..60c86f4122
--- /dev/null
+++ b/Documentation/RelNotes/2.39.1.txt
@@ -0,0 +1,5 @@
+Git v2.39.1 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.7; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.40.0.txt b/Documentation/RelNotes/2.40.0.txt
new file mode 100644
index 0000000000..629d3c6980
--- /dev/null
+++ b/Documentation/RelNotes/2.40.0.txt
@@ -0,0 +1,179 @@
+Git v2.40 Release Notes
+=======================
+
+UI, Workflows & Features
+
+ * "merge-tree" learns a new `--merge-base` option.
+
+ * "git jump" (in contrib/) learned to present the "quickfix list" to
+ its standard output (instead of letting it consumed by the editor
+ it invokes), and learned to also drive emacs/emacsclient.
+
+ * "git var UNKNOWN_VARIABLE" and "git var VARIABLE" with the variable
+ given an empty value used to behave identically. Now the latter
+ just gives an empty output, while the former still gives an error
+ message.
+
+ * Introduce a case insensitive mode to the Bash completion helpers.
+
+ * The advice message given by "git status" when it takes long time to
+ enumerate untracked paths has been updated.
+
+ * Just like "git var GIT_EDITOR" abstracts the complex logic to
+ choose which editor gets used behind it, "git var" now give support
+ to GIT_SEQUENCE_EDITOR.
+
+ * "git format-patch" learned to honor format.mboxrd even when sending
+ patches to the standard output stream,
+
+ * 'cat-file' gains mailmap support for its '--batch-check' and '-s'
+ options.
+
+ * Conditionally skip the pre-applypatch and applypatch-msg hooks when
+ applying patches with 'git am'.
+
+ * Introduce an optional configuration to allow the trailing hash that
+ protects the index file from bit flipping.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * `git bisect` becomes a builtin.
+
+ * The pack-bitmap machinery is taught to log the paths of redundant
+ bitmap(s) to trace2 instead of stderr.
+
+ * Use the SHA1DC implementation on macOS, just like other platforms,
+ by default.
+
+ * Even in a repository with promisor remote, it is useless to
+ attempt to lazily attempt fetching an object that is expected to be
+ commit, because no "filter" mode omits commit objects. Take
+ advantage of this assumption to fail fast on errors.
+
+ * Stop using "git --super-prefix" and narrow the scope of its use to
+ the submodule--helper.
+
+ * Stop running win+VS build by default.
+ (merge a0da6deeec js/ci-disable-cmake-by-default later to maint).
+
+ * 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.
+ (merge 4542582e59 cw/ci-whitespace later to maint).
+
+ * Use `git diff --no-index` as a test_cmp on Windows.
+
+ We'd probably need to revisit "do we really want to, and have to,
+ lose CRLF vs LF?" later, at which time we may be able to further
+ clean this up by replacing "git diff --no-index" with "diff -u".
+
+ * Avoid unnecessary builds in CI, with settings configured in
+ ci-config.
+ (merge eb5b03a9c0 tb/ci-concurrency later to maint).
+
+
+Fixes since v2.39
+-----------------
+
+ * Various leak fixes.
+ (merge ac95f5d36a ab/various-leak-fixes later to maint).
+
+ * Fix a bug where `pack-objects` would not respect multiple `--filter`
+ arguments when invoked directly.
+ (merge d4f7036887 rs/multi-filter-args later to maint).
+
+ * Make fsmonitor more robust to avoid the flakiness seen in t7527.
+ (merge 6692d45477 jh/t7527-unflake-by-forcing-cookie later to maint).
+
+ * Stop using deprecated macOS API in fsmonitor.
+ (merge b0226007f0 jh/fsmonitor-darwin-modernize later to maint).
+
+ * Redefining system functions for a few functions did not follow our
+ usual "implement git_foo() and #define foo(args) git_foo(args)"
+ pattern, which has broken build for some folks.
+ (merge e1a95b78d8 jk/avoid-redef-system-functions-2.30 later to maint).
+ (merge 395bec6b39 jk/avoid-redef-system-functions later to maint).
+
+ * The way the diff machinery prepares the options array for the
+ parse_options API has been refactored to avoid resource leaks.
+ (merge 189e97bc4b rs/diff-parseopts later to maint).
+
+ * Correct pthread API usage.
+ (merge 786e67611d sx/pthread-error-check-fix later to maint).
+
+ * The code to auto-correct a misspelt subcommand unnecessarily called
+ into git_default_config() from the early config codepath, which was
+ a no-no. This has bee corrected.
+ (merge 0918d08887 sg/help-autocorrect-config-fix later to maint).
+
+ * "git http-fetch" (which is rarely used) forgot to identify itself
+ in the trace2 output.
+ (merge 7abb43cbc8 jt/http-fetch-trace2-report-name later to maint).
+
+ * The output from "git diff --stat" on an unmerged path lost the
+ terminating LF in Git 2.39, which has been corrected.
+ (merge 209d9cb011 pg/diff-stat-unmerged-regression-fix later to maint).
+
+ * "git pull -v --recurse-submodules" attempted to pass "-v" down to
+ underlying "git submodule update", which did not understand the
+ request and barfed, which has been corrected.
+ (merge 6f65f84766 ss/pull-v-recurse-fix later to maint).
+
+ * When given a pattern that matches an empty string at the end of a
+ line, the code to parse the "git diff" line-ranges fell into an
+ infinite loop, which has been corrected.
+ (merge 4e57c88e02 lk/line-range-parsing-fix later to maint).
+
+ * Fix the sequence to fsync $GIT_DIR/packed-refs file that forgot to
+ flush its output to the disk..
+ (merge ce54672f9b ps/fsync-refs-fix later to maint).
+
+ * Fix to a small regression in 2.38 days.
+ (merge 6d5e9e53aa ab/bundle-wo-args later to maint).
+
+ * "git diff --relative" did not mix well with "git diff --ext-diff",
+ which has been corrected.
+ (merge f034bb1cad jk/ext-diff-with-relative later to maint).
+
+ * 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.
+ (merge 5842710dc2 ws/single-file-cone later to maint).
+
+ * Deal with a few deprecation warning from cURL library.
+ (merge 6c065f72b8 jk/curl-avoid-deprecated-api later to maint).
+
+ * Doc update for environment variables set when hooks are invoked.
+ (merge 772f8ff826 es/hooks-and-local-env later to maint).
+
+ * Document ORIG_HEAD a bit more.
+ (merge f1c9243fc5 pb/doc-orig-head later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+ (merge 77e04b2ed4 rs/t4205-do-not-exit-in-test-script later to maint).
+ (merge faebba436e rs/plug-pattern-list-leak-in-lof later to maint).
+ (merge 243caa8982 ab/t5314-avoid-losing-exit-status later to maint).
+ (merge 4d81ce1b99 ab/t7600-avoid-losing-exit-status-of-git later to maint).
+ (merge 5f3bfdc4f3 ab/t4023-avoid-losing-exit-status-of-diff later to maint).
+ (merge 500317ae03 js/t3920-shell-and-or-fix later to maint).
+ (merge 86325d36e6 rs/t3920-crlf-eating-grep-fix later to maint).
+ (merge cfbd173ccb rj/branch-copy-and-rename later to maint).
+ (merge c25d9e529d jk/unused-post-2.39 later to maint).
+ (merge a31cfe3283 jk/server-supports-v2-cleanup later to maint).
+ (merge a658e881c1 rs/am-parse-options-cleanup later to maint).
+ (merge 4cb39fcf19 rs/clear-commit-marks-cleanup later to maint).
+ (merge b07a819c05 rs/reflog-expiry-cleanup later to maint).
+ (merge d422d06167 rs/clarify-error-in-write-loose-object later to maint).
+ (merge 92cb135855 sk/remove-duplicate-includes later to maint).
+ (merge 4eb1ccecd4 dh/mingw-ownership-check-typofix later to maint).
+ (merge f95526419b ar/typofix-gitattributes-doc later to maint).
+ (merge 27875aeec9 km/doc-branch-start-point later to maint).
+ (merge 35c194dc57 es/t1509-root-fixes later to maint).
+ (merge 7b341645e3 pw/ci-print-failure-name-fix later to maint).
+ (merge bcb71d45bf jx/t1301-updates later to maint).
+ (merge ebdc46c242 jc/doc-diff-patch.txt later to maint).
+ (merge a87a20cbb4 ar/test-cleanup later to maint).
+ (merge f5156f1885 ar/bisect-doc-update later to maint).
+ (merge fca2d86c97 jk/interop-error later to maint).
+ (merge cf4936ed74 tl/ls-tree-code-clean-up later to maint).
diff --git a/Documentation/config/feature.txt b/Documentation/config/feature.txt
index 95975e5091..e52bc6b858 100644
--- a/Documentation/config/feature.txt
+++ b/Documentation/config/feature.txt
@@ -23,6 +23,11 @@ feature.manyFiles::
working directory. With many files, commands such as `git status` and
`git checkout` may be slow and these new defaults improve performance:
+
+* `index.skipHash=true` speeds up index writes by not computing a trailing
+ checksum. Note that this will cause Git versions earlier than 2.13.0 to
+ refuse to parse the index and Git versions earlier than 2.40.0 will report
+ a corrupted index during `git fsck`.
++
* `index.version=4` enables path-prefix compression in the index.
+
* `core.untrackedCache=true` enables the untracked cache. This setting assumes
diff --git a/Documentation/config/format.txt b/Documentation/config/format.txt
index c7303d8d9f..3bd78269e2 100644
--- a/Documentation/config/format.txt
+++ b/Documentation/config/format.txt
@@ -139,3 +139,7 @@ For example,
------------
+
will only show notes from `refs/notes/bar`.
+
+format.mboxrd::
+ A boolean value which enables the robust "mboxrd" format when
+ `--stdout` is in use to escape "^>+From " lines.
diff --git a/Documentation/config/index.txt b/Documentation/config/index.txt
index 75f3a2d105..23c7985eb4 100644
--- a/Documentation/config/index.txt
+++ b/Documentation/config/index.txt
@@ -30,3 +30,14 @@ index.version::
Specify the version with which new index files should be
initialized. This does not affect existing repositories.
If `feature.manyFiles` is enabled, then the default is 4.
+
+index.skipHash::
+ When enabled, do not compute the trailing hash for the index file.
+ This accelerates Git commands that manipulate the index, such as
+ `git add`, `git commit`, or `git status`. Instead of storing the
+ checksum, write a trailing set of bytes with value zero, indicating
+ that the computation was skipped.
++
+If you enable `index.skipHash`, then Git clients older than 2.13.0 will
+refuse to parse the index and Git clients older than 2.40.0 will report an
+error during `git fsck`.
diff --git a/Documentation/config/transfer.txt b/Documentation/config/transfer.txt
index 264812cca4..c3ac767d1e 100644
--- a/Documentation/config/transfer.txt
+++ b/Documentation/config/transfer.txt
@@ -115,3 +115,9 @@ transfer.unpackLimit::
transfer.advertiseSID::
Boolean. When true, client and server processes will advertise their
unique session IDs to their remote counterpart. Defaults to false.
+
+transfer.bundleURI::
+ When `true`, local `git clone` commands will request bundle
+ information from the remote server (if advertised) and download
+ bundles before continuing the clone through the Git protocol.
+ Defaults to `false`.
diff --git a/Documentation/diff-generate-patch.txt b/Documentation/diff-generate-patch.txt
index c78063d4f7..546adf79e5 100644
--- a/Documentation/diff-generate-patch.txt
+++ b/Documentation/diff-generate-patch.txt
@@ -1,3 +1,4 @@
+[[generate_patch_text_with_p]]
Generating patch text with -p
-----------------------------
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 3674ac48e9..7d73e976d9 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -22,7 +22,13 @@ ifndef::git-format-patch[]
-p::
-u::
--patch::
- Generate patch (see section on generating patches).
+ Generate patch (see section titled
+ifdef::git-log[]
+<<generate_patch_text_with_p, "Generating patch text with -p">>).
+endif::git-log[]
+ifndef::git-log[]
+"Generating patch text with -p").
+endif::git-log[]
ifdef::git-diff[]
This is the default.
endif::git-diff[]
diff --git a/Documentation/fsck-msgids.txt b/Documentation/fsck-msgids.txt
index 7af76ff99a..12eae8a222 100644
--- a/Documentation/fsck-msgids.txt
+++ b/Documentation/fsck-msgids.txt
@@ -46,6 +46,18 @@
`fullPathname`::
(WARN) A path contains the full path starting with "/".
+`gitattributesBlob`::
+ (ERROR) A non-blob found at `.gitattributes`.
+
+`gitattributesLarge`::
+ (ERROR) The `.gitattributes` blob is too large.
+
+`gitattributesLineLength`::
+ (ERROR) The `.gitattributes` blob contains too long lines.
+
+`gitattributesMissing`::
+ (ERROR) Unable to read `.gitattributes` blob.
+
`gitattributesSymlink`::
(INFO) `.gitattributes` is a symlink.
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index 326276e51c..0c1dfb3c98 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -9,7 +9,7 @@ git-am - Apply a series of patches from a mailbox
SYNOPSIS
--------
[verse]
-'git am' [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8]
+'git am' [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8] [--no-verify]
[--[no-]3way] [--interactive] [--committer-date-is-author-date]
[--ignore-date] [--ignore-space-change | --ignore-whitespace]
[--whitespace=<option>] [-C<n>] [-p<n>] [--directory=<dir>]
@@ -138,6 +138,12 @@ include::rerere-options.txt[]
--interactive::
Run interactively.
+-n::
+--no-verify::
+ By default, the pre-applypatch and applypatch-msg hooks are run.
+ When any of `--no-verify` or `-n` is given, these are bypassed.
+ See also linkgit:githooks[5].
+
--committer-date-is-author-date::
By default the command records the date from the e-mail
message as the commit author date, and uses the time of
diff --git a/Documentation/git-bisect-lk2009.txt b/Documentation/git-bisect-lk2009.txt
index f3d9566c89..0bc165788e 100644
--- a/Documentation/git-bisect-lk2009.txt
+++ b/Documentation/git-bisect-lk2009.txt
@@ -1347,8 +1347,8 @@ author to given a talk and for publishing this paper.
References
----------
-- [[[1]]] https://www.nist.gov/sites/default/files/documents/director/planning/report02-3.pdf['The Economic Impacts of Inadequate Infratructure for Software Testing'. Nist Planning Report 02-3], see Executive Summary and Chapter 8.
-- [[[2]]] http://www.oracle.com/technetwork/java/codeconvtoc-136057.html['Code Conventions for the Java Programming Language'. Sun Microsystems.]
+- [[[1]]] https://web.archive.org/web/20091206032101/http://www.nist.gov/public_affairs/releases/n02-10.htm['Software Errors Cost U.S. Economy $59.5 Billion Annually'. Nist News Release.] See also https://www.nist.gov/system/files/documents/director/planning/report02-3.pdf['The Economic Impacts of Inadequate Infratructure for Software Testing'. Nist Planning Report 02-3], Executive Summary and Chapter 8.
+- [[[2]]] https://www.oracle.com/java/technologies/javase/codeconventions-introduction.html['Code Conventions for the Java Programming Language: 1. Introduction'. Sun Microsystems.]
- [[[3]]] https://en.wikipedia.org/wiki/Software_maintenance['Software maintenance'. Wikipedia.]
- [[[4]]] https://lore.kernel.org/git/7vps5xsbwp.fsf_-_@assigned-by-dhcp.cox.net/[Junio C Hamano. 'Automated bisect success story'.]
- [[[5]]] https://lwn.net/Articles/317154/[Christian Couder. 'Fully automated bisecting with "git bisect run"'. LWN.net.]
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 12c5f84e3b..aa2f78c4c2 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -116,7 +116,7 @@ OPTIONS
-f::
--force::
- Reset <branchname> to <startpoint>, even if <branchname> exists
+ Reset <branchname> to <start-point>, even if <branchname> exists
already. Without `-f`, 'git branch' refuses to change an existing branch.
In combination with `-d` (or `--delete`), allow deleting the
branch irrespective of its merged status, or whether it even
diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt
index ec30b5c574..830f0a2eff 100644
--- a/Documentation/git-cat-file.txt
+++ b/Documentation/git-cat-file.txt
@@ -45,7 +45,9 @@ OPTIONS
-s::
Instead of the content, show the object size identified by
- `<object>`.
+ `<object>`. If used with `--use-mailmap` option, will show
+ the size of updated object after replacing idents using the
+ mailmap mechanism.
-e::
Exit with zero status if `<object>` exists and is a valid
@@ -89,26 +91,49 @@ OPTIONS
--batch::
--batch=<format>::
Print object information and contents for each object provided
- on stdin. May not be combined with any other options or arguments
- except `--textconv` or `--filters`, in which case the input lines
- also need to specify the path, separated by whitespace. See the
- section `BATCH OUTPUT` below for details.
+ on stdin. May not be combined with any other options or arguments
+ except `--textconv`, `--filters`, or `--use-mailmap`.
+ +
+ * When used with `--textconv` or `--filters`, the input lines
+ must specify the path, separated by whitespace. See the section
+ `BATCH OUTPUT` below for details.
+ +
+ * When used with `--use-mailmap`, for commit and tag objects, the
+ contents part of the output shows the identities replaced using the
+ mailmap mechanism, while the information part of the output shows
+ the size of the object as if it actually recorded the replacement
+ identities.
--batch-check::
--batch-check=<format>::
- Print object information for each object provided on stdin. May
- not be combined with any other options or arguments except
- `--textconv` or `--filters`, in which case the input lines also
- need to specify the path, separated by whitespace. See the
- section `BATCH OUTPUT` below for details.
+ Print object information for each object provided on stdin. May not be
+ combined with any other options or arguments except `--textconv`, `--filters`
+ or `--use-mailmap`.
+ +
+ * When used with `--textconv` or `--filters`, the input lines must
+ specify the path, separated by whitespace. See the section
+ `BATCH OUTPUT` below for details.
+ +
+ * When used with `--use-mailmap`, for commit and tag objects, the
+ printed object information shows the size of the object as if the
+ identities recorded in it were replaced by the mailmap mechanism.
--batch-command::
--batch-command=<format>::
Enter a command mode that reads commands and arguments from stdin. May
- only be combined with `--buffer`, `--textconv` or `--filters`. In the
- case of `--textconv` or `--filters`, the input lines also need to specify
- the path, separated by whitespace. See the section `BATCH OUTPUT` below
- for details.
+ only be combined with `--buffer`, `--textconv`, `--use-mailmap` or
+ `--filters`.
+ +
+ * When used with `--textconv` or `--filters`, the input lines must
+ specify the path, separated by whitespace. See the section
+ `BATCH OUTPUT` below for details.
+ +
+ * When used with `--use-mailmap`, for commit and tag objects, the
+ `contents` command shows the identities replaced using the
+ mailmap mechanism, while the `info` command shows the size
+ of the object as if it actually recorded the replacement
+ identities.
+
+
`--batch-command` recognizes the following commands:
+
diff --git a/Documentation/git-check-attr.txt b/Documentation/git-check-attr.txt
index 84f41a8e82..6e4f3aaf34 100644
--- a/Documentation/git-check-attr.txt
+++ b/Documentation/git-check-attr.txt
@@ -9,8 +9,8 @@ git-check-attr - Display gitattributes information
SYNOPSIS
--------
[verse]
-'git check-attr' [-a | --all | <attr>...] [--] <pathname>...
-'git check-attr' --stdin [-z] [-a | --all | <attr>...]
+'git check-attr' [--source <tree-ish>] [-a | --all | <attr>...] [--] <pathname>...
+'git check-attr' --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]
DESCRIPTION
-----------
@@ -36,6 +36,11 @@ OPTIONS
If `--stdin` is also given, input paths are separated
with a NUL character instead of a linefeed character.
+--source=<tree-ish>::
+ Check attributes against the specified tree-ish. It is common to
+ specify the source tree by naming a commit, branch or tag associated
+ with it.
+
\--::
Interpret all preceding arguments as attributes and all following
arguments as path names.
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 4cb9d555b4..9f116acdbd 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -477,9 +477,9 @@ before that happens. If we have not yet moved away from commit `f`,
any of these will create a reference to it:
------------
-$ git checkout -b foo <1>
-$ git branch foo <2>
-$ git tag foo <3>
+$ git checkout -b foo # or "git switch -c foo" <1>
+$ git branch foo <2>
+$ git tag foo <3>
------------
<1> creates a new branch `foo`, which refers to commit `f`, and then
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index 1e8ac9df60..fdcad3d200 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -219,7 +219,7 @@ again, this time exercising more care about matching up context lines.
------------
$ 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 --git a/Documentation/git-fetch.txt b/Documentation/git-fetch.txt
index 63d9569e16..fba66f1460 100644
--- a/Documentation/git-fetch.txt
+++ b/Documentation/git-fetch.txt
@@ -251,10 +251,10 @@ EXAMPLES
$ git fetch origin
------------------------------------------------
+
-The above command copies all branches from the remote refs/heads/
-namespace and stores them to the local refs/remotes/origin/ namespace,
-unless the branch.<name>.fetch option is used to specify a non-default
-refspec.
+The above command copies all branches from the remote `refs/heads/`
+namespace and stores them to the local `refs/remotes/origin/` namespace,
+unless the `remote.<repository>.fetch` option is used to specify a
+non-default refspec.
* Using refspecs explicitly:
+
diff --git a/Documentation/git-merge-tree.txt b/Documentation/git-merge-tree.txt
index 04bcc416e6..88ee942101 100644
--- a/Documentation/git-merge-tree.txt
+++ b/Documentation/git-merge-tree.txt
@@ -64,6 +64,11 @@ OPTIONS
share no common history. This flag can be given to override that
check and make the merge proceed anyway.
+--merge-base=<commit>::
+ Instead of finding the merge-bases for <branch1> and <branch2>,
+ specify a merge-base for the merge, and specifying multiple bases is
+ currently not supported. This option is incompatible with `--stdin`.
+
[[OUTPUT]]
OUTPUT
------
@@ -216,6 +221,17 @@ with linkgit:git-merge[1]:
* any messages that would have been printed to stdout (the
<<IM,Informational messages>>)
+INPUT FORMAT
+------------
+'git merge-tree --stdin' input format is fully text based. Each line
+has this format:
+
+ [<base-commit> -- ]<branch1> <branch2>
+
+If one line is separated by `--`, the string before the separator is
+used for specifying a merge-base for the merge and the string after
+the separator describes the branches to be merged.
+
MISTAKES TO AVOID
-----------------
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index 2d6a1391c8..0aeff572a5 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -37,7 +37,8 @@ Then "`git merge topic`" will replay the changes made on the
`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 --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index f9675bd24e..d811c1cf44 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -38,6 +38,13 @@ The current branch is reset to `<upstream>` or `<newbase>` if the
`git reset --hard <upstream>` (or `<newbase>`). `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 --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt
index 01cb4c9b9c..79ad5643ee 100644
--- a/Documentation/git-reset.txt
+++ b/Documentation/git-reset.txt
@@ -49,7 +49,8 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
'git reset' [<mode>] [<commit>]::
This form resets the current branch head to `<commit>` and
possibly updates the index (resetting it to the tree of `<commit>`) and
- the working tree depending on `<mode>`. If `<mode>` is omitted,
+ the working tree depending on `<mode>`. Before the operation, `ORIG_HEAD`
+ is set to the tip of the current branch. If `<mode>` is omitted,
defaults to `--mixed`. The `<mode>` must be one of the following:
+
--
diff --git a/Documentation/git-status.txt b/Documentation/git-status.txt
index 5e438a7fdc..a051b1e8f3 100644
--- a/Documentation/git-status.txt
+++ b/Documentation/git-status.txt
@@ -457,6 +457,66 @@ during the write may conflict with other simultaneous processes, causing
them to fail. Scripts running `status` in the background should consider
using `git --no-optional-locks status` (see linkgit:git[1] for details).
+UNTRACKED FILES AND PERFORMANCE
+-------------------------------
+
+`git status` can be very slow in large worktrees if/when it
+needs to search for untracked files and directories. There are
+many configuration options available to speed this up by either
+avoiding the work or making use of cached results from previous
+Git commands. There is no single optimum set of settings right
+for everyone. We'll list a summary of the relevant options to help
+you, but before going into the list, you may want to run `git status`
+again, because your configuration may already be caching `git status`
+results, so it could be faster on subsequent runs.
+
+* The `--untracked-files=no` flag or the
+ `status.showUntrackedfiles=false` config (see above for both):
+ indicate that `git status` should not report untracked
+ files. This is the fastest option. `git status` will not list
+ the untracked files, so you need to be careful to remember if
+ you create any new files and manually `git add` them.
+
+* `advice.statusUoption=false` (see linkgit:git-config[1]):
+ setting this variable to `false` disables the warning message
+ given when enumerating untracked files takes more than 2
+ seconds. In a large project, it may take longer and the user
+ may have already accepted the trade off (e.g. using "-uno" may
+ not be an acceptable option for the user), in which case, there
+ is no point issuing the warning message, and in such a case,
+ disabling the warning may be the best.
+
+* `core.untrackedCache=true` (see linkgit:git-update-index[1]):
+ enable the untracked cache feature and only search directories
+ that have been modified since the previous `git status` command.
+ Git remembers the set of untracked files within each directory
+ and assumes that if a directory has not been modified, then
+ the set of untracked files within has not changed. This is much
+ faster than enumerating the contents of every directory, but still
+ not without cost, because Git still has to search for the set of
+ modified directories. The untracked cache is stored in the
+ `.git/index` file. The reduced cost of searching for untracked
+ files is offset slightly by the increased size of the index and
+ the cost of keeping it up-to-date. That reduced search time is
+ usually worth the additional size.
+
+* `core.untrackedCache=true` and `core.fsmonitor=true` or
+ `core.fsmonitor=<hook_command_pathname>` (see
+ linkgit:git-update-index[1]): enable both the untracked cache
+ and FSMonitor features and only search directories that have
+ been modified since the previous `git status` command. This
+ is faster than using just the untracked cache alone because
+ Git can also avoid searching for modified directories. Git
+ only has to enumerate the exact set of directories that have
+ changed recently. While the FSMonitor feature can be enabled
+ without the untracked cache, the benefits are greatly reduced
+ in that case.
+
+Note that after you turn on the untracked cache and/or FSMonitor
+features it may take a few `git status` commands for the various
+caches to warm up before you see improved command times. This is
+normal.
+
SEE ALSO
--------
linkgit:gitignore[5]
diff --git a/Documentation/git-var.txt b/Documentation/git-var.txt
index 6aa521fab2..f40202b8e3 100644
--- a/Documentation/git-var.txt
+++ b/Documentation/git-var.txt
@@ -13,7 +13,8 @@ SYNOPSIS
DESCRIPTION
-----------
-Prints a Git logical variable.
+Prints a Git logical variable. Exits with code 1 if the variable has
+no value.
OPTIONS
-------
@@ -49,6 +50,14 @@ ifdef::git-default-editor[]
The build you are using chose '{git-default-editor}' as the default.
endif::git-default-editor[]
+GIT_SEQUENCE_EDITOR::
+ Text editor used to edit the 'todo' file while running `git rebase
+ -i`. Like `GIT_EDITOR`, the value is meant to be interpreted by
+ the shell when it is used. The order of preference is the
+ `$GIT_SEQUENCE_EDITOR` environment variable, then
+ `sequence.editor` configuration, and then the value of `git var
+ GIT_EDITOR`.
+
GIT_PAGER::
Text viewer for use by Git commands (e.g., 'less'). The value
is meant to be interpreted by the shell. The order of preference
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 1d33e083ab..f9a7a4554c 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -13,8 +13,7 @@ SYNOPSIS
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
[-p|--paginate|-P|--no-pager] [--no-replace-objects] [--bare]
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
- [--super-prefix=<path>] [--config-env=<name>=<envvar>]
- <command> [<args>]
+ [--config-env=<name>=<envvar>] <command> [<args>]
DESCRIPTION
-----------
@@ -169,11 +168,6 @@ If you just want to run git as if it was started in `<path>` then use
details. Equivalent to setting the `GIT_NAMESPACE` environment
variable.
---super-prefix=<path>::
- Currently for internal use only. Set a prefix which gives a path from
- above a repository down to its root. One use is to give submodules
- context about the superproject that invoked it.
-
--bare::
Treat the repository as a bare repository. If GIT_DIR
environment is not set, it is set to the current working
diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
index 4b36d51beb..c19e64ea0e 100644
--- a/Documentation/gitattributes.txt
+++ b/Documentation/gitattributes.txt
@@ -1155,7 +1155,7 @@ Unspecified::
String::
- Specify a comma separate list of common whitespace problems to
+ Specify a comma separated list of common whitespace problems to
notice in the same format as the `core.whitespace` configuration
variable.
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index a16e62bc8c..62908602e7 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -27,6 +27,18 @@ repository. An exception are hooks triggered during a push ('pre-receive',
'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 --git a/Documentation/gitprotocol-v2.txt b/Documentation/gitprotocol-v2.txt
index 59bf41cefb..acb97ad0c2 100644
--- a/Documentation/gitprotocol-v2.txt
+++ b/Documentation/gitprotocol-v2.txt
@@ -578,6 +578,207 @@ and associated requested information, each separated by a single space.
obj-info = obj-id SP obj-size
+bundle-uri
+~~~~~~~~~~
+
+If the 'bundle-uri' capability is advertised, the server supports the
+`bundle-uri' command.
+
+The capability is currently advertised with no value (i.e. not
+"bundle-uri=somevalue"), a value may be added in the future for
+supporting command-wide extensions. Clients MUST ignore any unknown
+capability values and proceed with the 'bundle-uri` dialog they
+support.
+
+The 'bundle-uri' command is intended to be issued before `fetch` to
+get URIs to bundle files (see linkgit:git-bundle[1]) to "seed" and
+inform the subsequent `fetch` command.
+
+The client CAN issue `bundle-uri` before or after any other valid
+command. To be useful to clients it's expected that it'll be issued
+after an `ls-refs` and before `fetch`, but CAN be issued at any time
+in the dialog.
+
+DISCUSSION of bundle-uri
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+The intent of the feature is optimize for server resource consumption
+in the common case by changing the common case of fetching a very
+large PACK during linkgit:git-clone[1] into a smaller incremental
+fetch.
+
+It also allows servers to achieve better caching in combination with
+an `uploadpack.packObjectsHook` (see linkgit:git-config[1]).
+
+By having new clones or fetches be a more predictable and common
+negotiation against the tips of recently produces *.bundle file(s).
+Servers might even pre-generate the results of such negotiations for
+the `uploadpack.packObjectsHook` as new pushes come in.
+
+One way that servers could take advantage of these bundles is that the
+server would anticipate that fresh clones will download a known bundle,
+followed by catching up to the current state of the repository using ref
+tips found in that bundle (or bundles).
+
+PROTOCOL for bundle-uri
+^^^^^^^^^^^^^^^^^^^^^^^
+
+A `bundle-uri` request takes no arguments, and as noted above does not
+currently advertise a capability value. Both may be added in the
+future.
+
+When the client issues a `command=bundle-uri` request, the response is a
+list of key-value pairs provided as packet lines with value
+`<key>=<value>`. Each `<key>` should be interpreted as a config key from
+the `bundle.*` namespace to construct a list of bundles. These keys are
+grouped by a `bundle.<id>.` subsection, where each key corresponding to a
+given `<id>` contributes attributes to the bundle defined by that `<id>`.
+See linkgit:git-config[1] for the specific details of these keys and how
+the Git client will interpret their values.
+
+Clients MUST parse the line according to the above format, lines that do
+not conform to the format SHOULD be discarded. The user MAY be warned in
+such a case.
+
+bundle-uri CLIENT AND SERVER EXPECTATIONS
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+URI CONTENTS::
+The content at the advertised URIs MUST be one of two types.
++
+The advertised URI may contain a bundle file that `git bundle verify`
+would accept. I.e. they MUST contain one or more reference tips for
+use by the client, MUST indicate prerequisites (in any) with standard
+"-" prefixes, and MUST indicate their "object-format", if
+applicable.
++
+The advertised URI may alternatively contain a plaintext file that `git
+config --list` would accept (with the `--file` option). The key-value
+pairs in this list are in the `bundle.*` namespace (see
+linkgit:git-config[1]).
+
+bundle-uri CLIENT ERROR RECOVERY::
+A client MUST above all gracefully degrade on errors, whether that
+error is because of bad missing/data in the bundle URI(s), because
+that client is too dumb to e.g. understand and fully parse out bundle
+headers and their prerequisite relationships, or something else.
++
+Server operators should feel confident in turning on "bundle-uri" and
+not worry if e.g. their CDN goes down that clones or fetches will run
+into hard failures. Even if the server bundle(s) are
+incomplete, or bad in some way the client should still end up with a
+functioning repository, just as if it had chosen not to use this
+protocol extension.
++
+All subsequent discussion on client and server interaction MUST keep
+this in mind.
+
+bundle-uri SERVER TO CLIENT::
+The ordering of the returned bundle uris is not significant. Clients
+MUST parse their headers to discover their contained OIDS and
+prerequisites. A client MUST consider the content of the bundle(s)
+themselves and their header as the ultimate source of truth.
++
+A server MAY even return bundle(s) that don't have any direct
+relationship to the repository being cloned (either through accident,
+or intentional "clever" configuration), and expect a client to sort
+out what data they'd like from the bundle(s), if any.
+
+bundle-uri CLIENT TO SERVER::
+The client SHOULD provide reference tips found in the bundle header(s)
+as 'have' lines in any subsequent `fetch` request. A client MAY also
+ignore the bundle(s) entirely if doing so is deemed worse for some
+reason, e.g. if the bundles can't be downloaded, it doesn't like the
+tips it finds etc.
+
+WHEN ADVERTISED BUNDLE(S) REQUIRE NO FURTHER NEGOTIATION::
+If after issuing `bundle-uri` and `ls-refs`, and getting the header(s)
+of the bundle(s) the client finds that the ref tips it wants can be
+retrieved entirely from advertised bundle(s), the client MAY disconnect
+from the Git server. The results of such a 'clone' or 'fetch' should be
+indistinguishable from the state attained without using bundle-uri.
+
+EARLY CLIENT DISCONNECTIONS AND ERROR RECOVERY::
+A client MAY perform an early disconnect while still downloading the
+bundle(s) (having streamed and parsed their headers). In such a case
+the client MUST gracefully recover from any errors related to
+finishing the download and validation of the bundle(s).
++
+I.e. a client might need to re-connect and issue a 'fetch' command,
+and possibly fall back to not making use of 'bundle-uri' at all.
++
+This "MAY" behavior is specified as such (and not a "SHOULD") on the
+assumption that a server advertising bundle uris is more likely than
+not to be serving up a relatively large repository, and to be pointing
+to URIs that have a good chance of being in working order. A client
+MAY e.g. look at the payload size of the bundles as a heuristic to see
+if an early disconnect is worth it, should falling back on a full
+"fetch" dialog be necessary.
+
+WHEN ADVERTISED BUNDLE(S) REQUIRE FURTHER NEGOTIATION::
+A client SHOULD commence a negotiation of a PACK from the server via
+the "fetch" command using the OID tips found in advertised bundles,
+even if's still in the process of downloading those bundle(s).
++
+This allows for aggressive early disconnects from any interactive
+server dialog. The client blindly trusts that the advertised OID tips
+are relevant, and issues them as 'have' lines, it then requests any
+tips it would like (usually from the "ls-refs" advertisement) via
+'want' lines. The server will then compute a (hopefully small) PACK
+with the expected difference between the tips from the bundle(s) and
+the data requested.
++
+The only connection the client then needs to keep active is to the
+concurrently downloading static bundle(s), when those and the
+incremental PACK are retrieved they should be inflated and
+validated. Any errors at this point should be gracefully recovered
+from, see above.
+
+bundle-uri PROTOCOL FEATURES
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The client constructs a bundle list from the `<key>=<value>` pairs
+provided by the server. These pairs are part of the `bundle.*` namespace
+as documented in linkgit:git-config[1]. In this section, we discuss some
+of these keys and describe the actions the client will do in response to
+this information.
+
+In particular, the `bundle.version` key specifies an integer value. The
+only accepted value at the moment is `1`, but if the client sees an
+unexpected value here then the client MUST ignore the bundle list.
+
+As long as `bundle.version` is understood, all other unknown keys MAY be
+ignored by the client. The server will guarantee compatibility with older
+clients, though newer clients may be better able to use the extra keys to
+minimize downloads.
+
+Any backwards-incompatible addition of pre-URI key-value will be
+guarded by a new `bundle.version` value or values in 'bundle-uri'
+capability advertisement itself, and/or by new future `bundle-uri`
+request arguments.
+
+Some example key-value pairs that are not currently implemented but could
+be implemented in the future include:
+
+ * Add a "hash=<val>" or "size=<bytes>" advertise the expected hash or
+ size of the bundle file.
+
+ * Advertise that one or more bundle files are the same (to e.g. have
+ clients round-robin or otherwise choose one of N possible files).
+
+ * A "oid=<OID>" shortcut and "prerequisite=<OID>" shortcut. For
+ expressing the common case of a bundle with one tip and no
+ prerequisites, or one tip and one prerequisite.
++
+This would allow for optimizing the common case of servers who'd like
+to provide one "big bundle" containing only their "main" branch,
+and/or incremental updates thereof.
++
+A client receiving such a a response MAY assume that they can skip
+retrieving the header from a bundle at the indicated URI, and thus
+save themselves and the server(s) the request(s) needed to inspect the
+headers of that bundle or bundles.
+
GIT
---
Part of the linkgit:git[1] suite
diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt
index 0d2e55d781..9aa58052bc 100644
--- a/Documentation/revisions.txt
+++ b/Documentation/revisions.txt
@@ -49,7 +49,8 @@ characters and to avoid word splitting.
`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 --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
index b2580ab851..c4c2d3e022 100755
--- a/GIT-VERSION-GEN
+++ b/GIT-VERSION-GEN
@@ -1,7 +1,7 @@
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.39.0
+DEF_VER=v2.39.GIT
LF='
'
diff --git a/INSTALL b/INSTALL
index 3344788397..d5694f8c47 100644
--- a/INSTALL
+++ b/INSTALL
@@ -139,7 +139,7 @@ Issues of note:
not need that functionality, use NO_CURL to build without
it.
- Git requires version "7.19.4" or later of "libcurl" to build
+ Git requires version "7.19.5" or later of "libcurl" to build
without NO_CURL. This version requirement may be bumped in
the future.
diff --git a/Makefile b/Makefile
index 093829ae28..45bd6ac9c3 100644
--- a/Makefile
+++ b/Makefile
@@ -515,10 +515,8 @@ include shared.mak
# Define BLK_SHA1 to make use of optimized C SHA-1 routines bundled
# with git (in the block-sha1/ directory).
#
-# Define NO_APPLE_COMMON_CRYPTO on OSX to opt-out of using the
-# "APPLE_COMMON_CRYPTO" backend for SHA-1, which is currently the
-# default on that OS. On macOS 01.4 (Tiger) or older,
-# NO_APPLE_COMMON_CRYPTO is defined by default.
+# Define APPLE_COMMON_CRYPTO_SHA1 to use Apple's CommonCrypto for
+# SHA-1.
#
# If don't enable any of the *_SHA1 settings in this section, Git will
# default to its built-in sha1collisiondetection library, which is a
@@ -695,7 +693,6 @@ THIRD_PARTY_SOURCES =
# interactive shell sessions without exporting it.
unexport CDPATH
-SCRIPT_SH += git-bisect.sh
SCRIPT_SH += git-difftool--helper.sh
SCRIPT_SH += git-filter-branch.sh
SCRIPT_SH += git-merge-octopus.sh
@@ -805,6 +802,7 @@ TEST_BUILTINS_OBJS += test-dump-cache-tree.o
TEST_BUILTINS_OBJS += test-dump-fsmonitor.o
TEST_BUILTINS_OBJS += test-dump-split-index.o
TEST_BUILTINS_OBJS += test-dump-untracked-cache.o
+TEST_BUILTINS_OBJS += test-env-helper.o
TEST_BUILTINS_OBJS += test-example-decorate.o
TEST_BUILTINS_OBJS += test-fast-rebase.o
TEST_BUILTINS_OBJS += test-fsmonitor-client.o
@@ -1206,7 +1204,7 @@ BUILTIN_OBJS += builtin/am.o
BUILTIN_OBJS += builtin/annotate.o
BUILTIN_OBJS += builtin/apply.o
BUILTIN_OBJS += builtin/archive.o
-BUILTIN_OBJS += builtin/bisect--helper.o
+BUILTIN_OBJS += builtin/bisect.o
BUILTIN_OBJS += builtin/blame.o
BUILTIN_OBJS += builtin/branch.o
BUILTIN_OBJS += builtin/bugreport.o
@@ -1238,7 +1236,6 @@ BUILTIN_OBJS += builtin/diff-index.o
BUILTIN_OBJS += builtin/diff-tree.o
BUILTIN_OBJS += builtin/diff.o
BUILTIN_OBJS += builtin/difftool.o
-BUILTIN_OBJS += builtin/env--helper.o
BUILTIN_OBJS += builtin/fast-export.o
BUILTIN_OBJS += builtin/fast-import.o
BUILTIN_OBJS += builtin/fetch-pack.o
@@ -1916,7 +1913,7 @@ ifdef NO_POSIX_GOODIES
BASIC_CFLAGS += -DNO_POSIX_GOODIES
endif
-ifdef APPLE_COMMON_CRYPTO
+ifdef APPLE_COMMON_CRYPTO_SHA1
# Apple CommonCrypto requires chunking
SHA1_MAX_BLOCK_SIZE = 1024L*1024L*1024L
endif
@@ -1933,7 +1930,7 @@ ifdef BLK_SHA1
LIB_OBJS += block-sha1/sha1.o
BASIC_CFLAGS += -DSHA1_BLK
else
-ifdef APPLE_COMMON_CRYPTO
+ifdef APPLE_COMMON_CRYPTO_SHA1
COMPAT_CFLAGS += -DCOMMON_DIGEST_FOR_OPENSSL
BASIC_CFLAGS += -DSHA1_APPLE
else
diff --git a/RelNotes b/RelNotes
index 758368388a..47807bf257 120000
--- a/RelNotes
+++ b/RelNotes
@@ -1 +1 @@
-Documentation/RelNotes/2.39.0.txt \ No newline at end of file
+Documentation/RelNotes/2.40.0.txt \ No newline at end of file
diff --git a/add-interactive.c b/add-interactive.c
index ae1839c04a..00a0f6f96f 100644
--- a/add-interactive.c
+++ b/add-interactive.c
@@ -724,7 +724,7 @@ static int run_update(struct add_i_state *s, const struct pathspec *ps,
}
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 --git a/apply.c b/apply.c
index bc33814313..821fe411ec 100644
--- a/apply.c
+++ b/apply.c
@@ -2913,7 +2913,7 @@ static int apply_one_fragment(struct apply_state *state,
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 @@ static int apply_one_fragment(struct apply_state *state,
(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 '\\':
@@ -4105,7 +4105,7 @@ static int preimage_oid_in_gitlink_patch(struct patch *p, struct object_id *oid)
static int build_fake_ancestor(struct apply_state *state, struct patch *list)
{
struct patch *patch;
- struct index_state result = { NULL };
+ struct index_state result = INDEX_STATE_INIT;
struct lock_file lock = LOCK_INIT;
int res;
diff --git a/archive.c b/archive.c
index 941495f5d7..81ff76fce9 100644
--- a/archive.c
+++ b/archive.c
@@ -120,7 +120,7 @@ static const struct attr_check *get_archive_attrs(struct index_state *istate,
static struct attr_check *check;
if (!check)
check = attr_check_initl("export-ignore", "export-subst", NULL);
- git_check_attr(istate, path, check);
+ git_check_attr(istate, NULL, path, check);
return check;
}
diff --git a/attr.c b/attr.c
index 42ad6de8c7..1053dfcd4b 100644
--- a/attr.c
+++ b/attr.c
@@ -13,6 +13,8 @@
#include "dir.h"
#include "utf8.h"
#include "quote.h"
+#include "revision.h"
+#include "object-store.h"
#include "thread-utils.h"
const char git_attr__true[] = "(builtin)true";
@@ -24,7 +26,7 @@ static const char git_attr__unknown[] = "(builtin)unknown";
#define ATTR__UNKNOWN git_attr__unknown
struct git_attr {
- int attr_nr; /* unique attribute number */
+ unsigned int attr_nr; /* unique attribute number */
char name[FLEX_ARRAY]; /* attribute name */
};
@@ -206,7 +208,7 @@ static void report_invalid_attr(const char *name, size_t len,
* dictionary. If no entry is found, create a new attribute and store it in
* the dictionary.
*/
-static const struct git_attr *git_attr_internal(const char *name, int namelen)
+static const struct git_attr *git_attr_internal(const char *name, size_t namelen)
{
struct git_attr *a;
@@ -222,8 +224,8 @@ static const struct git_attr *git_attr_internal(const char *name, int namelen)
a->attr_nr = hashmap_get_size(&g_attr_hashmap.map);
attr_hashmap_add(&g_attr_hashmap, a->name, namelen, a);
- assert(a->attr_nr ==
- (hashmap_get_size(&g_attr_hashmap.map) - 1));
+ if (a->attr_nr != hashmap_get_size(&g_attr_hashmap.map) - 1)
+ die(_("unable to add additional attribute"));
}
hashmap_unlock(&g_attr_hashmap);
@@ -268,7 +270,7 @@ struct match_attr {
const struct git_attr *attr;
} u;
char is_macro;
- unsigned num_attr;
+ size_t num_attr;
struct attr_state state[FLEX_ARRAY];
};
@@ -289,7 +291,7 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,
struct attr_state *e)
{
const char *ep, *equals;
- int len;
+ size_t len;
ep = cp + strcspn(cp, blank);
equals = strchr(cp, '=');
@@ -333,8 +335,7 @@ static const char *parse_attr(const char *src, int lineno, const char *cp,
static struct match_attr *parse_attr_line(const char *line, const char *src,
int lineno, unsigned flags)
{
- int namelen;
- int num_attr, i;
+ size_t namelen, num_attr, i;
const char *cp, *name, *states;
struct match_attr *res = NULL;
int is_macro;
@@ -345,6 +346,11 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
return NULL;
name = cp;
+ if (strlen(line) >= ATTR_MAX_LINE_LENGTH) {
+ warning(_("ignoring overly long attributes line %d"), lineno);
+ return NULL;
+ }
+
if (*cp == '"' && !unquote_c_style(&pattern, name, &states)) {
name = pattern.buf;
namelen = pattern.len;
@@ -381,10 +387,9 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
goto fail_return;
}
- res = xcalloc(1,
- sizeof(*res) +
- sizeof(struct attr_state) * num_attr +
- (is_macro ? 0 : namelen + 1));
+ res = xcalloc(1, st_add3(sizeof(*res),
+ st_mult(sizeof(struct attr_state), num_attr),
+ is_macro ? 0 : namelen + 1));
if (is_macro) {
res->u.attr = git_attr_internal(name, namelen);
} else {
@@ -447,11 +452,12 @@ struct attr_stack {
static void attr_stack_free(struct attr_stack *e)
{
- int i;
+ unsigned i;
free(e->origin);
for (i = 0; i < e->num_matches; i++) {
struct match_attr *a = e->attrs[i];
- int j;
+ size_t j;
+
for (j = 0; j < a->num_attr; j++) {
const char *setto = a->state[j].setto;
if (setto == ATTR__TRUE ||
@@ -599,8 +605,7 @@ struct attr_check *attr_check_dup(const struct attr_check *check)
ret->nr = check->nr;
ret->alloc = check->alloc;
- ALLOC_ARRAY(ret->items, ret->nr);
- COPY_ARRAY(ret->items, check->items, ret->nr);
+ DUP_ARRAY(ret->items, check->items, ret->nr);
return ret;
}
@@ -660,8 +665,8 @@ static void handle_attr_line(struct attr_stack *res,
a = parse_attr_line(line, src, lineno, flags);
if (!a)
return;
- ALLOC_GROW(res->attrs, res->num_matches + 1, res->alloc);
- res->attrs[res->num_matches++] = a;
+ ALLOC_GROW_BY(res->attrs, res->num_matches, 1, res->alloc);
+ res->attrs[res->num_matches - 1] = a;
}
static struct attr_stack *read_attr_from_array(const char **list)
@@ -701,11 +706,12 @@ void git_attr_set_direction(enum git_attr_direction new_direction)
static struct attr_stack *read_attr_from_file(const char *path, unsigned flags)
{
+ struct strbuf buf = STRBUF_INIT;
int fd;
FILE *fp;
struct attr_stack *res;
- char buf[2048];
int lineno = 0;
+ struct stat st;
if (flags & READ_ATTR_NOFOLLOW)
fd = open_nofollow(path, O_RDONLY);
@@ -717,26 +723,86 @@ static struct attr_stack *read_attr_from_file(const char *path, unsigned flags)
return NULL;
}
fp = xfdopen(fd, "r");
+ if (fstat(fd, &st)) {
+ warning_errno(_("cannot fstat gitattributes file '%s'"), path);
+ fclose(fp);
+ return NULL;
+ }
+ if (st.st_size >= ATTR_MAX_FILE_SIZE) {
+ warning(_("ignoring overly large gitattributes file '%s'"), path);
+ fclose(fp);
+ return NULL;
+ }
CALLOC_ARRAY(res, 1);
- while (fgets(buf, sizeof(buf), fp)) {
- char *bufp = buf;
- if (!lineno)
- skip_utf8_bom(&bufp, strlen(bufp));
- handle_attr_line(res, bufp, path, ++lineno, flags);
+ while (strbuf_getline(&buf, fp) != EOF) {
+ if (!lineno && starts_with(buf.buf, utf8_bom))
+ strbuf_remove(&buf, 0, strlen(utf8_bom));
+ handle_attr_line(res, buf.buf, path, ++lineno, flags);
}
+
fclose(fp);
+ strbuf_release(&buf);
return res;
}
-static struct attr_stack *read_attr_from_index(struct index_state *istate,
- const char *path,
- unsigned flags)
+static struct attr_stack *read_attr_from_buf(char *buf, const char *path,
+ unsigned flags)
{
struct attr_stack *res;
- char *buf, *sp;
+ char *sp;
int lineno = 0;
+ if (!buf)
+ return NULL;
+
+ CALLOC_ARRAY(res, 1);
+ for (sp = buf; *sp;) {
+ char *ep;
+ int more;
+
+ ep = strchrnul(sp, '\n');
+ more = (*ep == '\n');
+ *ep = '\0';
+ handle_attr_line(res, sp, path, ++lineno, flags);
+ sp = ep + more;
+ }
+ free(buf);
+
+ return res;
+}
+
+static struct attr_stack *read_attr_from_blob(struct index_state *istate,
+ const struct object_id *tree_oid,
+ const char *path, unsigned flags)
+{
+ struct object_id oid;
+ unsigned long sz;
+ enum object_type type;
+ void *buf;
+ unsigned short mode;
+
+ if (!tree_oid)
+ return NULL;
+
+ if (get_tree_entry(istate->repo, tree_oid, path, &oid, &mode))
+ return NULL;
+
+ buf = repo_read_object_file(istate->repo, &oid, &type, &sz);
+ if (!buf || type != OBJ_BLOB) {
+ free(buf);
+ return NULL;
+ }
+
+ return read_attr_from_buf(buf, path, flags);
+}
+
+static struct attr_stack *read_attr_from_index(struct index_state *istate,
+ const char *path, unsigned flags)
+{
+ char *buf;
+ unsigned long size;
+
if (!istate)
return NULL;
@@ -754,32 +820,27 @@ static struct attr_stack *read_attr_from_index(struct index_state *istate,
if (!path_in_cone_mode_sparse_checkout(path, istate))
return NULL;
- buf = read_blob_data_from_index(istate, path, NULL);
+ buf = read_blob_data_from_index(istate, path, &size);
if (!buf)
return NULL;
-
- CALLOC_ARRAY(res, 1);
- for (sp = buf; *sp; ) {
- char *ep;
- int more;
-
- ep = strchrnul(sp, '\n');
- more = (*ep == '\n');
- *ep = '\0';
- handle_attr_line(res, sp, path, ++lineno, flags);
- sp = ep + more;
+ if (size >= ATTR_MAX_FILE_SIZE) {
+ warning(_("ignoring overly large gitattributes blob '%s'"), path);
+ return NULL;
}
- free(buf);
- return res;
+
+ return read_attr_from_buf(buf, path, flags);
}
static struct attr_stack *read_attr(struct index_state *istate,
+ const struct object_id *tree_oid,
const char *path, unsigned flags)
{
struct attr_stack *res = NULL;
if (direction == GIT_ATTR_INDEX) {
res = read_attr_from_index(istate, path, flags);
+ } else if (tree_oid) {
+ res = read_attr_from_blob(istate, tree_oid, path, flags);
} else if (!is_bare_repository()) {
if (direction == GIT_ATTR_CHECKOUT) {
res = read_attr_from_index(istate, path, flags);
@@ -839,6 +900,7 @@ static void push_stack(struct attr_stack **attr_stack_p,
}
static void bootstrap_attr_stack(struct index_state *istate,
+ const struct object_id *tree_oid,
struct attr_stack **stack)
{
struct attr_stack *e;
@@ -864,7 +926,7 @@ static void bootstrap_attr_stack(struct index_state *istate,
}
/* root directory */
- e = read_attr(istate, GITATTRIBUTES_FILE, flags | READ_ATTR_NOFOLLOW);
+ e = read_attr(istate, tree_oid, GITATTRIBUTES_FILE, flags | READ_ATTR_NOFOLLOW);
push_stack(stack, e, xstrdup(""), 0);
/* info frame */
@@ -878,6 +940,7 @@ static void bootstrap_attr_stack(struct index_state *istate,
}
static void prepare_attr_stack(struct index_state *istate,
+ const struct object_id *tree_oid,
const char *path, int dirlen,
struct attr_stack **stack)
{
@@ -899,7 +962,7 @@ static void prepare_attr_stack(struct index_state *istate,
* .gitattributes in deeper directories to shallower ones,
* and finally use the built-in set as the default.
*/
- bootstrap_attr_stack(istate, stack);
+ bootstrap_attr_stack(istate, tree_oid, stack);
/*
* Pop the "info" one that is always at the top of the stack.
@@ -954,7 +1017,7 @@ static void prepare_attr_stack(struct index_state *istate,
strbuf_add(&pathbuf, path + pathbuf.len, (len - pathbuf.len));
strbuf_addf(&pathbuf, "/%s", GITATTRIBUTES_FILE);
- next = read_attr(istate, pathbuf.buf, READ_ATTR_NOFOLLOW);
+ next = read_attr(istate, tree_oid, pathbuf.buf, READ_ATTR_NOFOLLOW);
/* reset the pathbuf to not include "/.gitattributes" */
strbuf_setlen(&pathbuf, len);
@@ -999,12 +1062,12 @@ static int macroexpand_one(struct all_attrs_item *all_attrs, int nr, int rem);
static int fill_one(struct all_attrs_item *all_attrs,
const struct match_attr *a, int rem)
{
- int i;
+ size_t i;
- for (i = a->num_attr - 1; rem > 0 && i >= 0; i--) {
- const struct git_attr *attr = a->state[i].attr;
+ for (i = a->num_attr; rem > 0 && i > 0; i--) {
+ const struct git_attr *attr = a->state[i - 1].attr;
const char **n = &(all_attrs[attr->attr_nr].value);
- const char *v = a->state[i].setto;
+ const char *v = a->state[i - 1].setto;
if (*n == ATTR__UNKNOWN) {
*n = v;
@@ -1020,11 +1083,11 @@ static int fill(const char *path, int pathlen, int basename_offset,
struct all_attrs_item *all_attrs, int rem)
{
for (; rem > 0 && stack; stack = stack->prev) {
- int i;
+ unsigned i;
const char *base = stack->origin ? stack->origin : "";
- for (i = stack->num_matches - 1; 0 < rem && 0 <= i; i--) {
- const struct match_attr *a = stack->attrs[i];
+ for (i = stack->num_matches; 0 < rem && 0 < i; i--) {
+ const struct match_attr *a = stack->attrs[i - 1];
if (a->is_macro)
continue;
if (path_matches(path, pathlen, basename_offset,
@@ -1055,11 +1118,11 @@ static void determine_macros(struct all_attrs_item *all_attrs,
const struct attr_stack *stack)
{
for (; stack; stack = stack->prev) {
- int i;
- for (i = stack->num_matches - 1; i >= 0; i--) {
- const struct match_attr *ma = stack->attrs[i];
+ unsigned i;
+ for (i = stack->num_matches; i > 0; i--) {
+ const struct match_attr *ma = stack->attrs[i - 1];
if (ma->is_macro) {
- int n = ma->u.attr->attr_nr;
+ unsigned int n = ma->u.attr->attr_nr;
if (!all_attrs[n].macro) {
all_attrs[n].macro = ma;
}
@@ -1074,8 +1137,8 @@ static void determine_macros(struct all_attrs_item *all_attrs,
* Otherwise all attributes are collected.
*/
static void collect_some_attrs(struct index_state *istate,
- const char *path,
- struct attr_check *check)
+ const struct object_id *tree_oid,
+ const char *path, struct attr_check *check)
{
int pathlen, rem, dirlen;
const char *cp, *last_slash = NULL;
@@ -1094,7 +1157,7 @@ static void collect_some_attrs(struct index_state *istate,
dirlen = 0;
}
- prepare_attr_stack(istate, path, dirlen, &check->stack);
+ prepare_attr_stack(istate, tree_oid, path, dirlen, &check->stack);
all_attrs_init(&g_attr_hashmap, check);
determine_macros(check->all_attrs, check->stack);
@@ -1103,15 +1166,15 @@ static void collect_some_attrs(struct index_state *istate,
}
void git_check_attr(struct index_state *istate,
- const char *path,
+ const struct object_id *tree_oid, const char *path,
struct attr_check *check)
{
int i;
- collect_some_attrs(istate, path, check);
+ collect_some_attrs(istate, tree_oid, path, check);
for (i = 0; i < check->nr; i++) {
- size_t n = check->items[i].attr->attr_nr;
+ unsigned int n = check->items[i].attr->attr_nr;
const char *value = check->all_attrs[n].value;
if (value == ATTR__UNKNOWN)
value = ATTR__UNSET;
@@ -1119,13 +1182,13 @@ void git_check_attr(struct index_state *istate,
}
}
-void git_all_attrs(struct index_state *istate,
+void git_all_attrs(struct index_state *istate, const struct object_id *tree_oid,
const char *path, struct attr_check *check)
{
int i;
attr_check_reset(check);
- collect_some_attrs(istate, path, check);
+ collect_some_attrs(istate, tree_oid, path, check);
for (i = 0; i < check->all_attrs_nr; i++) {
const char *name = check->all_attrs[i].attr->name;
diff --git a/attr.h b/attr.h
index 3fb40cced0..58a2bc1344 100644
--- a/attr.h
+++ b/attr.h
@@ -107,7 +107,20 @@
* - Free the `attr_check` struct by calling `attr_check_free()`.
*/
+/**
+ * The maximum line length for a gitattributes file. If the line exceeds this
+ * length we will ignore it.
+ */
+#define ATTR_MAX_LINE_LENGTH 2048
+
+ /**
+ * The maximum size of the giattributes file. If the file exceeds this size we
+ * will ignore it.
+ */
+#define ATTR_MAX_FILE_SIZE (100 * 1024 * 1024)
+
struct index_state;
+struct object_id;
/**
* An attribute is an opaque object that is identified by its name. Pass the
@@ -190,13 +203,14 @@ void attr_check_free(struct attr_check *check);
const char *git_attr_name(const struct git_attr *);
void git_check_attr(struct index_state *istate,
- const char *path, struct attr_check *check);
+ const struct object_id *tree_oid, const char *path,
+ struct attr_check *check);
/*
* Retrieve all attributes that apply to the specified path.
* check holds the attributes and their values.
*/
-void git_all_attrs(struct index_state *istate,
+void git_all_attrs(struct index_state *istate, const struct object_id *tree_oid,
const char *path, struct attr_check *check);
enum git_attr_direction {
diff --git a/bisect.c b/bisect.c
index ec7487e683..ef5ee5a643 100644
--- a/bisect.c
+++ b/bisect.c
@@ -472,7 +472,6 @@ static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
-static GIT_PATH_FUNC(git_path_head_name, "head-name")
static void read_bisect_paths(struct strvec *array)
{
@@ -1188,8 +1187,6 @@ int bisect_clean_state(void)
unlink_or_warn(git_path_bisect_run());
unlink_or_warn(git_path_bisect_terms());
unlink_or_warn(git_path_bisect_first_parent());
- /* Cleanup head-name if it got left by an old version of git-bisect */
- unlink_or_warn(git_path_head_name());
/*
* Cleanup BISECT_START last to support the --no-checkout option
* introduced in the commit 4796e823a.
diff --git a/blob.c b/blob.c
index 182718aba9..8f83523b0c 100644
--- a/blob.c
+++ b/blob.c
@@ -13,8 +13,7 @@ struct blob *lookup_blob(struct repository *r, const struct object_id *oid)
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 --git a/blob.h b/blob.h
index 1664872055..74555c90c4 100644
--- a/blob.h
+++ b/blob.h
@@ -11,8 +11,6 @@ struct blob {
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 @@ int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size);
* 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 --git a/builtin.h b/builtin.h
index 8901a34d6b..46cc789789 100644
--- a/builtin.h
+++ b/builtin.h
@@ -51,10 +51,6 @@
* on bare repositories.
* This only makes sense when `RUN_SETUP` is also set.
*
- * `SUPPORT_SUPER_PREFIX`:
- *
- * The built-in supports `--super-prefix`.
- *
* `DELAY_PAGER_CONFIG`:
*
* If RUN_SETUP or RUN_SETUP_GENTLY is set, git.c normally handles
@@ -116,7 +112,7 @@ int cmd_am(int argc, const char **argv, const char *prefix);
int cmd_annotate(int argc, const char **argv, const char *prefix);
int cmd_apply(int argc, const char **argv, const char *prefix);
int cmd_archive(int argc, const char **argv, const char *prefix);
-int cmd_bisect__helper(int argc, const char **argv, const char *prefix);
+int cmd_bisect(int argc, const char **argv, const char *prefix);
int cmd_blame(int argc, const char **argv, const char *prefix);
int cmd_branch(int argc, const char **argv, const char *prefix);
int cmd_bugreport(int argc, const char **argv, const char *prefix);
diff --git a/builtin/add.c b/builtin/add.c
index 76277df326..0c60402267 100644
--- a/builtin/add.c
+++ b/builtin/add.c
@@ -88,7 +88,7 @@ static int fix_unmerged_status(struct diff_filepair *p,
}
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;
@@ -695,6 +695,6 @@ finish:
die(_("Unable to write new index file"));
dir_clear(&dir);
- UNLEAK(pathspec);
+ clear_pathspec(&pathspec);
return exit_status;
}
diff --git a/builtin/am.c b/builtin/am.c
index 30c9b3a9cd..82a41cbfc4 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -117,6 +117,7 @@ struct am_state {
/* various operating modes and command line options */
int interactive;
+ int no_verify;
int threeway;
int quiet;
int signoff; /* enum signoff_type */
@@ -472,10 +473,12 @@ static void am_destroy(const struct am_state *state)
*/
static int run_applypatch_msg_hook(struct am_state *state)
{
- int ret;
+ int ret = 0;
assert(state->msg);
- ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);
+
+ if (!state->no_verify)
+ ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);
if (!ret) {
FREE_AND_NULL(state->msg);
@@ -1476,6 +1479,7 @@ static int run_apply(const struct am_state *state, const char *index_file)
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 +1487,14 @@ static int run_apply(const struct am_state *state, const char *index_file)
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.
+ */
+ DUP_ARRAY(apply_argv, apply_opts.v, apply_opts.nr);
+
+ opts_left = apply_parse_options(apply_opts.nr, apply_argv,
&apply_state, &force_apply, &options,
NULL);
@@ -1513,6 +1524,7 @@ static int run_apply(const struct am_state *state, const char *index_file)
strvec_clear(&apply_paths);
strvec_clear(&apply_opts);
clear_apply_state(&apply_state);
+ free(apply_argv);
if (res)
return res;
@@ -1640,7 +1652,7 @@ static void do_commit(const struct am_state *state)
const char *reflog_msg, *author, *committer = NULL;
struct strbuf sb = STRBUF_INIT;
- if (run_hooks("pre-applypatch"))
+ if (!state->no_verify && run_hooks("pre-applypatch"))
exit(1);
if (write_cache_as_tree(&tree, 0, NULL))
@@ -2330,6 +2342,8 @@ int cmd_am(int argc, const char **argv, const char *prefix)
struct option options[] = {
OPT_BOOL('i', "interactive", &state.interactive,
N_("run interactively")),
+ OPT_BOOL('n', "no-verify", &state.no_verify,
+ N_("bypass pre-applypatch and applypatch-msg hooks")),
OPT_HIDDEN_BOOL('b', "binary", &binary,
N_("historical option -- no-op")),
OPT_BOOL('3', "3way", &state.threeway,
diff --git a/builtin/bisect--helper.c b/builtin/bisect.c
index 6e41cbdb2d..7301740267 100644
--- a/builtin/bisect--helper.c
+++ b/builtin/bisect.c
@@ -15,23 +15,44 @@ static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
-static GIT_PATH_FUNC(git_path_head_name, "head-name")
static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
-static const char * const git_bisect_helper_usage[] = {
- N_("git bisect--helper --bisect-reset [<commit>]"),
- "git bisect--helper --bisect-terms [--term-good | --term-old | --term-bad | --term-new]",
- N_("git bisect--helper --bisect-start [--term-{new,bad}=<term> --term-{old,good}=<term>]"
- " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<paths>...]"),
- "git bisect--helper --bisect-next",
- N_("git bisect--helper --bisect-state (bad|new) [<rev>]"),
- N_("git bisect--helper --bisect-state (good|old) [<rev>...]"),
- N_("git bisect--helper --bisect-replay <filename>"),
- N_("git bisect--helper --bisect-skip [(<rev>|<range>)...]"),
- "git bisect--helper --bisect-visualize",
- N_("git bisect--helper --bisect-run <cmd>..."),
+#define BUILTIN_GIT_BISECT_START_USAGE \
+ N_("git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]" \
+ " [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]" \
+ " [<pathspec>...]")
+#define BUILTIN_GIT_BISECT_STATE_USAGE \
+ N_("git bisect (good|bad) [<rev>...]")
+#define BUILTIN_GIT_BISECT_TERMS_USAGE \
+ "git bisect terms [--term-good | --term-bad]"
+#define BUILTIN_GIT_BISECT_SKIP_USAGE \
+ N_("git bisect skip [(<rev>|<range>)...]")
+#define BUILTIN_GIT_BISECT_NEXT_USAGE \
+ "git bisect next"
+#define BUILTIN_GIT_BISECT_RESET_USAGE \
+ N_("git bisect reset [<commit>]")
+#define BUILTIN_GIT_BISECT_VISUALIZE_USAGE \
+ "git bisect visualize"
+#define BUILTIN_GIT_BISECT_REPLAY_USAGE \
+ N_("git bisect replay <logfile>")
+#define BUILTIN_GIT_BISECT_LOG_USAGE \
+ "git bisect log"
+#define BUILTIN_GIT_BISECT_RUN_USAGE \
+ N_("git bisect run <cmd>...")
+
+static const char * const git_bisect_usage[] = {
+ BUILTIN_GIT_BISECT_START_USAGE,
+ BUILTIN_GIT_BISECT_STATE_USAGE,
+ BUILTIN_GIT_BISECT_TERMS_USAGE,
+ BUILTIN_GIT_BISECT_SKIP_USAGE,
+ BUILTIN_GIT_BISECT_NEXT_USAGE,
+ BUILTIN_GIT_BISECT_RESET_USAGE,
+ BUILTIN_GIT_BISECT_VISUALIZE_USAGE,
+ BUILTIN_GIT_BISECT_REPLAY_USAGE,
+ BUILTIN_GIT_BISECT_LOG_USAGE,
+ BUILTIN_GIT_BISECT_RUN_USAGE,
NULL
};
@@ -656,7 +677,8 @@ static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char
return bisect_next(terms, prefix);
}
-static enum bisect_error bisect_start(struct bisect_terms *terms, const char **argv, int argc)
+static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
+ const char **argv)
{
int no_checkout = 0;
int first_parent_only = 0;
@@ -785,13 +807,6 @@ static enum bisect_error bisect_start(struct bisect_terms *terms, const char **a
strbuf_addstr(&start_head, oid_to_hex(&head_oid));
} else if (!get_oid(head, &head_oid) &&
skip_prefix(head, "refs/heads/", &head)) {
- /*
- * This error message should only be triggered by
- * cogito usage, and cogito users should understand
- * it relates to cg-seek.
- */
- if (!is_empty_or_missing_file(git_path_head_name()))
- return error(_("won't bisect on cg-seek'ed tree"));
strbuf_addstr(&start_head, head);
} else {
return error(_("bad HEAD - strange symbolic ref"));
@@ -886,13 +901,13 @@ static int bisect_autostart(struct bisect_terms *terms)
yesno = git_prompt(_("Do you want me to do it for you "
"[Y/n]? "), PROMPT_ECHO);
res = tolower(*yesno) == 'n' ?
- -1 : bisect_start(terms, empty_strvec, 0);
+ -1 : bisect_start(terms, 0, empty_strvec);
return res;
}
-static enum bisect_error bisect_state(struct bisect_terms *terms, const char **argv,
- int argc)
+static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
+ const char **argv)
{
const char *state;
int i, verify_expected = 1;
@@ -1011,7 +1026,7 @@ static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)
struct strvec argv = STRVEC_INIT;
int res;
sq_dequote_to_strvec(rev, &argv);
- res = bisect_start(terms, argv.v, argv.nr);
+ res = bisect_start(terms, argv.nr, argv.v);
strvec_clear(&argv);
return res;
}
@@ -1061,7 +1076,8 @@ static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *f
return bisect_auto_next(terms, NULL);
}
-static enum bisect_error bisect_skip(struct bisect_terms *terms, const char **argv, int argc)
+static enum bisect_error bisect_skip(struct bisect_terms *terms, int argc,
+ const char **argv)
{
int i;
enum bisect_error res;
@@ -1091,13 +1107,14 @@ static enum bisect_error bisect_skip(struct bisect_terms *terms, const char **ar
strvec_push(&argv_state, argv[i]);
}
}
- res = bisect_state(terms, argv_state.v, argv_state.nr);
+ res = bisect_state(terms, argv_state.nr, argv_state.v);
strvec_clear(&argv_state);
return res;
}
-static int bisect_visualize(struct bisect_terms *terms, const char **argv, int argc)
+static int bisect_visualize(struct bisect_terms *terms, int argc,
+ const char **argv)
{
struct child_process cmd = CHILD_PROCESS_INIT;
struct strbuf sb = STRBUF_INIT;
@@ -1180,7 +1197,7 @@ static int verify_good(const struct bisect_terms *terms, const char *command)
return rc;
}
-static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
+static int bisect_run(struct bisect_terms *terms, int argc, const char **argv)
{
int res = BISECT_OK;
struct strbuf command = STRBUF_INIT;
@@ -1191,13 +1208,13 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
if (bisect_next_check(terms, NULL))
return BISECT_FAILED;
- if (argc)
- sq_quote_argv(&command, argv);
- else {
+ if (!argc) {
error(_("bisect run failed: no command provided."));
return BISECT_FAILED;
}
+ sq_quote_argv(&command, argv);
+ strbuf_ltrim(&command);
while (1) {
res = do_bisect_run(command.buf);
@@ -1211,8 +1228,8 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
if (is_first_run && (res == 126 || res == 127)) {
int rc = verify_good(terms, command.buf);
is_first_run = 0;
- if (rc < 0) {
- error(_("unable to verify '%s' on good"
+ if (rc < 0 || 128 <= rc) {
+ error(_("unable to verify %s on good"
" revision"), command.buf);
res = BISECT_FAILED;
break;
@@ -1227,7 +1244,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
if (res < 0 || 128 <= res) {
error(_("bisect run failed: exit code %d from"
- " '%s' is < 0 or >= 128"), res, command.buf);
+ " %s is < 0 or >= 128"), res, command.buf);
break;
}
@@ -1249,7 +1266,7 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
saved_stdout = dup(1);
dup2(temporary_stdout_fd, 1);
- res = bisect_state(terms, &new_state, 1);
+ res = bisect_state(terms, 1, &new_state);
fflush(stdout);
dup2(saved_stdout, 1);
@@ -1261,14 +1278,14 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
if (res == BISECT_ONLY_SKIPPED_LEFT)
error(_("bisect run cannot continue any more"));
else if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) {
- printf(_("bisect run success"));
+ puts(_("bisect run success"));
res = BISECT_OK;
} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
- printf(_("bisect found first bad commit"));
+ puts(_("bisect found first bad commit"));
res = BISECT_OK;
} else if (res) {
- error(_("bisect run failed: 'git bisect--helper --bisect-state"
- " %s' exited with error code %d"), new_state, res);
+ error(_("bisect run failed: 'git bisect %s'"
+ " exited with error code %d"), new_state, res);
} else {
continue;
}
@@ -1282,7 +1299,8 @@ static int bisect_run(struct bisect_terms *terms, const char **argv, int argc)
static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED)
{
if (argc > 1)
- return error(_("--bisect-reset requires either no argument or a commit"));
+ return error(_("'%s' requires either no argument or a commit"),
+ "git bisect reset");
return bisect_reset(argc ? argv[0] : NULL);
}
@@ -1292,7 +1310,8 @@ static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNU
struct bisect_terms terms = { 0 };
if (argc > 1)
- return error(_("--bisect-terms requires 0 or 1 argument"));
+ return error(_("'%s' requires 0 or 1 argument"),
+ "git bisect terms");
res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
free_terms(&terms);
return res;
@@ -1304,7 +1323,7 @@ static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNU
struct bisect_terms terms = { 0 };
set_terms(&terms, "bad", "good");
- res = bisect_start(&terms, argv, argc);
+ res = bisect_start(&terms, argc, argv);
free_terms(&terms);
return res;
}
@@ -1315,29 +1334,16 @@ static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *pref
struct bisect_terms terms = { 0 };
if (argc)
- return error(_("--bisect-next requires 0 arguments"));
+ return error(_("'%s' requires 0 arguments"),
+ "git bisect next");
get_terms(&terms);
res = bisect_next(&terms, prefix);
free_terms(&terms);
return res;
}
-static int cmd_bisect__state(int argc, const char **argv, const char *prefix UNUSED)
-{
- int res;
- struct bisect_terms terms = { 0 };
-
- set_terms(&terms, "bad", "good");
- get_terms(&terms);
- res = bisect_state(&terms, argv, argc);
- free_terms(&terms);
- return res;
-}
-
-static int cmd_bisect__log(int argc, const char **argv UNUSED, const char *prefix UNUSED)
+static int cmd_bisect__log(int argc UNUSED, const char **argv UNUSED, const char *prefix UNUSED)
{
- if (argc)
- return error(_("--bisect-log requires 0 arguments"));
return bisect_log();
}
@@ -1361,7 +1367,7 @@ static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUS
set_terms(&terms, "bad", "good");
get_terms(&terms);
- res = bisect_skip(&terms, argv, argc);
+ res = bisect_skip(&terms, argc, argv);
free_terms(&terms);
return res;
}
@@ -1372,7 +1378,7 @@ static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix
struct bisect_terms terms = { 0 };
get_terms(&terms);
- res = bisect_visualize(&terms, argv, argc);
+ res = bisect_visualize(&terms, argc, argv);
free_terms(&terms);
return res;
}
@@ -1383,14 +1389,14 @@ static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSE
struct bisect_terms terms = { 0 };
if (!argc)
- return error(_("bisect run failed: no command provided."));
+ return error(_("'%s' failed: no command provided."), "git bisect run");
get_terms(&terms);
- res = bisect_run(&terms, argv, argc);
+ res = bisect_run(&terms, argc, argv);
free_terms(&terms);
return res;
}
-int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
+int cmd_bisect(int argc, const char **argv, const char *prefix)
{
int res = 0;
parse_opt_subcommand_fn *fn = NULL;
@@ -1399,7 +1405,6 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
OPT_SUBCOMMAND("terms", &fn, cmd_bisect__terms),
OPT_SUBCOMMAND("start", &fn, cmd_bisect__start),
OPT_SUBCOMMAND("next", &fn, cmd_bisect__next),
- OPT_SUBCOMMAND("state", &fn, cmd_bisect__state),
OPT_SUBCOMMAND("log", &fn, cmd_bisect__log),
OPT_SUBCOMMAND("replay", &fn, cmd_bisect__replay),
OPT_SUBCOMMAND("skip", &fn, cmd_bisect__skip),
@@ -1408,22 +1413,27 @@ int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
OPT_SUBCOMMAND("run", &fn, cmd_bisect__run),
OPT_END()
};
- argc = parse_options(argc, argv, prefix, options,
- git_bisect_helper_usage, 0);
-
- if (!fn)
- usage_with_options(git_bisect_helper_usage, options);
- argc--;
- argv++;
-
- res = fn(argc, argv, prefix);
-
- /*
- * Handle early success
- * From check_merge_bases > check_good_are_ancestors_of_bad > bisect_next_all
- */
- if ((res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) || (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND))
- res = BISECT_OK;
+ argc = parse_options(argc, argv, prefix, options, git_bisect_usage,
+ PARSE_OPT_SUBCOMMAND_OPTIONAL);
+
+ if (!fn) {
+ struct bisect_terms terms = { 0 };
+
+ if (!argc)
+ usage_msg_opt(_("need a command"), git_bisect_usage, options);
+
+ set_terms(&terms, "bad", "good");
+ get_terms(&terms);
+ if (check_and_set_terms(&terms, argv[0]))
+ usage_msg_optf(_("unknown command: '%s'"), git_bisect_usage,
+ options, argv[0]);
+ res = bisect_state(&terms, argc, argv);
+ free_terms(&terms);
+ } else {
+ argc--;
+ argv++;
+ res = fn(argc, argv, prefix);
+ }
- return -res;
+ return is_bisect_success(res) ? 0 : -res;
}
diff --git a/builtin/branch.c b/builtin/branch.c
index 9470c980c1..f63fd45edb 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -581,13 +581,13 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
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 --git a/builtin/bugreport.c b/builtin/bugreport.c
index 96052541cb..5bc254be80 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -106,6 +106,7 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
const char *user_relative_path = NULL;
char *prefixed_filename;
size_t output_path_len;
+ int ret;
const struct option bugreport_options[] = {
OPT_CALLBACK_F(0, "diagnose", &diagnose, N_("mode"),
@@ -182,7 +183,9 @@ int cmd_bugreport(int argc, const char **argv, const char *prefix)
user_relative_path);
free(prefixed_filename);
- UNLEAK(buffer);
- UNLEAK(report_path);
- return !!launch_editor(report_path.buf, NULL, NULL);
+ strbuf_release(&buffer);
+
+ ret = !!launch_editor(report_path.buf, NULL, NULL);
+ strbuf_release(&report_path);
+ return ret;
}
diff --git a/builtin/bundle.c b/builtin/bundle.c
index c12c09f854..acceef6200 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -55,13 +55,12 @@ static int parse_options_cmd_bundle(int argc,
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 <file> 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 --git a/builtin/cat-file.c b/builtin/cat-file.c
index b3be58b1fb..cc17635e76 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -132,8 +132,21 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
case 's':
oi.sizep = &size;
+
+ if (use_mailmap) {
+ oi.typep = &type;
+ oi.contentp = (void**)&buf;
+ }
+
if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0)
die("git cat-file: could not get object info");
+
+ if (use_mailmap && (type == OBJ_COMMIT || type == OBJ_TAG)) {
+ size_t s = size;
+ buf = replace_idents_using_mailmap(buf, &s);
+ size = cast_size_t_to_ulong(s);
+ }
+
printf("%"PRIuMAX"\n", (uintmax_t)size);
ret = 0;
goto cleanup;
@@ -431,6 +444,9 @@ static void batch_object_write(const char *obj_name,
if (!data->skip_object_info) {
int ret;
+ if (use_mailmap)
+ data->info.typep = &data->type;
+
if (pack)
ret = packed_object_info(the_repository, pack, offset,
&data->info);
@@ -444,6 +460,18 @@ static void batch_object_write(const char *obj_name,
fflush(stdout);
return;
}
+
+ if (use_mailmap && (data->type == OBJ_COMMIT || data->type == OBJ_TAG)) {
+ size_t s = data->size;
+ char *buf = NULL;
+
+ buf = repo_read_object_file(the_repository, &data->oid, &data->type,
+ &data->size);
+ buf = replace_idents_using_mailmap(buf, &s);
+ data->size = cast_size_t_to_ulong(s);
+
+ free(buf);
+ }
}
strbuf_reset(scratch);
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
index 0fef10eb6b..d7a40e674c 100644
--- a/builtin/check-attr.c
+++ b/builtin/check-attr.c
@@ -9,9 +9,10 @@
static int all_attrs;
static int cached_attrs;
static int stdin_paths;
+static char *source;
static const char * const check_attr_usage[] = {
-N_("git check-attr [-a | --all | <attr>...] [--] <pathname>..."),
-N_("git check-attr --stdin [-z] [-a | --all | <attr>...]"),
+N_("git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] <pathname>..."),
+N_("git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"),
NULL
};
@@ -23,6 +24,7 @@ static const struct option check_attr_options[] = {
OPT_BOOL(0 , "stdin", &stdin_paths, N_("read file names from stdin")),
OPT_BOOL('z', NULL, &nul_term_line,
N_("terminate input and output records by a NUL character")),
+ OPT_STRING(0, "source", &source, N_("<tree-ish>"), N_("which tree-ish to check attributes at")),
OPT_END()
};
@@ -55,27 +57,26 @@ static void output_attr(struct attr_check *check, const char *file)
}
}
-static void check_attr(const char *prefix,
- struct attr_check *check,
- int collect_all,
+static void check_attr(const char *prefix, struct attr_check *check,
+ const struct object_id *tree_oid, int collect_all,
const char *file)
+
{
char *full_path =
prefix_path(prefix, prefix ? strlen(prefix) : 0, file);
if (collect_all) {
- git_all_attrs(&the_index, full_path, check);
+ git_all_attrs(&the_index, tree_oid, full_path, check);
} else {
- git_check_attr(&the_index, full_path, check);
+ git_check_attr(&the_index, tree_oid, full_path, check);
}
output_attr(check, file);
free(full_path);
}
-static void check_attr_stdin_paths(const char *prefix,
- struct attr_check *check,
- int collect_all)
+static void check_attr_stdin_paths(const char *prefix, struct attr_check *check,
+ const struct object_id *tree_oid, int collect_all)
{
struct strbuf buf = STRBUF_INIT;
struct strbuf unquoted = STRBUF_INIT;
@@ -89,7 +90,7 @@ static void check_attr_stdin_paths(const char *prefix,
die("line is badly quoted");
strbuf_swap(&buf, &unquoted);
}
- check_attr(prefix, check, collect_all, buf.buf);
+ check_attr(prefix, check, tree_oid, collect_all, buf.buf);
maybe_flush_or_die(stdout, "attribute to stdout");
}
strbuf_release(&buf);
@@ -105,6 +106,8 @@ static NORETURN void error_with_usage(const char *msg)
int cmd_check_attr(int argc, const char **argv, const char *prefix)
{
struct attr_check *check;
+ struct object_id *tree_oid = NULL;
+ struct object_id initialized_oid;
int cnt, i, doubledash, filei;
if (!is_bare_repository())
@@ -176,11 +179,17 @@ int cmd_check_attr(int argc, const char **argv, const char *prefix)
}
}
+ if (source) {
+ if (repo_get_oid_tree(the_repository, source, &initialized_oid))
+ die("%s: not a valid tree-ish source", source);
+ tree_oid = &initialized_oid;
+ }
+
if (stdin_paths)
- check_attr_stdin_paths(prefix, check, all_attrs);
+ check_attr_stdin_paths(prefix, check, tree_oid, all_attrs);
else {
for (i = filei; i < argc; i++)
- check_attr(prefix, check, all_attrs, argv[i]);
+ check_attr(prefix, check, tree_oid, all_attrs, argv[i]);
maybe_flush_or_die(stdout, "attribute to stdout");
}
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 3fa29a08ee..5963e1b74b 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -232,7 +232,7 @@ static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
pos++;
}
if (!overlay_mode) {
- unlink_entry(ce);
+ unlink_entry(ce, NULL);
return 0;
}
if (stage == 2)
@@ -1270,7 +1270,7 @@ static int parse_branchname_arg(int argc, const char **argv,
* between A and B, A...B names that merge base.
*
* (b) If <something> is _not_ a commit, either "--" is present
- * or <something> is not a path, no -t or -b was given, and
+ * or <something> is not a path, no -t or -b was given,
* and there is a tracking branch whose name is <something>
* in one and only one remote (or if the branch exists on the
* remote named in checkout.defaultRemote), then this is a
@@ -1471,6 +1471,8 @@ static void die_if_some_operation_in_progress(void)
"or \"git worktree add\"."));
if (state.bisect_in_progress)
warning(_("you are switching branch while bisecting"));
+
+ wt_status_state_free_buffers(&state);
}
static int checkout_branch(struct checkout_opts *opts,
diff --git a/builtin/clone.c b/builtin/clone.c
index f518bb2dc1..5453ba5277 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -1271,6 +1271,27 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
if (refs)
mapped_refs = wanted_peer_refs(refs, &remote->fetch);
+ if (!bundle_uri) {
+ /*
+ * Populate transport->got_remote_bundle_uri and
+ * transport->bundle_uri. We might get nothing.
+ */
+ transport_get_remote_bundle_uri(transport);
+
+ if (transport->bundles &&
+ hashmap_get_size(&transport->bundles->bundles)) {
+ /* At this point, we need the_repository to match the cloned repo. */
+ if (repo_init(the_repository, git_dir, work_tree))
+ warning(_("failed to initialize the repo, skipping bundle URI"));
+ else if (fetch_bundle_list(the_repository,
+ transport->bundles))
+ warning(_("failed to fetch advertised bundles"));
+ } else {
+ clear_bundle_list(transport->bundles);
+ FREE_AND_NULL(transport->bundles);
+ }
+ }
+
if (mapped_refs) {
int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
diff --git a/builtin/commit.c b/builtin/commit.c
index 06b1330346..44b763d7cd 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -991,8 +991,11 @@ static int prepare_to_commit(const char *index_file, const char *prefix,
struct object_id oid;
const char *parent = "HEAD";
- if (!active_nr && read_cache() < 0)
- die(_("Cannot read index"));
+ if (!active_nr) {
+ discard_cache();
+ if (read_cache() < 0)
+ die(_("Cannot read index"));
+ }
if (amend)
parent = "HEAD^1";
@@ -1875,8 +1878,8 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
apply_autostash(git_path_merge_autostash(the_repository));
cleanup:
- UNLEAK(author_ident);
- UNLEAK(err);
- UNLEAK(sb);
+ strbuf_release(&author_ident);
+ strbuf_release(&err);
+ strbuf_release(&sb);
return ret;
}
diff --git a/builtin/config.c b/builtin/config.c
index 753e5fac29..060cf9f3e0 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -639,8 +639,9 @@ static char *default_user_config(void)
int cmd_config(int argc, const char **argv, const char *prefix)
{
int nongit = !startup_info->have_repository;
- char *value;
+ char *value = NULL;
int flags = 0;
+ int ret = 0;
given_config_source.file = xstrdup_or_null(getenv(CONFIG_ENVIRONMENT));
@@ -856,44 +857,38 @@ int cmd_config(int argc, const char **argv, const char *prefix)
free(config_file);
}
else if (actions == ACTION_SET) {
- int ret;
check_write();
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1]);
- UNLEAK(value);
ret = git_config_set_in_file_gently(given_config_source.file, argv[0], value);
if (ret == CONFIG_NOTHING_SET)
error(_("cannot overwrite multiple values with a single value\n"
" Use a regexp, --add or --replace-all to change %s."), argv[0]);
- return ret;
}
else if (actions == ACTION_SET_ALL) {
check_write();
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1]);
- UNLEAK(value);
- return git_config_set_multivar_in_file_gently(given_config_source.file,
- argv[0], value, argv[2],
- flags);
+ ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+ argv[0], value, argv[2],
+ flags);
}
else if (actions == ACTION_ADD) {
check_write();
check_argc(argc, 2, 2);
value = normalize_value(argv[0], argv[1]);
- UNLEAK(value);
- return git_config_set_multivar_in_file_gently(given_config_source.file,
- argv[0], value,
- CONFIG_REGEX_NONE,
- flags);
+ ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+ argv[0], value,
+ CONFIG_REGEX_NONE,
+ flags);
}
else if (actions == ACTION_REPLACE_ALL) {
check_write();
check_argc(argc, 2, 3);
value = normalize_value(argv[0], argv[1]);
- UNLEAK(value);
- return git_config_set_multivar_in_file_gently(given_config_source.file,
- argv[0], value, argv[2],
- flags | CONFIG_FLAGS_MULTI_REPLACE);
+ ret = git_config_set_multivar_in_file_gently(given_config_source.file,
+ argv[0], value, argv[2],
+ flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_GET) {
check_argc(argc, 1, 2);
@@ -934,26 +929,28 @@ int cmd_config(int argc, const char **argv, const char *prefix)
flags | CONFIG_FLAGS_MULTI_REPLACE);
}
else if (actions == ACTION_RENAME_SECTION) {
- int ret;
check_write();
check_argc(argc, 2, 2);
ret = git_config_rename_section_in_file(given_config_source.file,
argv[0], argv[1]);
if (ret < 0)
return ret;
- if (ret == 0)
+ else if (!ret)
die(_("no such section: %s"), argv[0]);
+ else
+ ret = 0;
}
else if (actions == ACTION_REMOVE_SECTION) {
- int ret;
check_write();
check_argc(argc, 1, 1);
ret = git_config_rename_section_in_file(given_config_source.file,
argv[0], NULL);
if (ret < 0)
return ret;
- if (ret == 0)
+ else if (!ret)
die(_("no such section: %s"), argv[0]);
+ else
+ ret = 0;
}
else if (actions == ACTION_GET_COLOR) {
check_argc(argc, 1, 2);
@@ -966,5 +963,6 @@ int cmd_config(int argc, const char **argv, const char *prefix)
return get_colorbool(argv[0], argc == 2);
}
- return 0;
+ free(value);
+ return ret;
}
diff --git a/builtin/diff.c b/builtin/diff.c
index 163f2c6a87..26f1e532c6 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -612,7 +612,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
if (1 < rev.diffopt.skip_stat_unmatch)
refresh_index_quietly();
release_revisions(&rev);
- UNLEAK(ent);
+ object_array_clear(&ent);
UNLEAK(blob);
return result;
}
diff --git a/builtin/difftool.c b/builtin/difftool.c
index d9b76226f6..758e7bd3b6 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -361,7 +361,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
struct hashmap symlinks2 = HASHMAP_INIT(pair_cmp, NULL);
struct hashmap_iter iter;
struct pair_entry *entry;
- struct index_state wtindex;
+ struct index_state wtindex = INDEX_STATE_INIT;
struct checkout lstate, rstate;
int err = 0;
struct child_process cmd = CHILD_PROCESS_INIT;
@@ -387,8 +387,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
mkdir(ldir.buf, 0700);
mkdir(rdir.buf, 0700);
- memset(&wtindex, 0, sizeof(wtindex));
-
memset(&lstate, 0, sizeof(lstate));
lstate.base_dir = lbase_dir = xstrdup(ldir.buf);
lstate.base_dir_len = ldir.len;
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 3b3314e7b2..39a890fc00 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -409,7 +409,7 @@ static const char *anonymize_oid(const char *oid_hex)
}
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 --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
index 6f30a4f93a..0feef8caf6 100644
--- a/builtin/fsmonitor--daemon.c
+++ b/builtin/fsmonitor--daemon.c
@@ -710,6 +710,7 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
"fsmonitor: unsupported V1 protocol '%s'"),
command);
do_trivial = 1;
+ do_cookie = 1;
} else {
/* We have "builtin:*" */
@@ -719,6 +720,7 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
"fsmonitor: invalid V2 protocol token '%s'",
command);
do_trivial = 1;
+ do_cookie = 1;
} else {
/*
@@ -1209,7 +1211,7 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
* events.
*/
if (pthread_create(&state->listener_thread, NULL,
- fsm_listen__thread_proc, state) < 0) {
+ fsm_listen__thread_proc, state)) {
ipc_server_stop_async(state->ipc_server_data);
err = error(_("could not start fsmonitor listener thread"));
goto cleanup;
@@ -1220,7 +1222,7 @@ static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
* Start the health thread to watch over our process.
*/
if (pthread_create(&state->health_thread, NULL,
- fsm_health__thread_proc, state) < 0) {
+ fsm_health__thread_proc, state)) {
ipc_server_stop_async(state->ipc_server_data);
err = error(_("could not start fsmonitor health thread"));
goto cleanup;
diff --git a/builtin/log.c b/builtin/log.c
index 89447a5083..057e299c24 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -52,6 +52,7 @@ static int decoration_style;
static int decoration_given;
static int use_mailmap_config = 1;
static unsigned int force_in_body_from;
+static int stdout_mboxrd;
static const char *fmt_patch_subject_prefix = "PATCH";
static int fmt_patch_name_max = FORMAT_PATCH_NAME_MAX_DEFAULT;
static const char *fmt_pretty;
@@ -1077,6 +1078,10 @@ static int git_format_config(const char *var, const char *value, void *cb)
cover_from_description_mode = parse_cover_from_description(value);
return 0;
}
+ if (!strcmp(var, "format.mboxrd")) {
+ stdout_mboxrd = git_config_bool(var, value);
+ return 0;
+ }
return git_log_config(var, value, cb);
}
@@ -2105,6 +2110,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.diffopt.close_file, "--output",
!!output_directory, "--output-directory");
+ if (use_stdout && stdout_mboxrd)
+ rev.commit_format = CMIT_FMT_MBOXRD;
+
if (use_stdout) {
setup_pager();
} else if (!rev.diffopt.close_file) {
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
index 4cf8a23648..a03b559eca 100644
--- a/builtin/ls-files.c
+++ b/builtin/ls-files.c
@@ -613,6 +613,7 @@ void overlay_tree_on_index(struct index_state *istate,
if (!fn)
fn = read_one_entry_quick;
err = read_tree(the_repository, tree, &pathspec, fn, istate);
+ clear_pathspec(&pathspec);
if (err)
die("unable to read tree entries %s", tree_name);
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
index c3ea09281a..8cc8c995df 100644
--- a/builtin/ls-tree.c
+++ b/builtin/ls-tree.c
@@ -14,37 +14,11 @@
#include "parse-options.h"
#include "pathspec.h"
-static int line_termination = '\n';
-#define LS_RECURSIVE 1
-#define LS_TREE_ONLY (1 << 1)
-#define LS_SHOW_TREES (1 << 2)
-static int abbrev;
-static int ls_options;
-static struct pathspec pathspec;
-static int chomp_prefix;
-static const char *ls_tree_prefix;
-static const char *format;
-struct show_tree_data {
- unsigned mode;
- enum object_type type;
- const struct object_id *oid;
- const char *pathname;
- struct strbuf *base;
-};
-
-static const char * const ls_tree_usage[] = {
+static const char * const ls_tree_usage[] = {
N_("git ls-tree [<options>] <tree-ish> [<path>...]"),
NULL
};
-static enum ls_tree_cmdmode {
- MODE_DEFAULT = 0,
- MODE_LONG,
- MODE_NAME_ONLY,
- MODE_NAME_STATUS,
- MODE_OBJECT_ONLY,
-} cmdmode;
-
static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
const enum object_type type, unsigned int padded)
{
@@ -64,10 +38,34 @@ static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
}
}
+struct ls_tree_options {
+ unsigned null_termination:1;
+ int abbrev;
+ enum ls_tree_path_options {
+ LS_RECURSIVE = 1 << 0,
+ LS_TREE_ONLY = 1 << 1,
+ LS_SHOW_TREES = 1 << 2,
+ } ls_options;
+ struct pathspec pathspec;
+ int chomp_prefix;
+ const char *ls_tree_prefix;
+ const char *format;
+};
+
+struct show_tree_data {
+ struct ls_tree_options *options;
+ unsigned mode;
+ enum object_type type;
+ const struct object_id *oid;
+ const char *pathname;
+ struct strbuf *base;
+};
+
static size_t expand_show_tree(struct strbuf *sb, const char *start,
void *context)
{
struct show_tree_data *data = context;
+ struct ls_tree_options *options = data->options;
const char *end;
const char *p;
unsigned int errlen;
@@ -92,18 +90,18 @@ static size_t expand_show_tree(struct strbuf *sb, const char *start,
} else if (skip_prefix(start, "(objectsize)", &p)) {
expand_objectsize(sb, data->oid, data->type, 0);
} else if (skip_prefix(start, "(objectname)", &p)) {
- strbuf_add_unique_abbrev(sb, data->oid, abbrev);
+ strbuf_add_unique_abbrev(sb, data->oid, options->abbrev);
} else if (skip_prefix(start, "(path)", &p)) {
const char *name = data->base->buf;
- const char *prefix = chomp_prefix ? ls_tree_prefix : NULL;
- struct strbuf quoted = STRBUF_INIT;
+ const char *prefix = options->chomp_prefix ? options->ls_tree_prefix : NULL;
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, &quoted, NULL, 0);
- strbuf_addbuf(sb, &quoted);
+ quote_c_style(name, sb, NULL, 0);
+ strbuf_setlen(data->base, baselen);
strbuf_release(&sbuf);
- strbuf_release(&quoted);
} else {
errlen = (unsigned long)len;
die(_("bad ls-tree format: %%%.*s"), errlen, start);
@@ -111,18 +109,19 @@ static size_t expand_show_tree(struct strbuf *sb, const char *start,
return len;
}
-static int show_recursive(const char *base, size_t baselen, const char *pathname)
+static int show_recursive(struct ls_tree_options *options, const char *base,
+ size_t baselen, const char *pathname)
{
int i;
- if (ls_options & LS_RECURSIVE)
+ if (options->ls_options & LS_RECURSIVE)
return 1;
- if (!pathspec.nr)
+ if (!options->pathspec.nr)
return 0;
- for (i = 0; i < pathspec.nr; i++) {
- const char *spec = pathspec.items[i].match;
+ for (i = 0; i < options->pathspec.nr; i++) {
+ const char *spec = options->pathspec.items[i].match;
size_t len, speclen;
if (strncmp(base, spec, baselen))
@@ -142,14 +141,14 @@ static int show_recursive(const char *base, size_t baselen, const char *pathname
}
static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
- const char *pathname, unsigned mode, void *context UNUSED)
+ const char *pathname, unsigned mode, void *context)
{
- size_t baselen;
+ struct ls_tree_options *options = context;
int recurse = 0;
struct strbuf sb = STRBUF_INIT;
enum object_type type = object_type(mode);
-
- struct show_tree_data data = {
+ struct show_tree_data cb_data = {
+ .options = options,
.mode = mode,
.type = type,
.oid = oid,
@@ -157,94 +156,100 @@ static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
.base = base,
};
- if (type == OBJ_TREE && show_recursive(base->buf, base->len, pathname))
+ if (type == OBJ_TREE && show_recursive(options, base->buf, base->len, pathname))
recurse = READ_TREE_RECURSIVE;
- if (type == OBJ_TREE && recurse && !(ls_options & LS_SHOW_TREES))
+ if (type == OBJ_TREE && recurse && !(options->ls_options & LS_SHOW_TREES))
return recurse;
- if (type == OBJ_BLOB && (ls_options & LS_TREE_ONLY))
+ if (type == OBJ_BLOB && (options->ls_options & LS_TREE_ONLY))
return 0;
- baselen = base->len;
- strbuf_expand(&sb, format, expand_show_tree, &data);
- strbuf_addch(&sb, line_termination);
+ strbuf_expand(&sb, options->format, expand_show_tree, &cb_data);
+ strbuf_addch(&sb, options->null_termination ? '\0' : '\n');
fwrite(sb.buf, sb.len, 1, stdout);
strbuf_release(&sb);
- strbuf_setlen(base, baselen);
return recurse;
}
-static int show_tree_common(struct show_tree_data *data, int *recurse,
- const struct object_id *oid, struct strbuf *base,
- const char *pathname, unsigned mode)
+static int show_tree_common(struct ls_tree_options *options, int *recurse,
+ struct strbuf *base, const char *pathname,
+ enum object_type type)
{
- enum object_type type = object_type(mode);
int ret = -1;
-
*recurse = 0;
- data->mode = mode;
- data->type = type;
- data->oid = oid;
- data->pathname = pathname;
- data->base = base;
if (type == OBJ_BLOB) {
- if (ls_options & LS_TREE_ONLY)
+ if (options->ls_options & LS_TREE_ONLY)
ret = 0;
} else if (type == OBJ_TREE &&
- show_recursive(base->buf, base->len, pathname)) {
+ show_recursive(options, base->buf, base->len, pathname)) {
*recurse = READ_TREE_RECURSIVE;
- if (!(ls_options & LS_SHOW_TREES))
+ if (!(options->ls_options & LS_SHOW_TREES))
ret = *recurse;
}
return ret;
}
-static void show_tree_common_default_long(struct strbuf *base,
+static void show_tree_common_default_long(struct ls_tree_options *options,
+ struct strbuf *base,
const char *pathname,
const size_t baselen)
{
+ const char *prefix = options->chomp_prefix ? options->ls_tree_prefix : NULL;
+
strbuf_addstr(base, pathname);
- write_name_quoted_relative(base->buf,
- chomp_prefix ? ls_tree_prefix : NULL, stdout,
- line_termination);
+
+ if (options->null_termination) {
+ struct strbuf sb = STRBUF_INIT;
+ const char *name = relative_path(base->buf, prefix, &sb);
+
+ fputs(name, stdout);
+ fputc('\0', stdout);
+
+ strbuf_release(&sb);
+ } else {
+ write_name_quoted_relative(base->buf, prefix, stdout, '\n');
+ }
+
strbuf_setlen(base, baselen);
}
static int show_tree_default(const struct object_id *oid, struct strbuf *base,
const char *pathname, unsigned mode,
- void *context UNUSED)
+ void *context)
{
+ struct ls_tree_options *options = context;
int early;
int recurse;
- struct show_tree_data data = { 0 };
+ enum object_type type = object_type(mode);
- early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ early = show_tree_common(options, &recurse, base, pathname, type);
if (early >= 0)
return early;
- printf("%06o %s %s\t", data.mode, type_name(data.type),
- find_unique_abbrev(data.oid, abbrev));
- show_tree_common_default_long(base, pathname, data.base->len);
+ printf("%06o %s %s\t", mode, type_name(object_type(mode)),
+ find_unique_abbrev(oid, options->abbrev));
+ show_tree_common_default_long(options, base, pathname, base->len);
return recurse;
}
static int show_tree_long(const struct object_id *oid, struct strbuf *base,
const char *pathname, unsigned mode,
- void *context UNUSED)
+ void *context)
{
+ struct ls_tree_options *options = context;
int early;
int recurse;
- struct show_tree_data data = { 0 };
char size_text[24];
+ enum object_type type = object_type(mode);
- early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ early = show_tree_common(options, &recurse, base, pathname, type);
if (early >= 0)
return early;
- if (data.type == OBJ_BLOB) {
+ if (type == OBJ_BLOB) {
unsigned long size;
- if (oid_object_info(the_repository, data.oid, &size) == OBJ_BAD)
+ if (oid_object_info(the_repository, oid, &size) == OBJ_BAD)
xsnprintf(size_text, sizeof(size_text), "BAD");
else
xsnprintf(size_text, sizeof(size_text),
@@ -253,49 +258,76 @@ static int show_tree_long(const struct object_id *oid, struct strbuf *base,
xsnprintf(size_text, sizeof(size_text), "-");
}
- printf("%06o %s %s %7s\t", data.mode, type_name(data.type),
- find_unique_abbrev(data.oid, abbrev), size_text);
- show_tree_common_default_long(base, pathname, data.base->len);
+ printf("%06o %s %s %7s\t", mode, type_name(type),
+ find_unique_abbrev(oid, options->abbrev), size_text);
+ show_tree_common_default_long(options, base, pathname, base->len);
return recurse;
}
static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
const char *pathname, unsigned mode,
- void *context UNUSED)
+ void *context)
{
+ struct ls_tree_options *options = context;
int early;
int recurse;
const size_t baselen = base->len;
- struct show_tree_data data = { 0 };
+ enum object_type type = object_type(mode);
+ const char *prefix;
- early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ early = show_tree_common(options, &recurse, base, pathname, type);
if (early >= 0)
return early;
+ prefix = options->chomp_prefix ? options->ls_tree_prefix : NULL;
strbuf_addstr(base, pathname);
- write_name_quoted_relative(base->buf,
- chomp_prefix ? ls_tree_prefix : NULL,
- stdout, line_termination);
+ if (options->null_termination) {
+ struct strbuf sb = STRBUF_INIT;
+ const char *name = relative_path(base->buf, prefix, &sb);
+
+ fputs(name, stdout);
+ fputc('\0', stdout);
+
+ strbuf_release(&sb);
+ } else {
+ write_name_quoted_relative(base->buf, prefix, stdout, '\n');
+ }
strbuf_setlen(base, baselen);
return recurse;
}
static int show_tree_object(const struct object_id *oid, struct strbuf *base,
const char *pathname, unsigned mode,
- void *context UNUSED)
+ void *context)
{
+ struct ls_tree_options *options = context;
int early;
int recurse;
- struct show_tree_data data = { 0 };
+ enum object_type type = object_type(mode);
+ const char *str;
- early = show_tree_common(&data, &recurse, oid, base, pathname, mode);
+ early = show_tree_common(options, &recurse, base, pathname, type);
if (early >= 0)
return early;
- printf("%s%c", find_unique_abbrev(oid, abbrev), line_termination);
+ str = find_unique_abbrev(oid, options->abbrev);
+ if (options->null_termination) {
+ fputs(str, stdout);
+ fputc('\0', stdout);
+ } else {
+ puts(str);
+ }
return recurse;
}
+enum ls_tree_cmdmode {
+ MODE_DEFAULT = 0,
+ MODE_LONG,
+ MODE_NAME_ONLY,
+ MODE_NAME_STATUS,
+ MODE_OBJECT_ONLY,
+};
+
struct ls_tree_cmdmode_to_fmt {
enum ls_tree_cmdmode mode;
const char *const fmt;
@@ -335,15 +367,18 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
struct tree *tree;
int i, full_tree = 0;
read_tree_fn_t fn = NULL;
+ enum ls_tree_cmdmode cmdmode = MODE_DEFAULT;
+ int null_termination = 0;
+ struct ls_tree_options options = { 0 };
const struct option ls_tree_options[] = {
- OPT_BIT('d', NULL, &ls_options, N_("only show trees"),
+ OPT_BIT('d', NULL, &options.ls_options, N_("only show trees"),
LS_TREE_ONLY),
- OPT_BIT('r', NULL, &ls_options, N_("recurse into subtrees"),
+ OPT_BIT('r', NULL, &options.ls_options, N_("recurse into subtrees"),
LS_RECURSIVE),
- OPT_BIT('t', NULL, &ls_options, N_("show trees when recursing"),
+ OPT_BIT('t', NULL, &options.ls_options, N_("show trees when recursing"),
LS_SHOW_TREES),
- OPT_SET_INT('z', NULL, &line_termination,
- N_("terminate entries with NUL byte"), 0),
+ OPT_BOOL('z', NULL, &null_termination,
+ N_("terminate entries with NUL byte")),
OPT_CMDMODE('l', "long", &cmdmode, N_("include object size"),
MODE_LONG),
OPT_CMDMODE(0, "name-only", &cmdmode, N_("list only filenames"),
@@ -352,29 +387,32 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
MODE_NAME_STATUS),
OPT_CMDMODE(0, "object-only", &cmdmode, N_("list only objects"),
MODE_OBJECT_ONLY),
- OPT_SET_INT(0, "full-name", &chomp_prefix,
+ OPT_SET_INT(0, "full-name", &options.chomp_prefix,
N_("use full path names"), 0),
OPT_BOOL(0, "full-tree", &full_tree,
N_("list entire tree; not just current directory "
"(implies --full-name)")),
- OPT_STRING_F(0, "format", &format, N_("format"),
+ OPT_STRING_F(0, "format", &options.format, N_("format"),
N_("format to use for the output"),
PARSE_OPT_NONEG),
- OPT__ABBREV(&abbrev),
+ OPT__ABBREV(&options.abbrev),
OPT_END()
};
struct ls_tree_cmdmode_to_fmt *m2f = ls_tree_cmdmode_format;
+ int ret;
git_config(git_default_config, NULL);
- ls_tree_prefix = prefix;
+ options.ls_tree_prefix = prefix;
if (prefix)
- chomp_prefix = strlen(prefix);
+ options.chomp_prefix = strlen(prefix);
argc = parse_options(argc, argv, prefix, ls_tree_options,
ls_tree_usage, 0);
+ options.null_termination = null_termination;
+
if (full_tree) {
- ls_tree_prefix = prefix = NULL;
- chomp_prefix = 0;
+ options.ls_tree_prefix = prefix = NULL;
+ options.chomp_prefix = 0;
}
/*
* We wanted to detect conflicts between --name-only and
@@ -386,10 +424,10 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
/* -d -r should imply -t, but -d by itself should not have to. */
if ( (LS_TREE_ONLY|LS_RECURSIVE) ==
- ((LS_TREE_ONLY|LS_RECURSIVE) & ls_options))
- ls_options |= LS_SHOW_TREES;
+ ((LS_TREE_ONLY|LS_RECURSIVE) & options.ls_options))
+ options.ls_options |= LS_SHOW_TREES;
- if (format && cmdmode)
+ if (options.format && cmdmode)
usage_msg_opt(
_("--format can't be combined with other format-altering options"),
ls_tree_usage, ls_tree_options);
@@ -404,13 +442,13 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
* cannot be lifted until it is converted to use
* match_pathspec() or tree_entry_interesting()
*/
- parse_pathspec(&pathspec, PATHSPEC_ALL_MAGIC &
- ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
+ parse_pathspec(&options.pathspec, PATHSPEC_ALL_MAGIC &
+ ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
PATHSPEC_PREFER_CWD,
prefix, argv + 1);
- for (i = 0; i < pathspec.nr; i++)
- pathspec.items[i].nowildcard_len = pathspec.items[i].len;
- pathspec.has_wildcard = 0;
+ for (i = 0; i < options.pathspec.nr; i++)
+ options.pathspec.items[i].nowildcard_len = options.pathspec.items[i].len;
+ options.pathspec.has_wildcard = 0;
tree = parse_tree_indirect(&oid);
if (!tree)
die("not a tree object");
@@ -420,11 +458,11 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
*/
while (m2f) {
if (!m2f->fmt) {
- fn = format ? show_tree_fmt : show_tree_default;
- } else if (format && !strcmp(format, m2f->fmt)) {
+ fn = options.format ? show_tree_fmt : show_tree_default;
+ } else if (options.format && !strcmp(options.format, m2f->fmt)) {
cmdmode = m2f->mode;
fn = m2f->fn;
- } else if (!format && cmdmode == m2f->mode) {
+ } else if (!options.format && cmdmode == m2f->mode) {
fn = m2f->fn;
} else {
m2f++;
@@ -433,5 +471,7 @@ int cmd_ls_tree(int argc, const char **argv, const char *prefix)
break;
}
- return !!read_tree(the_repository, tree, &pathspec, fn, NULL);
+ ret = !!read_tree(the_repository, tree, &options.pathspec, fn, &options);
+ clear_pathspec(&options.pathspec);
+ return ret;
}
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
index e3767087bb..828dc81c42 100644
--- a/builtin/merge-tree.c
+++ b/builtin/merge-tree.c
@@ -3,6 +3,7 @@
#include "tree-walk.h"
#include "xdiff-interface.h"
#include "help.h"
+#include "commit.h"
#include "commit-reach.h"
#include "merge-ort.h"
#include "object-store.h"
@@ -98,7 +99,7 @@ static void *origin(struct merge_list *entry, unsigned long *size)
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++)
@@ -406,6 +407,7 @@ struct merge_tree_options {
};
static int real_merge(struct merge_tree_options *o,
+ const char *merge_base,
const char *branch1, const char *branch2,
const char *prefix)
{
@@ -432,16 +434,31 @@ static int real_merge(struct merge_tree_options *o,
opt.branch1 = branch1;
opt.branch2 = branch2;
- /*
- * Get the merge bases, in reverse order; see comment above
- * merge_incore_recursive in merge-ort.h
- */
- merge_bases = get_merge_bases(parent1, parent2);
- if (!merge_bases && !o->allow_unrelated_histories)
- die(_("refusing to merge unrelated histories"));
- merge_bases = reverse_commit_list(merge_bases);
+ if (merge_base) {
+ struct commit *base_commit;
+ struct tree *base_tree, *parent1_tree, *parent2_tree;
+
+ base_commit = lookup_commit_reference_by_name(merge_base);
+ if (!base_commit)
+ die(_("could not lookup commit %s"), merge_base);
+
+ opt.ancestor = merge_base;
+ base_tree = get_commit_tree(base_commit);
+ parent1_tree = get_commit_tree(parent1);
+ parent2_tree = get_commit_tree(parent2);
+ merge_incore_nonrecursive(&opt, base_tree, parent1_tree, parent2_tree, &result);
+ } else {
+ /*
+ * Get the merge bases, in reverse order; see comment above
+ * merge_incore_recursive in merge-ort.h
+ */
+ merge_bases = get_merge_bases(parent1, parent2);
+ if (!merge_bases && !o->allow_unrelated_histories)
+ die(_("refusing to merge unrelated histories"));
+ merge_bases = reverse_commit_list(merge_bases);
+ merge_incore_recursive(&opt, merge_bases, parent1, parent2, &result);
+ }
- merge_incore_recursive(&opt, merge_bases, parent1, parent2, &result);
if (result.clean < 0)
die(_("failure to merge"));
@@ -487,6 +504,7 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
struct merge_tree_options o = { .show_messages = -1 };
int expected_remaining_argc;
int original_argc;
+ const char *merge_base = NULL;
const char * const merge_tree_usage[] = {
N_("git merge-tree [--write-tree] [<options>] <branch1> <branch2>"),
@@ -515,6 +533,10 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
&o.use_stdin,
N_("perform multiple merges, one per line of input"),
PARSE_OPT_NONEG),
+ OPT_STRING(0, "merge-base",
+ &merge_base,
+ N_("commit"),
+ N_("specify a merge-base for the merge")),
OPT_END()
};
@@ -529,16 +551,35 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
if (o.mode == MODE_TRIVIAL)
die(_("--trivial-merge is incompatible with all other options"));
+ if (merge_base)
+ die(_("--merge-base is incompatible with --stdin"));
line_termination = '\0';
while (strbuf_getline_lf(&buf, stdin) != EOF) {
struct strbuf **split;
int result;
+ const char *input_merge_base = NULL;
split = strbuf_split(&buf, ' ');
- if (!split[0] || !split[1] || split[2])
+ if (!split[0] || !split[1])
die(_("malformed input line: '%s'."), buf.buf);
strbuf_rtrim(split[0]);
- result = real_merge(&o, split[0]->buf, split[1]->buf, prefix);
+ strbuf_rtrim(split[1]);
+
+ /* parse the merge-base */
+ if (!strcmp(split[1]->buf, "--")) {
+ input_merge_base = split[0]->buf;
+ }
+
+ if (input_merge_base && split[2] && split[3] && !split[4]) {
+ strbuf_rtrim(split[2]);
+ strbuf_rtrim(split[3]);
+ result = real_merge(&o, input_merge_base, split[2]->buf, split[3]->buf, prefix);
+ } else if (!input_merge_base && !split[2]) {
+ result = real_merge(&o, NULL, split[0]->buf, split[1]->buf, prefix);
+ } else {
+ die(_("malformed input line: '%s'."), buf.buf);
+ }
+
if (result < 0)
die(_("merging cannot continue; got unclean result of %d"), result);
strbuf_list_free(split);
@@ -581,7 +622,7 @@ int cmd_merge_tree(int argc, const char **argv, const char *prefix)
/* Do the relevant type of merge */
if (o.mode == MODE_REAL)
- return real_merge(&o, argv[0], argv[1], prefix);
+ return real_merge(&o, merge_base, argv[0], argv[1], prefix);
else
return trivial_merge(argv[0], argv[1], argv[2]);
}
diff --git a/builtin/merge.c b/builtin/merge.c
index dd474371a2..74de2ebd2b 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -188,7 +188,7 @@ static struct strategy *get_strategy(const char *name)
for (i = 0; i < main_cmds.cnt; i++) {
int j, found = 0;
struct cmdname *ent = main_cmds.names[i];
- for (j = 0; j < ARRAY_SIZE(all_strategy); j++)
+ for (j = 0; !found && j < ARRAY_SIZE(all_strategy); j++)
if (!strncmp(ent->name, all_strategy[j].name, ent->len)
&& !all_strategy[j].name[ent->len])
found = 1;
@@ -776,7 +776,7 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
}
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;
@@ -1789,5 +1789,6 @@ done:
}
strbuf_release(&buf);
free(branch_to_free);
+ discard_index(&the_index);
return ret;
}
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 573d0b20b7..cabace4abb 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1318,7 +1318,7 @@ static int no_try_delta(const char *path)
if (!check)
check = attr_check_initl("delta", NULL);
- git_check_attr(the_repository->index, path, check);
+ git_check_attr(the_repository->index, NULL, path, check);
if (ATTR_FALSE(check->items[0].value))
return 1;
return 0;
@@ -4149,21 +4149,6 @@ static int option_parse_cruft_expiration(const struct option *opt,
return 0;
}
-struct po_filter_data {
- unsigned have_revs:1;
- struct rev_info revs;
-};
-
-static struct list_objects_filter_options *po_filter_revs_init(void *value)
-{
- struct po_filter_data *data = value;
-
- repo_init_revisions(the_repository, &data->revs, NULL);
- data->have_revs = 1;
-
- return &data->revs.filter;
-}
-
int cmd_pack_objects(int argc, const char **argv, const char *prefix)
{
int use_internal_rev_list = 0;
@@ -4174,7 +4159,8 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
int rev_list_index = 0;
int stdin_packs = 0;
struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
- struct po_filter_data pfd = { .have_revs = 0 };
+ struct list_objects_filter_options filter_options =
+ LIST_OBJECTS_FILTER_INIT;
struct option pack_objects_options[] = {
OPT_SET_INT('q', "quiet", &progress,
@@ -4265,7 +4251,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
&write_bitmap_index,
N_("write a bitmap index if possible"),
WRITE_BITMAP_QUIET, PARSE_OPT_HIDDEN),
- OPT_PARSE_LIST_OBJECTS_FILTER_INIT(&pfd, po_filter_revs_init),
+ OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
OPT_CALLBACK_F(0, "missing", NULL, N_("action"),
N_("handling for missing objects"), PARSE_OPT_NONEG,
option_parse_missing_action),
@@ -4385,7 +4371,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
if (!rev_list_all || !rev_list_reflog || !rev_list_index)
unpack_unreachable_expiration = 0;
- if (pfd.have_revs && pfd.revs.filter.choice) {
+ if (filter_options.choice) {
if (!pack_to_stdout)
die(_("cannot use --filter without --stdout"));
if (stdin_packs)
@@ -4472,13 +4458,11 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
read_cruft_objects();
} else if (!use_internal_rev_list) {
read_object_list_from_stdin();
- } else if (pfd.have_revs) {
- get_object_list(&pfd.revs, rp.nr, rp.v);
- release_revisions(&pfd.revs);
} else {
struct rev_info revs;
repo_init_revisions(the_repository, &revs, NULL);
+ list_objects_filter_copy(&revs.filter, &filter_options);
get_object_list(&revs, rp.nr, rp.v);
release_revisions(&revs);
}
@@ -4513,6 +4497,7 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
reuse_packfile_objects);
cleanup:
+ list_objects_filter_release(&filter_options);
strvec_clear(&rp);
return 0;
diff --git a/builtin/range-diff.c b/builtin/range-diff.c
index e2a74efb42..aecfae12d3 100644
--- a/builtin/range-diff.c
+++ b/builtin/range-diff.c
@@ -47,7 +47,7 @@ int cmd_range_diff(int argc, const char **argv, const char *prefix)
repo_diff_setup(the_repository, &diffopt);
- options = parse_options_concat(range_diff_options, diffopt.parseopts);
+ options = add_diff_options(range_diff_options, &diffopt);
argc = parse_options(argc, argv, prefix, options,
builtin_range_diff_usage, PARSE_OPT_KEEP_DASHDASH);
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
index f702f9d47b..3ce7541783 100644
--- a/builtin/read-tree.c
+++ b/builtin/read-tree.c
@@ -114,6 +114,7 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
int prefix_set = 0;
struct lock_file lock_file = LOCK_INIT;
const struct option read_tree_options[] = {
+ OPT__SUPER_PREFIX(&opts.super_prefix),
OPT_CALLBACK_F(0, "index-output", NULL, N_("file"),
N_("write resulting index to <file>"),
PARSE_OPT_NONEG, index_output_cb),
diff --git a/builtin/rebase.c b/builtin/rebase.c
index b22768ca5b..a26cc0cfdb 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -113,7 +113,7 @@ struct rebase_options {
int autostash;
int committer_date_is_author_date;
int ignore_date;
- char *cmd;
+ struct string_list exec;
int allow_empty_message;
int rebase_merges, rebase_cousins;
char *strategy, *strategy_opts;
@@ -131,6 +131,7 @@ struct rebase_options {
.default_backend = "merge", \
.flags = REBASE_NO_QUIET, \
.git_am_opts = STRVEC_INIT, \
+ .exec = STRING_LIST_INIT_NODUP, \
.git_format_patch_opt = STRBUF_INIT, \
.fork_point = -1, \
}
@@ -243,17 +244,6 @@ static int init_basic_state(struct replay_opts *opts, const char *head_name,
return write_basic_state(opts, head_name, onto, orig_head);
}
-static void split_exec_commands(const char *cmd, struct string_list *commands)
-{
- if (cmd && *cmd) {
- string_list_split(commands, cmd, '\n', -1);
-
- /* rebase.c adds a new line to cmd after every command,
- * so here the last command is always empty */
- string_list_remove_empty_items(commands, 0);
- }
-}
-
static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
{
int ret;
@@ -261,7 +251,6 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
struct strvec make_script_args = STRVEC_INIT;
struct todo_list todo_list = TODO_LIST_INIT;
struct replay_opts replay = get_replay_opts(opts);
- struct string_list commands = STRING_LIST_INIT_DUP;
if (get_revision_ranges(opts->upstream, opts->onto, &opts->orig_head->object.oid,
&revisions, &shortrevisions))
@@ -297,14 +286,12 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
&todo_list))
BUG("unusable todo list");
- split_exec_commands(opts->cmd, &commands);
ret = complete_action(the_repository, &replay, flags,
shortrevisions, opts->onto_name, opts->onto,
- &opts->orig_head->object.oid, &commands,
+ &opts->orig_head->object.oid, &opts->exec,
opts->autosquash, opts->update_refs, &todo_list);
}
- string_list_clear(&commands, 0);
free(revisions);
free(shortrevisions);
todo_list_release(&todo_list);
@@ -1032,7 +1019,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
struct object_id branch_base;
int ignore_whitespace = 0;
const char *gpg_sign = NULL;
- struct string_list exec = STRING_LIST_INIT_NODUP;
const char *rebase_merges = NULL;
struct string_list strategy_options = STRING_LIST_INIT_NODUP;
struct object_id squash_onto;
@@ -1127,7 +1113,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
N_("GPG-sign commits"),
PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
OPT_AUTOSTASH(&options.autostash),
- OPT_STRING_LIST('x', "exec", &exec, N_("exec"),
+ OPT_STRING_LIST('x', "exec", &options.exec, N_("exec"),
N_("add exec lines after each commit of the "
"editable list")),
OPT_BOOL_F(0, "allow-empty-message",
@@ -1250,7 +1236,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (trace2_is_enabled()) {
if (is_merge(&options))
trace2_cmd_mode("interactive");
- else if (exec.nr)
+ else if (options.exec.nr)
trace2_cmd_mode("interactive-exec");
else
trace2_cmd_mode(action_names[options.action]);
@@ -1322,6 +1308,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (reset_head(the_repository, &ropts) < 0)
die(_("could not move back to %s"),
oid_to_hex(&options.orig_head->object.oid));
+ strbuf_release(&head_msg);
remove_branch_state(the_repository, 0);
ret = finish_rebase(&options);
goto cleanup;
@@ -1377,7 +1364,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if ((options.flags & REBASE_INTERACTIVE_EXPLICIT) ||
(options.action != ACTION_NONE) ||
- (exec.nr > 0) ||
+ (options.exec.nr > 0) ||
options.autosquash) {
allow_preemptive_ff = 0;
}
@@ -1401,8 +1388,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
}
}
- for (i = 0; i < exec.nr; i++)
- if (check_exec_cmd(exec.items[i].string))
+ for (i = 0; i < options.exec.nr; i++)
+ if (check_exec_cmd(options.exec.items[i].string))
exit(1);
if (!(options.flags & REBASE_NO_QUIET))
@@ -1421,17 +1408,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (gpg_sign)
options.gpg_sign_opt = xstrfmt("-S%s", gpg_sign);
- if (exec.nr) {
- int i;
-
+ if (options.exec.nr)
imply_merge(&options, "--exec");
- strbuf_reset(&buf);
- for (i = 0; i < exec.nr; i++)
- strbuf_addf(&buf, "exec %s\n", exec.items[i].string);
- options.cmd = xstrdup(buf.buf);
- }
-
if (rebase_merges) {
if (!*rebase_merges)
; /* default mode; do nothing */
@@ -1542,7 +1521,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (options.empty == EMPTY_UNSPECIFIED) {
if (options.flags & REBASE_INTERACTIVE_EXPLICIT)
options.empty = EMPTY_ASK;
- else if (exec.nr > 0)
+ else if (options.exec.nr > 0)
options.empty = EMPTY_KEEP;
else
options.empty = EMPTY_DROP;
@@ -1828,10 +1807,12 @@ cleanup:
strbuf_release(&revisions);
free(options.reflog_action);
free(options.head_name);
+ strvec_clear(&options.git_am_opts);
free(options.gpg_sign_opt);
- free(options.cmd);
+ string_list_clear(&options.exec, 0);
free(options.strategy);
strbuf_release(&options.git_format_patch_opt);
free(squash_onto_name);
+ string_list_clear(&strategy_options, 0);
return !!ret;
}
diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c
index fd3538d4f0..ee338bf440 100644
--- a/builtin/remote-ext.c
+++ b/builtin/remote-ext.c
@@ -169,6 +169,8 @@ static int command_loop(const char *child)
while (1) {
size_t i;
+ const char *arg;
+
if (!fgets(buffer, MAXCOMMAND - 1, stdin)) {
if (ferror(stdin))
die("Command input error");
@@ -182,10 +184,10 @@ static int command_loop(const char *child)
if (!strcmp(buffer, "capabilities")) {
printf("*connect\n\n");
fflush(stdout);
- } else if (!strncmp(buffer, "connect ", 8)) {
+ } else if (skip_prefix(buffer, "connect ", &arg)) {
printf("\n");
fflush(stdout);
- return run_child(child, buffer + 8);
+ return run_child(child, arg);
} else {
fprintf(stderr, "Bad command");
return 1;
diff --git a/builtin/remote-fd.c b/builtin/remote-fd.c
index 91dfe07e06..b2a3980b1d 100644
--- a/builtin/remote-fd.c
+++ b/builtin/remote-fd.c
@@ -40,7 +40,7 @@ static void command_loop(int input_fd, int output_fd)
if (!strcmp(buffer, "capabilities")) {
printf("*connect\n\n");
fflush(stdout);
- } else if (!strncmp(buffer, "connect ", 8)) {
+ } else if (starts_with(buffer, "connect ")) {
printf("\n");
fflush(stdout);
if (bidirectional_transfer_loop(input_fd,
diff --git a/builtin/repack.c b/builtin/repack.c
index 65eb1b8bd2..c1402ad038 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -973,6 +973,7 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
item = string_list_append(&names, line.buf);
item->util = populate_pack_exts(item->string);
}
+ strbuf_release(&line);
fclose(out);
ret = finish_command(&cmd);
if (ret)
@@ -1175,7 +1176,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
string_list_clear(&existing_nonkept_packs, 0);
string_list_clear(&existing_kept_packs, 0);
clear_pack_geometry(geometry);
- strbuf_release(&line);
return 0;
}
diff --git a/builtin/rerere.c b/builtin/rerere.c
index 8b7392d5b4..94ffb8c21a 100644
--- a/builtin/rerere.c
+++ b/builtin/rerere.c
@@ -14,7 +14,7 @@ static const char * const rerere_usage[] = {
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 --git a/builtin/reset.c b/builtin/reset.c
index 1fa86edb4c..fea20a9ba0 100644
--- a/builtin/reset.c
+++ b/builtin/reset.c
@@ -133,7 +133,8 @@ static void print_new_head_line(struct commit *commit)
}
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;
@@ -485,5 +486,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
if (!pathspec.nr)
remove_branch_state(the_repository, 0);
+ discard_index(&the_index);
+
return update_ref_status;
}
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 1c344d74a7..e67999e5eb 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -530,6 +530,7 @@ static int cmd_parseopt(int argc, const char **argv, const char *prefix)
strbuf_addstr(&parsed, " --");
sq_quote_argv(&parsed, argv);
puts(parsed.buf);
+ strbuf_release(&parsed);
return 0;
}
diff --git a/builtin/revert.c b/builtin/revert.c
index 6a9b550a61..f2d86d2a8f 100644
--- a/builtin/revert.c
+++ b/builtin/revert.c
@@ -221,6 +221,7 @@ static int run_sequencer(int argc, const char **argv, struct replay_opts *opts)
opts->strategy = xstrdup_or_null(opts->strategy);
if (!opts->strategy && getenv("GIT_TEST_MERGE_ALGORITHM"))
opts->strategy = xstrdup(getenv("GIT_TEST_MERGE_ALGORITHM"));
+ free(options);
if (cmd == 'q') {
int ret = sequencer_remove_state(opts);
@@ -261,6 +262,9 @@ int cmd_cherry_pick(int argc, const char **argv, const char *prefix)
opts.action = REPLAY_PICK;
sequencer_init_config(&opts);
res = run_sequencer(argc, argv, &opts);
+ if (opts.revs)
+ release_revisions(opts.revs);
+ free(opts.revs);
if (res < 0)
die(_("cherry-pick failed"));
return res;
diff --git a/builtin/rm.c b/builtin/rm.c
index d4989d4d86..4a4aec0d00 100644
--- a/builtin/rm.c
+++ b/builtin/rm.c
@@ -86,7 +86,7 @@ static void submodules_absorb_gitdir_if_needed(void)
continue;
if (!submodule_uses_gitfile(name))
- absorb_git_dir_into_superproject(name);
+ absorb_git_dir_into_superproject(name, NULL);
}
}
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index 58a22503f0..dc332c6d05 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -217,6 +217,7 @@ static int update_working_directory(struct pattern_list *pl)
o.head_idx = -1;
o.src_index = r->index;
o.dst_index = r->index;
+ index_state_init(&o.result);
o.skip_sparse_checkout = 0;
o.pl = pl;
diff --git a/builtin/stash.c b/builtin/stash.c
index 62e36718d3..a5f13fb1e9 100644
--- a/builtin/stash.c
+++ b/builtin/stash.c
@@ -1137,7 +1137,7 @@ static int save_untracked_files(struct stash_info *info, struct strbuf *msg,
int ret = 0;
struct strbuf untracked_msg = STRBUF_INIT;
struct child_process cp_upd_index = CHILD_PROCESS_INIT;
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT;
cp_upd_index.git_cmd = 1;
strvec_pushl(&cp_upd_index.args, "update-index", "-z", "--add",
@@ -1165,7 +1165,7 @@ static int save_untracked_files(struct stash_info *info, struct strbuf *msg,
}
done:
- discard_index(&istate);
+ release_index(&istate);
strbuf_release(&untracked_msg);
remove_path(stash_index_path.buf);
return ret;
@@ -1176,7 +1176,7 @@ static int stash_staged(struct stash_info *info, struct strbuf *out_patch,
{
int ret = 0;
struct child_process cp_diff_tree = CHILD_PROCESS_INIT;
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT;
if (write_index_as_tree(&info->w_tree, &istate, the_repository->index_file,
0, NULL)) {
@@ -1199,7 +1199,7 @@ static int stash_staged(struct stash_info *info, struct strbuf *out_patch,
}
done:
- discard_index(&istate);
+ release_index(&istate);
return ret;
}
@@ -1209,7 +1209,7 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps,
int ret = 0;
struct child_process cp_read_tree = CHILD_PROCESS_INIT;
struct child_process cp_diff_tree = CHILD_PROCESS_INIT;
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT;
char *old_index_env = NULL, *old_repo_index_file;
remove_path(stash_index_path.buf);
@@ -1260,7 +1260,7 @@ static int stash_patch(struct stash_info *info, const struct pathspec *ps,
}
done:
- discard_index(&istate);
+ release_index(&istate);
remove_path(stash_index_path.buf);
return ret;
}
@@ -1271,7 +1271,7 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
struct rev_info rev;
struct child_process cp_upd_index = CHILD_PROCESS_INIT;
struct strbuf diff_output = STRBUF_INIT;
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT;
init_revisions(&rev, NULL);
copy_pathspec(&rev.prune_data, ps);
@@ -1319,7 +1319,7 @@ static int stash_working_tree(struct stash_info *info, const struct pathspec *ps
}
done:
- discard_index(&istate);
+ release_index(&istate);
release_revisions(&rev);
strbuf_release(&diff_output);
remove_path(stash_index_path.buf);
@@ -1689,8 +1689,10 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
}
done:
+ strbuf_release(&patch);
free_stash_info(&info);
strbuf_release(&stash_msg_buf);
+ strbuf_release(&untracked_files);
return ret;
}
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 05f2c9bc98..4c173d8b37 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -113,10 +113,9 @@ static char *resolve_relative_url(const char *rel_url, const char *up_path, int
}
/* the result should be freed by the caller. */
-static char *get_submodule_displaypath(const char *path, const char *prefix)
+static char *get_submodule_displaypath(const char *path, const char *prefix,
+ const char *super_prefix)
{
- const char *super_prefix = get_super_prefix();
-
if (prefix && super_prefix) {
BUG("cannot have prefix '%s' and superprefix '%s'",
prefix, super_prefix);
@@ -279,6 +278,7 @@ struct foreach_cb {
int argc;
const char **argv;
const char *prefix;
+ const char *super_prefix;
int quiet;
int recursive;
};
@@ -294,7 +294,8 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
struct child_process cp = CHILD_PROCESS_INIT;
char *displaypath;
- displaypath = get_submodule_displaypath(path, info->prefix);
+ displaypath = get_submodule_displaypath(path, info->prefix,
+ info->super_prefix);
sub = submodule_from_path(the_repository, null_oid(), path);
@@ -364,10 +365,10 @@ static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
cpr.dir = path;
prepare_submodule_repo_env(&cpr.env);
- strvec_pushl(&cpr.args, "--super-prefix", NULL);
- strvec_pushf(&cpr.args, "%s/", displaypath);
strvec_pushl(&cpr.args, "submodule--helper", "foreach", "--recursive",
NULL);
+ strvec_pushl(&cpr.args, "--super-prefix", NULL);
+ strvec_pushf(&cpr.args, "%s/", displaypath);
if (info->quiet)
strvec_push(&cpr.args, "--quiet");
@@ -391,6 +392,7 @@ static int module_foreach(int argc, const char **argv, const char *prefix)
struct pathspec pathspec = { 0 };
struct module_list list = MODULE_LIST_INIT;
struct option module_foreach_options[] = {
+ OPT__SUPER_PREFIX(&info.super_prefix),
OPT__QUIET(&info.quiet, N_("suppress output of entering each submodule command")),
OPT_BOOL(0, "recursive", &info.recursive,
N_("recurse into nested submodules")),
@@ -435,11 +437,13 @@ static int starts_with_dot_dot_slash(const char *const path)
struct init_cb {
const char *prefix;
+ const char *super_prefix;
unsigned int flags;
};
#define INIT_CB_INIT { 0 }
static void init_submodule(const char *path, const char *prefix,
+ const char *super_prefix,
unsigned int flags)
{
const struct submodule *sub;
@@ -447,7 +451,7 @@ static void init_submodule(const char *path, const char *prefix,
const char *upd;
char *url = NULL, *displaypath;
- displaypath = get_submodule_displaypath(path, prefix);
+ displaypath = get_submodule_displaypath(path, prefix, super_prefix);
sub = submodule_from_path(the_repository, null_oid(), path);
@@ -523,7 +527,8 @@ static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data
{
struct init_cb *info = cb_data;
- init_submodule(list_item->name, info->prefix, info->flags);
+ init_submodule(list_item->name, info->prefix, info->super_prefix,
+ info->flags);
}
static int module_init(int argc, const char **argv, const char *prefix)
@@ -570,6 +575,7 @@ cleanup:
struct status_cb {
const char *prefix;
+ const char *super_prefix;
unsigned int flags;
};
#define STATUS_CB_INIT { 0 }
@@ -608,7 +614,7 @@ static int handle_submodule_head_ref(const char *refname UNUSED,
static void status_submodule(const char *path, const struct object_id *ce_oid,
unsigned int ce_flags, const char *prefix,
- unsigned int flags)
+ const char *super_prefix, unsigned int flags)
{
char *displaypath;
struct strvec diff_files_args = STRVEC_INIT;
@@ -624,7 +630,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
die(_("no submodule mapping found in .gitmodules for path '%s'"),
path);
- displaypath = get_submodule_displaypath(path, prefix);
+ displaypath = get_submodule_displaypath(path, prefix, super_prefix);
if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {
print_status(flags, 'U', path, null_oid(), displaypath);
@@ -682,10 +688,10 @@ static void status_submodule(const char *path, const struct object_id *ce_oid,
cpr.dir = path;
prepare_submodule_repo_env(&cpr.env);
- strvec_push(&cpr.args, "--super-prefix");
- strvec_pushf(&cpr.args, "%s/", displaypath);
strvec_pushl(&cpr.args, "submodule--helper", "status",
"--recursive", NULL);
+ strvec_push(&cpr.args, "--super-prefix");
+ strvec_pushf(&cpr.args, "%s/", displaypath);
if (flags & OPT_CACHED)
strvec_push(&cpr.args, "--cached");
@@ -709,7 +715,7 @@ static void status_submodule_cb(const struct cache_entry *list_item,
struct status_cb *info = cb_data;
status_submodule(list_item->name, &list_item->oid, list_item->ce_flags,
- info->prefix, info->flags);
+ info->prefix, info->super_prefix, info->flags);
}
static int module_status(int argc, const char **argv, const char *prefix)
@@ -719,6 +725,7 @@ static int module_status(int argc, const char **argv, const char *prefix)
struct module_list list = MODULE_LIST_INIT;
int quiet = 0;
struct option module_status_options[] = {
+ OPT__SUPER_PREFIX(&info.super_prefix),
OPT__QUIET(&quiet, N_("suppress submodule status output")),
OPT_BIT(0, "cached", &info.flags, N_("use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE),
@@ -787,6 +794,7 @@ struct summary_cb {
int argc;
const char **argv;
const char *prefix;
+ const char *super_prefix;
unsigned int cached: 1;
unsigned int for_status: 1;
unsigned int files: 1;
@@ -948,7 +956,8 @@ static void generate_submodule_summary(struct summary_cb *info,
dst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);
}
- displaypath = get_submodule_displaypath(p->sm_path, info->prefix);
+ displaypath = get_submodule_displaypath(p->sm_path, info->prefix,
+ info->super_prefix);
if (!missing_src && !missing_dst) {
struct child_process cp_rev_list = CHILD_PROCESS_INIT;
@@ -1043,7 +1052,7 @@ static void prepare_submodule_summary(struct summary_cb *info,
}
static void submodule_summary_callback(struct diff_queue_struct *q,
- struct diff_options *options,
+ struct diff_options *options UNUSED,
void *data)
{
int i;
@@ -1203,12 +1212,13 @@ static int module_summary(int argc, const char **argv, const char *prefix)
struct sync_cb {
const char *prefix;
+ const char *super_prefix;
unsigned int flags;
};
#define SYNC_CB_INIT { 0 }
static void sync_submodule(const char *path, const char *prefix,
- unsigned int flags)
+ const char *super_prefix, unsigned int flags)
{
const struct submodule *sub;
char *remote_key = NULL;
@@ -1239,7 +1249,7 @@ static void sync_submodule(const char *path, const char *prefix,
super_config_url = xstrdup("");
}
- displaypath = get_submodule_displaypath(path, prefix);
+ displaypath = get_submodule_displaypath(path, prefix, super_prefix);
if (!(flags & OPT_QUIET))
printf(_("Synchronizing submodule url for '%s'\n"),
@@ -1276,10 +1286,11 @@ static void sync_submodule(const char *path, const char *prefix,
cpr.dir = path;
prepare_submodule_repo_env(&cpr.env);
- strvec_push(&cpr.args, "--super-prefix");
- strvec_pushf(&cpr.args, "%s/", displaypath);
strvec_pushl(&cpr.args, "submodule--helper", "sync",
"--recursive", NULL);
+ strvec_push(&cpr.args, "--super-prefix");
+ strvec_pushf(&cpr.args, "%s/", displaypath);
+
if (flags & OPT_QUIET)
strvec_push(&cpr.args, "--quiet");
@@ -1302,7 +1313,8 @@ static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data
{
struct sync_cb *info = cb_data;
- sync_submodule(list_item->name, info->prefix, info->flags);
+ sync_submodule(list_item->name, info->prefix, info->super_prefix,
+ info->flags);
}
static int module_sync(int argc, const char **argv, const char *prefix)
@@ -1313,6 +1325,7 @@ static int module_sync(int argc, const char **argv, const char *prefix)
int quiet = 0;
int recursive = 0;
struct option module_sync_options[] = {
+ OPT__SUPER_PREFIX(&info.super_prefix),
OPT__QUIET(&quiet, N_("suppress output of synchronizing submodule url")),
OPT_BOOL(0, "recursive", &recursive,
N_("recurse into nested submodules")),
@@ -1365,7 +1378,7 @@ static void deinit_submodule(const char *path, const char *prefix,
if (!sub || !sub->name)
goto cleanup;
- displaypath = get_submodule_displaypath(path, prefix);
+ displaypath = get_submodule_displaypath(path, prefix, NULL);
/* remove the submodule work tree (unless the user already did it) */
if (is_directory(path)) {
@@ -1379,7 +1392,7 @@ static void deinit_submodule(const char *path, const char *prefix,
".git file by using absorbgitdirs."),
displaypath);
- absorb_git_dir_into_superproject(path);
+ absorb_git_dir_into_superproject(path, NULL);
}
@@ -1883,6 +1896,7 @@ static void submodule_update_clone_release(struct submodule_update_clone *suc)
struct update_data {
const char *prefix;
+ const char *super_prefix;
char *displaypath;
enum submodule_update_type update_default;
struct object_id suboid;
@@ -1958,7 +1972,8 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
enum submodule_update_type update_type;
char *key;
const struct update_data *ud = suc->update_data;
- char *displaypath = get_submodule_displaypath(ce->name, ud->prefix);
+ char *displaypath = get_submodule_displaypath(ce->name, ud->prefix,
+ ud->super_prefix);
struct strbuf sb = STRBUF_INIT;
int needs_cloning = 0;
int need_free_url = 0;
@@ -2438,11 +2453,11 @@ static void update_data_to_args(const struct update_data *update_data,
{
enum submodule_update_type update_type = update_data->update_default;
+ strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
if (update_data->displaypath) {
strvec_push(args, "--super-prefix");
strvec_pushf(args, "%s/", update_data->displaypath);
}
- strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
strvec_pushf(args, "--jobs=%d", update_data->max_jobs);
if (update_data->quiet)
strvec_push(args, "--quiet");
@@ -2608,7 +2623,8 @@ static int update_submodules(struct update_data *update_data)
goto fail;
update_data->displaypath = get_submodule_displaypath(
- update_data->sm_path, update_data->prefix);
+ update_data->sm_path, update_data->prefix,
+ update_data->super_prefix);
code = update_submodule(update_data);
FREE_AND_NULL(update_data->displaypath);
fail:
@@ -2634,6 +2650,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
LIST_OBJECTS_FILTER_INIT;
int ret;
struct option module_update_options[] = {
+ OPT__SUPER_PREFIX(&opt.super_prefix),
OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
OPT_BOOL(0, "init", &opt.init,
N_("initialize uninitialized submodules before update")),
@@ -2730,6 +2747,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
module_list_active(&list);
info.prefix = opt.prefix;
+ info.super_prefix = opt.super_prefix;
if (opt.quiet)
info.flags |= OPT_QUIET;
@@ -2828,7 +2846,9 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
int i;
struct pathspec pathspec = { 0 };
struct module_list list = MODULE_LIST_INIT;
+ const char *super_prefix = NULL;
struct option embed_gitdir_options[] = {
+ OPT__SUPER_PREFIX(&super_prefix),
OPT_END()
};
const char *const git_submodule_helper_usage[] = {
@@ -2844,7 +2864,8 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
goto cleanup;
for (i = 0; i < list.nr; i++)
- absorb_git_dir_into_superproject(list.entries[i]->name);
+ absorb_git_dir_into_superproject(list.entries[i]->name,
+ super_prefix);
ret = 0;
cleanup:
@@ -2876,7 +2897,7 @@ static int module_set_url(int argc, const char **argv, const char *prefix)
config_name = xstrfmt("submodule.%s.url", path);
config_set_in_gitmodules_file_gently(config_name, newurl);
- sync_submodule(path, prefix, quiet ? OPT_QUIET : 0);
+ sync_submodule(path, prefix, NULL, quiet ? OPT_QUIET : 0);
free(config_name);
@@ -3198,9 +3219,8 @@ static void die_on_index_match(const char *path, int force)
ensure_full_index(&the_index);
/*
- * Since there is only one pathspec, we just need
- * need to check ps_matched[0] to know if a cache
- * entry matched.
+ * Since there is only one pathspec, we just need to
+ * check ps_matched[0] to know if a cache entry matched.
*/
for (i = 0; i < the_index.cache_nr; i++) {
ce_path_match(&the_index, the_index.cache[i], &ps,
@@ -3353,8 +3373,6 @@ cleanup:
int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
{
- const char *cmd = argv[0];
- const char *subcmd;
parse_opt_subcommand_fn *fn = NULL;
const char *const usage[] = {
N_("git submodule--helper <command>"),
@@ -3378,18 +3396,6 @@ int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
OPT_END()
};
argc = parse_options(argc, argv, prefix, options, usage, 0);
- subcmd = argv[0];
-
- if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") &&
- strcmp(subcmd, "foreach") && strcmp(subcmd, "status") &&
- strcmp(subcmd, "sync") && strcmp(subcmd, "absorbgitdirs") &&
- get_super_prefix())
- /*
- * xstrfmt() rather than "%s %s" to keep the translated
- * string identical to git.c's.
- */
- die(_("%s doesn't support --super-prefix"),
- xstrfmt("'%s %s'", cmd, subcmd));
return fn(argc, argv, prefix);
}
diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c
index 9e8119dd35..88de32b7d7 100644
--- a/builtin/unpack-file.c
+++ b/builtin/unpack-file.c
@@ -19,6 +19,7 @@ static char *create_temp_file(struct object_id *oid)
if (write_in_full(fd, buf, size) < 0)
die_errno("unable to write temp-file");
close(fd);
+ free(buf);
return path;
}
diff --git a/builtin/var.c b/builtin/var.c
index 491db27429..a80c1df86f 100644
--- a/builtin/var.c
+++ b/builtin/var.c
@@ -11,12 +11,12 @@ static const char var_usage[] = "git var (-l | <variable>)";
static const char *editor(int flag)
{
- const char *pgm = git_editor();
-
- if (!pgm && flag & IDENT_STRICT)
- die("Terminal is dumb, but EDITOR unset");
+ return git_editor();
+}
- return pgm;
+static const char *sequence_editor(int flag)
+{
+ return git_sequence_editor();
}
static const char *pager(int flag)
@@ -41,6 +41,7 @@ static struct git_var git_vars[] = {
{ "GIT_COMMITTER_IDENT", git_committer_info },
{ "GIT_AUTHOR_IDENT", git_author_info },
{ "GIT_EDITOR", editor },
+ { "GIT_SEQUENCE_EDITOR", sequence_editor },
{ "GIT_PAGER", pager },
{ "GIT_DEFAULT_BRANCH", default_branch },
{ "", NULL },
@@ -56,18 +57,15 @@ static void list_vars(void)
printf("%s=%s\n", ptr->name, val);
}
-static const char *read_var(const char *var)
+static const struct git_var *get_git_var(const char *var)
{
struct git_var *ptr;
- const char *val;
- val = NULL;
for (ptr = git_vars; ptr->read; ptr++) {
if (strcmp(var, ptr->name) == 0) {
- val = ptr->read(IDENT_STRICT);
- break;
+ return ptr;
}
}
- return val;
+ return NULL;
}
static int show_config(const char *var, const char *value, void *cb)
@@ -81,7 +79,9 @@ static int show_config(const char *var, const char *value, void *cb)
int cmd_var(int argc, const char **argv, const char *prefix)
{
- const char *val = NULL;
+ const struct git_var *git_var;
+ const char *val;
+
if (argc != 2)
usage(var_usage);
@@ -91,10 +91,15 @@ int cmd_var(int argc, const char **argv, const char *prefix)
return 0;
}
git_config(git_default_config, NULL);
- val = read_var(argv[1]);
- if (!val)
+
+ git_var = get_git_var(argv[1]);
+ if (!git_var)
usage(var_usage);
+ val = git_var->read(IDENT_STRICT);
+ if (!val)
+ return 1;
+
printf("%s\n", val);
return 0;
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 4a24d53be1..311d6e9075 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -629,6 +629,7 @@ static int add(int ac, const char **av, const char *prefix)
N_("try to match the new branch name with a remote-tracking branch")),
OPT_END()
};
+ int ret;
memset(&opts, 0, sizeof(opts));
opts.checkout = 1;
@@ -705,9 +706,9 @@ static int add(int ac, const char **av, const char *prefix)
die(_("--[no-]track can only be used if a new branch is created"));
}
- UNLEAK(path);
- UNLEAK(opts);
- return add_worktree(path, branch, &opts);
+ ret = add_worktree(path, branch, &opts);
+ free(path);
+ return ret;
}
static void show_worktree_porcelain(struct worktree *wt, int line_terminator)
@@ -922,7 +923,7 @@ static int unlock_worktree(int ac, const char **av, const char *prefix)
static void validate_no_submodules(const struct worktree *wt)
{
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT;
struct strbuf path = STRBUF_INIT;
int i, found_submodules = 0;
diff --git a/bundle-uri.c b/bundle-uri.c
index 79a914f961..6462ab6deb 100644
--- a/bundle-uri.c
+++ b/bundle-uri.c
@@ -7,6 +7,7 @@
#include "hashmap.h"
#include "pkt-line.h"
#include "config.h"
+#include "remote.h"
static int compare_bundles(const void *hashmap_cmp_fn_data,
const struct hashmap_entry *he1,
@@ -49,6 +50,7 @@ void clear_bundle_list(struct bundle_list *list)
for_all_bundles_in_list(list, clear_remote_bundle_info, NULL);
hashmap_clear_and_free(&list->bundles, struct remote_bundle_info, ent);
+ free(list->baseURI);
}
int for_all_bundles_in_list(struct bundle_list *list,
@@ -163,7 +165,7 @@ static int bundle_list_update(const char *key, const char *value,
if (!strcmp(subkey, "uri")) {
if (bundle->uri)
return -1;
- bundle->uri = xstrdup(value);
+ bundle->uri = relative_url(list->baseURI, value, NULL);
return 0;
}
@@ -190,6 +192,18 @@ int bundle_uri_parse_config_format(const char *uri,
.error_action = CONFIG_ERROR_ERROR,
};
+ if (!list->baseURI) {
+ struct strbuf baseURI = STRBUF_INIT;
+ strbuf_addstr(&baseURI, uri);
+
+ /*
+ * If the URI does not end with a trailing slash, then
+ * remove the filename portion of the path. This is
+ * important for relative URIs.
+ */
+ strbuf_strip_file_from_path(&baseURI);
+ list->baseURI = strbuf_detach(&baseURI, NULL);
+ }
result = git_config_from_file_with_options(config_to_bundle_list,
filename, list,
&opts);
@@ -563,6 +577,77 @@ cleanup:
return result;
}
+int fetch_bundle_list(struct repository *r, struct bundle_list *list)
+{
+ int result;
+ struct bundle_list global_list;
+
+ init_bundle_list(&global_list);
+
+ /* If a bundle is added to this global list, then it is required. */
+ global_list.mode = BUNDLE_MODE_ALL;
+
+ if ((result = download_bundle_list(r, list, &global_list, 0)))
+ goto cleanup;
+
+ result = unbundle_all_bundles(r, &global_list);
+
+cleanup:
+ for_all_bundles_in_list(&global_list, unlink_bundle, NULL);
+ clear_bundle_list(&global_list);
+ return result;
+}
+
+/**
+ * API for serve.c.
+ */
+
+int bundle_uri_advertise(struct repository *r, struct strbuf *value UNUSED)
+{
+ static int advertise_bundle_uri = -1;
+
+ if (advertise_bundle_uri != -1)
+ goto cached;
+
+ advertise_bundle_uri = 0;
+ repo_config_get_maybe_bool(r, "uploadpack.advertisebundleuris", &advertise_bundle_uri);
+
+cached:
+ return advertise_bundle_uri;
+}
+
+static int config_to_packet_line(const char *key, const char *value, void *data)
+{
+ struct packet_reader *writer = data;
+
+ if (starts_with(key, "bundle."))
+ packet_write_fmt(writer->fd, "%s=%s", key, value);
+
+ return 0;
+}
+
+int bundle_uri_command(struct repository *r,
+ struct packet_reader *request)
+{
+ struct packet_writer writer;
+ packet_writer_init(&writer, 1);
+
+ while (packet_reader_read(request) == PACKET_READ_NORMAL)
+ die(_("bundle-uri: unexpected argument: '%s'"), request->line);
+ if (request->status != PACKET_READ_FLUSH)
+ die(_("bundle-uri: expected flush after arguments"));
+
+ /*
+ * Read all "bundle.*" config lines to the client as key=value
+ * packet lines.
+ */
+ git_config(config_to_packet_line, &writer);
+
+ packet_writer_flush(&writer);
+
+ return 0;
+}
+
/**
* General API for {transport,connect}.c etc.
*/
diff --git a/bundle-uri.h b/bundle-uri.h
index 4dbc269823..d5e89f1671 100644
--- a/bundle-uri.h
+++ b/bundle-uri.h
@@ -4,6 +4,7 @@
#include "hashmap.h"
#include "strbuf.h"
+struct packet_reader;
struct repository;
struct string_list;
@@ -60,6 +61,20 @@ struct bundle_list {
int version;
enum bundle_list_mode mode;
struct hashmap bundles;
+
+ /**
+ * The baseURI of a bundle_list is the URI that provided the list.
+ *
+ * In the case of the 'bundle-uri' protocol v2 command, the base
+ * URI is the URI of the Git remote.
+ *
+ * Otherwise, the bundle list was downloaded over HTTP from some
+ * known URI. 'baseURI' is set to that value.
+ *
+ * The baseURI is used as the base for any relative URIs
+ * advertised by the bundle list at that location.
+ */
+ char *baseURI;
};
void init_bundle_list(struct bundle_list *list);
@@ -93,6 +108,26 @@ int bundle_uri_parse_config_format(const char *uri,
int fetch_bundle_uri(struct repository *r, const char *uri);
/**
+ * Given a bundle list that was already advertised (likely by the
+ * bundle-uri protocol v2 verb) at the given uri, fetch and unbundle the
+ * bundles according to the bundle strategy of that list.
+ *
+ * It is expected that the given 'list' is initialized, including its
+ * 'baseURI' value.
+ *
+ * Returns non-zero if there was an error trying to download the list
+ * or any of its advertised bundles.
+ */
+int fetch_bundle_list(struct repository *r,
+ struct bundle_list *list);
+
+/**
+ * API for serve.c.
+ */
+int bundle_uri_advertise(struct repository *r, struct strbuf *value);
+int bundle_uri_command(struct repository *r, struct packet_reader *request);
+
+/**
* General API for {transport,connect}.c etc.
*/
diff --git a/cache-tree.c b/cache-tree.c
index c97111cccf..9af457f47c 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -405,7 +405,7 @@ static int update_one(struct cache_tree *it,
}
/*
- * CE_INTENT_TO_ADD entries exist on on-disk index but
+ * CE_INTENT_TO_ADD entries exist in on-disk index but
* they are not part of generated trees. Invalidate up
* to root to force cache-tree users to read elsewhere.
*/
diff --git a/cache.h b/cache.h
index 07d40b0964..be28fce12a 100644
--- a/cache.h
+++ b/cache.h
@@ -360,6 +360,19 @@ struct index_state {
struct pattern_list *sparse_checkout_patterns;
};
+/**
+ * A "struct index_state istate" must be initialized with
+ * INDEX_STATE_INIT or the corresponding index_state_init().
+ *
+ * If the variable won't be used again, use release_index() to free()
+ * its resources. If it needs to be used again use discard_index(),
+ * which does the same thing, but will use use index_state_init() at
+ * the end.
+ */
+#define INDEX_STATE_INIT { 0 }
+void index_state_init(struct index_state *istate);
+void release_index(struct index_state *istate);
+
/* Name hashing */
int test_lazy_init_name_hash(struct index_state *istate, int try_threaded);
void add_name_hash(struct index_state *istate, struct cache_entry *ce);
@@ -480,7 +493,6 @@ static inline enum object_type object_type(unsigned int mode)
#define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
#define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
#define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
-#define GIT_SUPER_PREFIX_ENVIRONMENT "GIT_INTERNAL_SUPER_PREFIX"
#define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
#define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
#define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
@@ -566,7 +578,6 @@ int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);
int get_common_dir(struct strbuf *sb, const char *gitdir);
const char *get_git_namespace(void);
const char *strip_namespace(const char *namespaced_ref);
-const char *get_super_prefix(void);
const char *get_git_work_tree(void);
/*
@@ -1865,7 +1876,7 @@ unsigned ws_check(const char *line, int len, unsigned ws_rule);
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 --git a/ci/lib.sh b/ci/lib.sh
index 706e3ba7e9..db7105e8a8 100755
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -258,8 +258,7 @@ macos-*)
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"
+ MAKEFLAGS="$MAKEFLAGS APPLE_COMMON_CRYPTO_SHA1=Yes"
fi
;;
esac
diff --git a/column.c b/column.c
index 1261e18a72..fbf88639aa 100644
--- a/column.c
+++ b/column.c
@@ -23,7 +23,7 @@ struct column_data {
/* return length of 's' in letters, ANSI escapes stripped */
static int item_length(const char *s)
{
- return utf8_strnwidth(s, -1, 1);
+ return utf8_strnwidth(s, strlen(s), 1);
}
/*
diff --git a/combine-diff.c b/combine-diff.c
index b0ece95480..1a39b5dde0 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -372,7 +372,7 @@ struct combine_diff_state {
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 --git a/commit-graph.c b/commit-graph.c
index a7d8755932..c11b59f28b 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1594,8 +1594,7 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)
_("Computing commit changed paths Bloom filters"),
ctx->commits.nr);
- ALLOC_ARRAY(sorted_commits, ctx->commits.nr);
- COPY_ARRAY(sorted_commits, ctx->commits.list, ctx->commits.nr);
+ DUP_ARRAY(sorted_commits, ctx->commits.list, ctx->commits.nr);
if (ctx->order_by_pack)
QSORT(sorted_commits, ctx->commits.nr, commit_pos_cmp);
diff --git a/commit-reach.c b/commit-reach.c
index c226ee3da4..2e33c599a8 100644
--- a/commit-reach.c
+++ b/commit-reach.c
@@ -245,8 +245,7 @@ static int remove_redundant_with_gen(struct repository *r,
* min_gen_pos points to the current position within 'array'
* that is not yet known to be STALE.
*/
- ALLOC_ARRAY(sorted, cnt);
- COPY_ARRAY(sorted, array, cnt);
+ DUP_ARRAY(sorted, array, cnt);
QSORT(sorted, cnt, compare_commits_by_gen);
min_generation = commit_graph_generation(sorted[0]);
diff --git a/commit.c b/commit.c
index 572301b80a..14538a811a 100644
--- a/commit.c
+++ b/commit.c
@@ -508,6 +508,17 @@ int repo_parse_commit_internal(struct repository *r,
enum object_type type;
void *buffer;
unsigned long size;
+ struct object_info oi = {
+ .typep = &type,
+ .sizep = &size,
+ .contentp = &buffer,
+ };
+ /*
+ * Git does not support partial clones that exclude commits, so set
+ * OBJECT_INFO_SKIP_FETCH_OBJECT to fail fast when an object is missing.
+ */
+ int flags = OBJECT_INFO_LOOKUP_REPLACE | OBJECT_INFO_SKIP_FETCH_OBJECT |
+ OBJECT_INFO_DIE_IF_CORRUPT;
int ret;
if (!item)
@@ -516,8 +527,8 @@ int repo_parse_commit_internal(struct repository *r,
return 0;
if (use_commit_graph && parse_commit_in_graph(r, item))
return 0;
- buffer = repo_read_object_file(r, &item->object.oid, &type, &size);
- if (!buffer)
+
+ if (oid_object_info_extended(r, &item->object.oid, &oi, flags) < 0)
return quiet_on_missing ? -1 :
error("Could not read %s",
oid_to_hex(&item->object.oid));
@@ -701,8 +712,10 @@ static void clear_commit_marks_1(struct commit_list **plist,
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 --git a/compat/fsmonitor/fsm-darwin-gcc.h b/compat/fsmonitor/fsm-darwin-gcc.h
index 1c75c3d48e..3496e29b3a 100644
--- a/compat/fsmonitor/fsm-darwin-gcc.h
+++ b/compat/fsmonitor/fsm-darwin-gcc.h
@@ -80,9 +80,7 @@ void CFRunLoopRun(void);
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 --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c
index cc9af1e3cb..97a55a6f0a 100644
--- a/compat/fsmonitor/fsm-listen-darwin.c
+++ b/compat/fsmonitor/fsm-listen-darwin.c
@@ -1,4 +1,5 @@
#ifndef __clang__
+#include <dispatch/dispatch.h>
#include "fsm-darwin-gcc.h"
#else
#include <CoreFoundation/CoreFoundation.h>
@@ -38,7 +39,9 @@ struct fsm_listen_data
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 @@ force_shutdown:
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 @@ int fsm_listen__ctor(struct fsmonitor_daemon_state *state)
if (!data->stream)
goto failed;
- /*
- * `data->rl` needs to be set inside the listener thread.
- */
-
return 0;
failed:
@@ -471,6 +473,11 @@ void fsm_listen__dtor(struct fsmonitor_daemon_state *state)
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 @@ void fsm_listen__stop_async(struct fsmonitor_daemon_state *state)
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 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
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 @@ void fsm_listen__loop(struct fsmonitor_daemon_state *state)
}
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 --git a/compat/mingw.c b/compat/mingw.c
index d614f156df..e433740381 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1396,8 +1396,7 @@ static wchar_t *make_environment_block(char **deltaenv)
p += s;
}
- ALLOC_ARRAY(result, size);
- COPY_ARRAY(result, wenv, size);
+ DUP_ARRAY(result, wenv, size);
FreeEnvironmentStringsW(wenv);
return result;
}
@@ -1839,16 +1838,13 @@ static int try_shell_exec(const char *cmd, char *const *argv)
if (prog) {
int exec_id;
int argc = 0;
-#ifndef _MSC_VER
- const
-#endif
char **argv2;
while (argv[argc]) argc++;
ALLOC_ARRAY(argv2, argc + 1);
argv2[0] = (char *)cmd; /* full path to the script file */
COPY_ARRAY(&argv2[1], &argv[1], argc);
- exec_id = trace2_exec(prog, argv2);
- pid = mingw_spawnv(prog, argv2, 1);
+ exec_id = trace2_exec(prog, (const char **)argv2);
+ pid = mingw_spawnv(prog, (const char **)argv2, 1);
if (pid >= 0) {
int status;
if (waitpid(pid, &status, 0) < 0)
@@ -2752,7 +2748,7 @@ int is_path_owned_by_current_sid(const char *path, struct strbuf *report)
/*
* On FAT32 volumes, ownership is not actually recorded.
*/
- strbuf_addf(report, "'%s' is on a file system that does"
+ strbuf_addf(report, "'%s' is on a file system that does "
"not record ownership\n", path);
} else if (report) {
LPSTR str1, str2, to_free1 = NULL, to_free2 = NULL;
diff --git a/compat/win32/pthread.h b/compat/win32/pthread.h
index 737983d00b..cc3221cb2c 100644
--- a/compat/win32/pthread.h
+++ b/compat/win32/pthread.h
@@ -66,7 +66,7 @@ pthread_t pthread_self(void);
static inline void NORETURN pthread_exit(void *ret)
{
- ExitThread((DWORD)(intptr_t)ret);
+ _endthreadex((unsigned)(uintptr_t)ret);
}
typedef DWORD pthread_key_t;
diff --git a/config.c b/config.c
index 27f38283ad..00090a32fc 100644
--- a/config.c
+++ b/config.c
@@ -3154,7 +3154,7 @@ int git_config_set_gently(const char *key, const char *value)
int repo_config_set_worktree_gently(struct repository *r,
const char *key, const char *value)
{
- /* Only use worktree-specific config if it is is already enabled. */
+ /* Only use worktree-specific config if it is already enabled. */
if (repository_format_worktree_config) {
char *file = repo_git_path(r, "config.worktree");
int ret = git_config_set_multivar_in_file_gently(
diff --git a/connect.c b/connect.c
index 5ea53deda2..63e59641c0 100644
--- a/connect.c
+++ b/connect.c
@@ -15,6 +15,7 @@
#include "version.h"
#include "protocol.h"
#include "alias.h"
+#include "bundle-uri.h"
static char *server_capabilities_v1;
static struct strvec server_capabilities_v2 = STRVEC_INIT;
@@ -66,7 +67,7 @@ static NORETURN void die_initial_contact(int unexpected)
}
/* 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 +77,13 @@ int server_supports_v2(const char *c, int die_on_error)
(!*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 +480,7 @@ static void send_capabilities(int fd_out, struct packet_reader *reader)
{
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)) {
@@ -491,6 +494,49 @@ static void send_capabilities(int fd_out, struct packet_reader *reader)
}
}
+int get_remote_bundle_uri(int fd_out, struct packet_reader *reader,
+ struct bundle_list *bundles, int stateless_rpc)
+{
+ int line_nr = 1;
+
+ /* Assert bundle-uri support */
+ ensure_server_supports_v2("bundle-uri");
+
+ /* (Re-)send capabilities */
+ send_capabilities(fd_out, reader);
+
+ /* Send command */
+ packet_write_fmt(fd_out, "command=bundle-uri\n");
+ packet_delim(fd_out);
+
+ packet_flush(fd_out);
+
+ /* Process response from server */
+ while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
+ const char *line = reader->line;
+ line_nr++;
+
+ if (!bundle_uri_parse_line(bundles, line))
+ continue;
+
+ return error(_("error on bundle-uri response line %d: %s"),
+ line_nr, line);
+ }
+
+ if (reader->status != PACKET_READ_FLUSH)
+ return error(_("expected flush after bundle-uri listing"));
+
+ /*
+ * Might die(), but obscure enough that that's OK, e.g. in
+ * serve.c we'll call BUG() on its equivalent (the
+ * PACKET_READ_RESPONSE_END check).
+ */
+ check_stateless_delimiter(stateless_rpc, reader,
+ _("expected response end packet after ref listing"));
+
+ return 0;
+}
+
struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
struct ref **list, int for_push,
struct transport_ls_refs_options *transport_options,
@@ -504,17 +550,18 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
&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 --git a/connect.h b/connect.h
index c53586e929..b26f7de784 100644
--- a/connect.h
+++ b/connect.h
@@ -20,7 +20,8 @@ enum protocol_version discover_version(struct packet_reader *reader);
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 --git a/connected.c b/connected.c
index 4f6388eed7..b90fd61790 100644
--- a/connected.c
+++ b/connected.c
@@ -85,6 +85,7 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
promisor_pack_found:
;
} while ((oid = fn(cb_data)) != NULL);
+ free(new_pack);
return 0;
}
@@ -121,8 +122,10 @@ no_promisor_pack_found:
else
rev_list.no_stderr = opt->quiet;
- if (start_command(&rev_list))
+ if (start_command(&rev_list)) {
+ free(new_pack);
return error(_("Could not run 'git rev-list'"));
+ }
sigchain_push(SIGPIPE, SIG_IGN);
@@ -154,5 +157,6 @@ no_promisor_pack_found:
err = error_errno(_("failed to close rev-list's stdin"));
sigchain_pop(SIGPIPE);
+ free(new_pack);
return finish_command(&rev_list) || err;
}
diff --git a/contrib/coccinelle/array.cocci b/contrib/coccinelle/array.cocci
index aa75937950..27a3b479c9 100644
--- a/contrib/coccinelle/array.cocci
+++ b/contrib/coccinelle/array.cocci
@@ -94,3 +94,10 @@ expression n != 1;
@@
- ptr = xcalloc(n, \( sizeof(*ptr) \| sizeof(T) \) )
+ CALLOC_ARRAY(ptr, n)
+
+@@
+expression dst, src, n;
+@@
+-ALLOC_ARRAY(dst, n);
+-COPY_ARRAY(dst, src, n);
++DUP_ARRAY(dst, src, n);
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index ba5c395d2d..dc95c34cc8 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -58,6 +58,12 @@
#
# When set to "1" suggest all options, including options which are
# typically hidden (e.g. '--allow-empty' for 'git commit').
+#
+# GIT_COMPLETION_IGNORE_CASE
+#
+# When set, uses for-each-ref '--ignore-case' to find refs that match
+# case insensitively, even on systems with case sensitive file systems
+# (e.g., completing tag name "FOO" on "git checkout f<TAB>").
case "$COMP_WORDBREAKS" in
*:*) : great ;;
@@ -646,6 +652,7 @@ __git_heads ()
local pfx="${1-}" cur_="${2-}" sfx="${3-}"
__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+ ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
"refs/heads/$cur_*" "refs/heads/$cur_*/**"
}
@@ -659,6 +666,7 @@ __git_remote_heads ()
local pfx="${1-}" cur_="${2-}" sfx="${3-}"
__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+ ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
"refs/remotes/$cur_*" "refs/remotes/$cur_*/**"
}
@@ -669,6 +677,7 @@ __git_tags ()
local pfx="${1-}" cur_="${2-}" sfx="${3-}"
__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+ ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
"refs/tags/$cur_*" "refs/tags/$cur_*/**"
}
@@ -688,6 +697,7 @@ __git_dwim_remote_heads ()
# but only output if the branch name is unique
__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
--sort="refname:strip=3" \
+ ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
"refs/remotes/*/$cur_*" "refs/remotes/*/$cur_*/**" | \
uniq -u
}
@@ -712,6 +722,7 @@ __git_refs ()
local format refs
local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}"
local match="${4-}"
+ local umatch="${4-}"
local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
__git_find_repo_path
@@ -735,12 +746,19 @@ __git_refs ()
fi
fi
+ if test "${GIT_COMPLETION_IGNORE_CASE:+1}" = "1"
+ then
+ # uppercase with tr instead of ${match,^^} for bash 3.2 compatibility
+ umatch=$(echo "$match" | tr a-z A-Z 2>/dev/null || echo "$match")
+ fi
+
if [ "$list_refs_from" = path ]; then
if [[ "$cur_" == ^* ]]; then
pfx="$pfx^"
fer_pfx="$fer_pfx^"
cur_=${cur_#^}
match=${match#^}
+ umatch=${umatch#^}
fi
case "$cur_" in
refs|refs/*)
@@ -751,7 +769,7 @@ __git_refs ()
*)
for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD; do
case "$i" in
- $match*)
+ $match*|$umatch*)
if [ -e "$dir/$i" ]; then
echo "$pfx$i$sfx"
fi
@@ -765,6 +783,7 @@ __git_refs ()
;;
esac
__git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \
+ ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
"${refs[@]}"
if [ -n "$track" ]; then
__git_dwim_remote_heads "$pfx" "$match" "$sfx"
@@ -784,15 +803,16 @@ __git_refs ()
*)
if [ "$list_refs_from" = remote ]; then
case "HEAD" in
- $match*) echo "${pfx}HEAD$sfx" ;;
+ $match*|$umatch*) echo "${pfx}HEAD$sfx" ;;
esac
__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
+ ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
"refs/remotes/$remote/$match*" \
"refs/remotes/$remote/$match*/**"
else
local query_symref
case "HEAD" in
- $match*) query_symref="HEAD" ;;
+ $match*|$umatch*) query_symref="HEAD" ;;
esac
__git ls-remote "$remote" $query_symref \
"refs/tags/$match*" "refs/heads/$match*" \
diff --git a/contrib/git-jump/README b/contrib/git-jump/README
index 8bcace29d2..3211841305 100644
--- a/contrib/git-jump/README
+++ b/contrib/git-jump/README
@@ -79,6 +79,14 @@ git jump grep -i foo_bar
git config jump.grepCmd "ag --column"
--------------------------------------------------
+You can use the optional argument '--stdout' to print the listing to
+standard output instead of feeding it to the editor. You can use the
+argument with M-x grep on Emacs:
+
+--------------------------------------------------
+# In Emacs, M-x grep and invoke "git jump --stdout <mode>"
+M-x grep<RET>git jump --stdout diff<RET>
+--------------------------------------------------
Related Programs
----------------
@@ -100,7 +108,7 @@ Limitations
-----------
This script was written and tested with vim. Given that the quickfix
-format is the same as what gcc produces, I expect emacs users have a
+format is the same as what gcc produces, I expect other tools have a
similar feature for iterating through the list, but I know nothing about
how to activate it.
diff --git a/contrib/git-jump/git-jump b/contrib/git-jump/git-jump
index 92dbd4cde1..40c4b0d111 100755
--- a/contrib/git-jump/git-jump
+++ b/contrib/git-jump/git-jump
@@ -2,7 +2,7 @@
usage() {
cat <<\EOF
-usage: git jump <mode> [<args>]
+usage: git jump [--stdout] <mode> [<args>]
Jump to interesting elements in an editor.
The <mode> parameter is one of:
@@ -15,12 +15,30 @@ grep: elements are grep hits. Arguments are given to git grep or, if
configured, to the command in `jump.grepCmd`.
ws: elements are whitespace errors. Arguments are given to diff --check.
+
+If the optional argument `--stdout` is given, print the quickfix
+lines to standard output instead of feeding it to the editor.
EOF
}
open_editor() {
editor=`git var GIT_EDITOR`
- eval "$editor -q \$1"
+ case "$editor" in
+ *emacs*)
+ # Supported editor values are:
+ # - emacs
+ # - emacsclient
+ # - emacsclient -t
+ #
+ # Wait for completion of the asynchronously executed process
+ # to avoid race conditions in case of "emacsclient".
+ eval "$editor --eval \"(let ((buf (grep \\\"cat \$1\\\"))) (pop-to-buffer buf) (select-frame-set-input-focus (selected-frame)) (while (get-buffer-process buf) (sleep-for 0.1)))\""
+ ;;
+ *)
+ # assume anything else is vi-compatible
+ eval "$editor -q \$1"
+ ;;
+ esac
}
mode_diff() {
@@ -64,15 +82,36 @@ mode_ws() {
git diff --check "$@"
}
+use_stdout=
+while test $# -gt 0; do
+ case "$1" in
+ --stdout)
+ use_stdout=t
+ ;;
+ --*)
+ usage >&2
+ exit 1
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+done
if test $# -lt 1; then
usage >&2
exit 1
fi
mode=$1; shift
+type "mode_$mode" >/dev/null 2>&1 || { usage >&2; exit 1; }
+
+if test "$use_stdout" = "t"; then
+ "mode_$mode" "$@"
+ exit 0
+fi
trap 'rm -f "$tmp"' 0 1 2 3 15
tmp=`mktemp -t git-jump.XXXXXX` || exit 1
-type "mode_$mode" >/dev/null 2>&1 || { usage >&2; exit 1; }
"mode_$mode" "$@" >"$tmp"
test -s "$tmp" || exit 0
open_editor "$tmp"
diff --git a/convert.c b/convert.c
index 9b67649032..a54d1690c0 100644
--- a/convert.c
+++ b/convert.c
@@ -1308,7 +1308,7 @@ void convert_attrs(struct index_state *istate,
git_config(read_convert_config, NULL);
}
- git_check_attr(istate, path, check);
+ git_check_attr(istate, NULL, path, check);
ccheck = check->items;
ca->crlf_action = git_path_check_crlf(ccheck + 4);
if (ca->crlf_action == CRLF_UNDEFINED)
diff --git a/csum-file.c b/csum-file.c
index 59ef3398ca..cce13c0f04 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -45,7 +45,8 @@ void hashflush(struct hashfile *f)
unsigned offset = f->offset;
if (offset) {
- the_hash_algo->update_fn(&f->ctx, f->buffer, offset);
+ if (!f->skip_hash)
+ the_hash_algo->update_fn(&f->ctx, f->buffer, offset);
flush(f, f->buffer, offset);
f->offset = 0;
}
@@ -64,7 +65,12 @@ int finalize_hashfile(struct hashfile *f, unsigned char *result,
int fd;
hashflush(f);
- the_hash_algo->final_fn(f->buffer, &f->ctx);
+
+ if (f->skip_hash)
+ hashclr(f->buffer);
+ else
+ the_hash_algo->final_fn(f->buffer, &f->ctx);
+
if (result)
hashcpy(result, f->buffer);
if (flags & CSUM_HASH_IN_STREAM)
@@ -108,7 +114,8 @@ void hashwrite(struct hashfile *f, const void *buf, unsigned int count)
* the hashfile's buffer. In this block,
* f->offset is necessarily zero.
*/
- the_hash_algo->update_fn(&f->ctx, buf, nr);
+ if (!f->skip_hash)
+ the_hash_algo->update_fn(&f->ctx, buf, nr);
flush(f, buf, nr);
} else {
/*
@@ -153,6 +160,7 @@ static struct hashfile *hashfd_internal(int fd, const char *name,
f->tp = tp;
f->name = name;
f->do_crc = 0;
+ f->skip_hash = 0;
the_hash_algo->init_fn(&f->ctx);
f->buffer_len = buffer_len;
diff --git a/csum-file.h b/csum-file.h
index 0d29f528fb..793a59da12 100644
--- a/csum-file.h
+++ b/csum-file.h
@@ -20,6 +20,13 @@ struct hashfile {
size_t buffer_len;
unsigned char *buffer;
unsigned char *check_buffer;
+
+ /**
+ * If non-zero, skip_hash indicates that we should
+ * not actually compute the hash for this hashfile and
+ * instead only use it as a buffered write.
+ */
+ int skip_hash;
};
/* Checkpoint */
diff --git a/date.c b/date.c
index 53bd6a7932..6f45eeb356 100644
--- a/date.c
+++ b/date.c
@@ -493,6 +493,12 @@ static int match_alpha(const char *date, struct tm *tm, int *offset)
return 2;
}
+ /* ISO-8601 allows yyyymmDD'T'HHMMSS, with less precision */
+ if (*date == 'T' && isdigit(date[1]) && tm->tm_hour == -1) {
+ tm->tm_min = tm->tm_sec = 0;
+ return 1;
+ }
+
/* BAD CRAP */
return skip_alpha(date);
}
@@ -639,6 +645,18 @@ static inline int nodate(struct tm *tm)
}
/*
+ * Have we seen an ISO-8601-alike date, i.e. 20220101T0,
+ * In which, hour is still unset,
+ * and minutes and second has been set to 0.
+ */
+static inline int maybeiso8601(struct tm *tm)
+{
+ return tm->tm_hour == -1 &&
+ tm->tm_min == 0 &&
+ tm->tm_sec == 0;
+}
+
+/*
* We've seen a digit. Time? Year? Date?
*/
static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt)
@@ -701,6 +719,25 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt
return end - date;
}
+ /* reduced precision of ISO-8601's time: HHMM or HH */
+ if (maybeiso8601(tm)) {
+ unsigned int num1 = num;
+ unsigned int num2 = 0;
+ if (n == 4) {
+ num1 = num / 100;
+ num2 = num % 100;
+ }
+ if ((n == 4 || n == 2) && !nodate(tm) &&
+ set_time(num1, num2, 0, tm) == 0)
+ return n;
+ /*
+ * We thought this is an ISO-8601 time string,
+ * we set minutes and seconds to 0,
+ * turn out it isn't, rollback the change.
+ */
+ tm->tm_min = tm->tm_sec = -1;
+ }
+
/* Four-digit year or a timezone? */
if (n == 4) {
if (num <= 1400 && *offset == -1) {
diff --git a/diff-lib.c b/diff-lib.c
index 2edea41a23..dec040c366 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -673,7 +673,7 @@ int index_differs_from(struct repository *r,
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 --git a/diff-no-index.c b/diff-no-index.c
index 18edbdf4b5..05fafd0019 100644
--- a/diff-no-index.c
+++ b/diff-no-index.c
@@ -255,8 +255,7 @@ int diff_no_index(struct rev_info *revs,
};
struct option *options;
- options = parse_options_concat(no_index_options,
- revs->diffopt.parseopts);
+ options = add_diff_options(no_index_options, &revs->diffopt);
argc = parse_options(argc, argv, revs->prefix, options,
diff_no_index_usage, 0);
if (argc != 2) {
diff --git a/diff.c b/diff.c
index 1054a4b732..329eebf16a 100644
--- a/diff.c
+++ b/diff.c
@@ -604,7 +604,7 @@ static unsigned long diff_filespec_size(struct repository *r,
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 @@ static int count_trailing_blank(mmfile_t *mf, unsigned ws_rule)
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 @@ static void check_blank_at_eof(mmfile_t *mf1, mmfile_t *mf2,
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 @@ static int new_blank_line_at_eof(struct emit_callback *ecbdata, const char *line
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 int color_words_output_graph_prefix(struct diff_words_data *diff_words)
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;
@@ -2801,7 +2800,7 @@ static void show_stats(struct diffstat_t *data, struct diff_options *options)
else if (file->is_unmerged) {
strbuf_addf(&out, " %s%s%*s | %*s",
prefix, name, padding, "",
- number_width, "Unmerged");
+ number_width, "Unmerged\n");
emit_diff_symbol(options, DIFF_SYMBOL_STATS_LINE,
out.buf, out.len, 0);
strbuf_reset(&out);
@@ -3185,8 +3184,9 @@ static int is_conflict_marker(const char *line, int marker_size, unsigned long l
}
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 void prep_temp_blob(struct index_state *istate,
}
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 @@ static struct diff_tempfile *prepare_temp_file(struct repository *r,
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 @@ static struct diff_tempfile *prepare_temp_file(struct repository *r,
}
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 @@ static struct diff_tempfile *prepare_temp_file(struct repository *r,
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 struct diff_tempfile *prepare_temp_file(struct repository *r,
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 @@ static void run_external_diff(const char *pgm,
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);
}
@@ -4615,8 +4611,6 @@ static void run_checkdiff(struct diff_filepair *p, struct diff_options *o)
builtin_checkdiff(name, other, attr_path, p->one, p->two, o);
}
-static void prep_parse_options(struct diff_options *options);
-
void repo_diff_setup(struct repository *r, struct diff_options *options)
{
memcpy(options, &default_diff_options, sizeof(*options));
@@ -4662,8 +4656,6 @@ void repo_diff_setup(struct repository *r, struct diff_options *options)
options->color_moved = diff_color_moved_default;
options->color_moved_ws_handling = diff_color_moved_ws_default;
-
- prep_parse_options(options);
}
static const char diff_status_letters[] = {
@@ -4821,8 +4813,6 @@ void diff_setup_done(struct diff_options *options)
options->filter = ~filter_bit[DIFF_STATUS_FILTER_AON];
options->filter &= ~options->filter_not;
}
-
- FREE_AND_NULL(options->parseopts);
}
int parse_long_opt(const char *opt, const char **argv,
@@ -5419,7 +5409,8 @@ static int diff_opt_rotate_to(const struct option *opt, const char *arg, int uns
return 0;
}
-static void prep_parse_options(struct diff_options *options)
+struct option *add_diff_options(const struct option *opts,
+ struct diff_options *options)
{
struct option parseopts[] = {
OPT_GROUP(N_("Diff output format options")),
@@ -5689,22 +5680,25 @@ static void prep_parse_options(struct diff_options *options)
OPT_END()
};
- ALLOC_ARRAY(options->parseopts, ARRAY_SIZE(parseopts));
- memcpy(options->parseopts, parseopts, sizeof(parseopts));
+ return parse_options_concat(opts, parseopts);
}
int diff_opt_parse(struct diff_options *options,
const char **av, int ac, const char *prefix)
{
+ struct option no_options[] = { OPT_END() };
+ struct option *parseopts = add_diff_options(no_options, options);
+
if (!prefix)
prefix = "";
- ac = parse_options(ac, av, prefix, options->parseopts, NULL,
+ ac = parse_options(ac, av, prefix, parseopts, NULL,
PARSE_OPT_KEEP_DASHDASH |
PARSE_OPT_KEEP_UNKNOWN_OPT |
PARSE_OPT_NO_INTERNAL_HELP |
PARSE_OPT_ONE_SHOT |
PARSE_OPT_STOP_AT_NON_OPTION);
+ free(parseopts);
return ac;
}
@@ -6513,7 +6507,6 @@ void diff_free(struct diff_options *options)
diff_free_file(options);
diff_free_ignore_regex(options);
clear_pathspec(&options->pathspec);
- FREE_AND_NULL(options->parseopts);
}
void diff_flush(struct diff_options *options)
@@ -7037,7 +7030,7 @@ static char *run_textconv(struct repository *r,
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 --git a/diff.h b/diff.h
index fd33caeb25..41eb2c3d42 100644
--- a/diff.h
+++ b/diff.h
@@ -394,7 +394,6 @@ struct diff_options {
unsigned color_moved_ws_handling;
struct repository *repo;
- struct option *parseopts;
struct strmap *additional_path_headers;
int no_free;
@@ -539,6 +538,7 @@ int git_diff_ui_config(const char *var, const char *value, void *cb);
#define diff_setup(diffopts) repo_diff_setup(the_repository, diffopts)
#endif
void repo_diff_setup(struct repository *, struct diff_options *);
+struct option *add_diff_options(const struct option *, struct diff_options *);
int diff_opt_parse(struct diff_options *, const char **, int, const char *);
void diff_setup_done(struct diff_options *);
int git_config_rename(const char *var, const char *value);
diff --git a/dir.c b/dir.c
index d604d1bab9..4e99f0c868 100644
--- a/dir.c
+++ b/dir.c
@@ -732,6 +732,13 @@ static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_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;
cur = given->pattern + 1;
next = given->pattern + 2;
@@ -3581,8 +3588,12 @@ static void free_untracked(struct untracked_cache_dir *ucd)
void free_untracked_cache(struct untracked_cache *uc)
{
- if (uc)
- free_untracked(uc->root);
+ if (!uc)
+ return;
+
+ free(uc->exclude_per_dir_to_free);
+ strbuf_release(&uc->ident);
+ free_untracked(uc->root);
free(uc);
}
@@ -3739,7 +3750,7 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long
next + offset + hashsz);
uc->dir_flags = get_be32(next + ouc_offset(dir_flags));
exclude_per_dir = (const char *)next + exclude_per_dir_offset;
- uc->exclude_per_dir = xstrdup(exclude_per_dir);
+ uc->exclude_per_dir = uc->exclude_per_dir_to_free = xstrdup(exclude_per_dir);
/* NUL after exclude_per_dir is covered by sizeof(*ouc) */
next += exclude_per_dir_offset + strlen(exclude_per_dir) + 1;
if (next >= end)
diff --git a/dir.h b/dir.h
index 674747d93a..8acfc04418 100644
--- a/dir.h
+++ b/dir.h
@@ -188,6 +188,7 @@ struct untracked_cache {
struct oid_stat ss_info_exclude;
struct oid_stat ss_excludes_file;
const char *exclude_per_dir;
+ char *exclude_per_dir_to_free;
struct strbuf ident;
/*
* dir_struct#flags must match dir_flags or the untracked
diff --git a/entry.c b/entry.c
index 616e4f073c..971ab26871 100644
--- a/entry.c
+++ b/entry.c
@@ -383,7 +383,7 @@ static int write_entry(struct cache_entry *ce, char *path, struct conv_attrs *ca
return error("cannot create submodule directory %s", path);
sub = submodule_from_ce(ce);
if (sub)
- return submodule_move_head(ce->name,
+ return submodule_move_head(ce->name, state->super_prefix,
NULL, oid_to_hex(&ce->oid),
state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);
break;
@@ -476,7 +476,7 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
* no pathname to return.
*/
BUG("Can't remove entry to a path");
- unlink_entry(ce);
+ unlink_entry(ce, state->super_prefix);
return 0;
}
@@ -510,10 +510,10 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
if (!(st.st_mode & S_IFDIR))
unlink_or_warn(ce->name);
- return submodule_move_head(ce->name,
+ return submodule_move_head(ce->name, state->super_prefix,
NULL, oid_to_hex(&ce->oid), 0);
} else
- return submodule_move_head(ce->name,
+ return submodule_move_head(ce->name, state->super_prefix,
"HEAD", oid_to_hex(&ce->oid),
state->force ? SUBMODULE_MOVE_HEAD_FORCE : 0);
}
@@ -560,12 +560,12 @@ int checkout_entry_ca(struct cache_entry *ce, struct conv_attrs *ca,
return write_entry(ce, path.buf, ca, state, 0, nr_checkouts);
}
-void unlink_entry(const struct cache_entry *ce)
+void unlink_entry(const struct cache_entry *ce, const char *super_prefix)
{
const struct submodule *sub = submodule_from_ce(ce);
if (sub) {
/* state.force is set at the caller. */
- submodule_move_head(ce->name, "HEAD", NULL,
+ submodule_move_head(ce->name, super_prefix, "HEAD", NULL,
SUBMODULE_MOVE_HEAD_FORCE);
}
if (check_leading_path(ce->name, ce_namelen(ce), 1) >= 0)
diff --git a/entry.h b/entry.h
index 9be4659881..2d4fbb88c8 100644
--- a/entry.h
+++ b/entry.h
@@ -8,6 +8,7 @@ struct checkout {
struct index_state *istate;
const char *base_dir;
int base_dir_len;
+ const char *super_prefix;
struct delayed_checkout *delayed_checkout;
struct checkout_metadata meta;
unsigned force:1,
@@ -48,8 +49,11 @@ int finish_delayed_checkout(struct checkout *state, int show_progress);
/*
* Unlink the last component and schedule the leading directories for
* removal, such that empty directories get removed.
+ *
+ * The "super_prefix" is either NULL, or the "--super-prefix" passed
+ * down from "read-tree" et al.
*/
-void unlink_entry(const struct cache_entry *ce);
+void unlink_entry(const struct cache_entry *ce, const char *super_prefix);
void *read_blob_entry(const struct cache_entry *ce, size_t *size);
int fstat_checkout_output(int fd, const struct checkout *state, struct stat *st);
diff --git a/environment.c b/environment.c
index 18d042b467..1ee3686fd8 100644
--- a/environment.c
+++ b/environment.c
@@ -102,8 +102,6 @@ char *git_work_tree_cfg;
static char *git_namespace;
-static char *super_prefix;
-
/*
* Repository-local GIT_* environment variables; see cache.h for details.
*/
@@ -121,7 +119,6 @@ const char * const local_repo_env[] = {
NO_REPLACE_OBJECTS_ENVIRONMENT,
GIT_REPLACE_REF_BASE_ENVIRONMENT,
GIT_PREFIX_ENVIRONMENT,
- GIT_SUPER_PREFIX_ENVIRONMENT,
GIT_SHALLOW_FILE_ENVIRONMENT,
GIT_COMMON_DIR_ENVIRONMENT,
NULL
@@ -234,16 +231,6 @@ const char *strip_namespace(const char *namespaced_ref)
return NULL;
}
-const char *get_super_prefix(void)
-{
- static int initialized;
- if (!initialized) {
- super_prefix = xstrdup_or_null(getenv(GIT_SUPER_PREFIX_ENVIRONMENT));
- initialized = 1;
- }
- return super_prefix;
-}
-
static int git_work_tree_initialized;
/*
diff --git a/fetch-pack.c b/fetch-pack.c
index 998fc2fa1e..04016d1e32 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -1317,15 +1317,15 @@ static void write_fetch_command_and_capabilities(struct strbuf *req_buf,
{
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 --git a/fsck.c b/fsck.c
index b3da1d68c0..47eaeedd70 100644
--- a/fsck.c
+++ b/fsck.c
@@ -2,6 +2,7 @@
#include "object-store.h"
#include "repository.h"
#include "object.h"
+#include "attr.h"
#include "blob.h"
#include "tree.h"
#include "tree-walk.h"
@@ -614,17 +615,22 @@ static int fsck_tree(const struct object_id *tree_oid,
".gitmodules is a symbolic link");
}
+ if (is_hfs_dotgitattributes(name) || is_ntfs_dotgitattributes(name)) {
+ if (!S_ISLNK(mode))
+ oidset_insert(&options->gitattributes_found,
+ entry_oid);
+ else
+ retval += report(options, tree_oid, OBJ_TREE,
+ FSCK_MSG_GITATTRIBUTES_SYMLINK,
+ ".gitattributes is a symlink");
+ }
+
if (S_ISLNK(mode)) {
if (is_hfs_dotgitignore(name) ||
is_ntfs_dotgitignore(name))
retval += report(options, tree_oid, OBJ_TREE,
FSCK_MSG_GITIGNORE_SYMLINK,
".gitignore is a symlink");
- if (is_hfs_dotgitattributes(name) ||
- is_ntfs_dotgitattributes(name))
- retval += report(options, tree_oid, OBJ_TREE,
- FSCK_MSG_GITATTRIBUTES_SYMLINK,
- ".gitattributes is a symlink");
if (is_hfs_dotmailmap(name) ||
is_ntfs_dotmailmap(name))
retval += report(options, tree_oid, OBJ_TREE,
@@ -1159,38 +1165,70 @@ static int fsck_gitmodules_fn(const char *var, const char *value, void *vdata)
static int fsck_blob(const struct object_id *oid, const char *buf,
unsigned long size, struct fsck_options *options)
{
- struct fsck_gitmodules_data data;
- struct config_options config_opts = { 0 };
-
- if (!oidset_contains(&options->gitmodules_found, oid))
- return 0;
- oidset_insert(&options->gitmodules_done, oid);
+ int ret = 0;
if (object_on_skiplist(options, oid))
return 0;
- if (!buf) {
- /*
- * A missing buffer here is a sign that the caller found the
- * blob too gigantic to load into memory. Let's just consider
- * that an error.
- */
- return report(options, oid, OBJ_BLOB,
- FSCK_MSG_GITMODULES_LARGE,
- ".gitmodules too large to parse");
+ if (oidset_contains(&options->gitmodules_found, oid)) {
+ struct config_options config_opts = { 0 };
+ struct fsck_gitmodules_data data;
+
+ oidset_insert(&options->gitmodules_done, oid);
+
+ if (!buf) {
+ /*
+ * A missing buffer here is a sign that the caller found the
+ * blob too gigantic to load into memory. Let's just consider
+ * that an error.
+ */
+ return report(options, oid, OBJ_BLOB,
+ FSCK_MSG_GITMODULES_LARGE,
+ ".gitmodules too large to parse");
+ }
+
+ data.oid = oid;
+ data.options = options;
+ data.ret = 0;
+ config_opts.error_action = CONFIG_ERROR_SILENT;
+ if (git_config_from_mem(fsck_gitmodules_fn, CONFIG_ORIGIN_BLOB,
+ ".gitmodules", buf, size, &data, &config_opts))
+ data.ret |= report(options, oid, OBJ_BLOB,
+ FSCK_MSG_GITMODULES_PARSE,
+ "could not parse gitmodules blob");
+ ret |= data.ret;
}
- data.oid = oid;
- data.options = options;
- data.ret = 0;
- config_opts.error_action = CONFIG_ERROR_SILENT;
- if (git_config_from_mem(fsck_gitmodules_fn, CONFIG_ORIGIN_BLOB,
- ".gitmodules", buf, size, &data, &config_opts))
- data.ret |= report(options, oid, OBJ_BLOB,
- FSCK_MSG_GITMODULES_PARSE,
- "could not parse gitmodules blob");
-
- return data.ret;
+ if (oidset_contains(&options->gitattributes_found, oid)) {
+ const char *ptr;
+
+ oidset_insert(&options->gitattributes_done, oid);
+
+ if (!buf || size > ATTR_MAX_FILE_SIZE) {
+ /*
+ * A missing buffer here is a sign that the caller found the
+ * blob too gigantic to load into memory. Let's just consider
+ * that an error.
+ */
+ return report(options, oid, OBJ_BLOB,
+ FSCK_MSG_GITATTRIBUTES_LARGE,
+ ".gitattributes too large to parse");
+ }
+
+ for (ptr = buf; *ptr; ) {
+ const char *eol = strchrnul(ptr, '\n');
+ if (eol - ptr >= ATTR_MAX_LINE_LENGTH) {
+ ret |= report(options, oid, OBJ_BLOB,
+ FSCK_MSG_GITATTRIBUTES_LINE_LENGTH,
+ ".gitattributes has too long lines to parse");
+ break;
+ }
+
+ ptr = *eol ? eol + 1 : eol;
+ }
+ }
+
+ return ret;
}
int fsck_object(struct object *obj, void *data, unsigned long size,
@@ -1229,19 +1267,21 @@ int fsck_error_function(struct fsck_options *o,
return 1;
}
-int fsck_finish(struct fsck_options *options)
+static int fsck_blobs(struct oidset *blobs_found, struct oidset *blobs_done,
+ enum fsck_msg_id msg_missing, enum fsck_msg_id msg_type,
+ struct fsck_options *options, const char *blob_type)
{
int ret = 0;
struct oidset_iter iter;
const struct object_id *oid;
- oidset_iter_init(&options->gitmodules_found, &iter);
+ oidset_iter_init(blobs_found, &iter);
while ((oid = oidset_iter_next(&iter))) {
enum object_type type;
unsigned long size;
char *buf;
- if (oidset_contains(&options->gitmodules_done, oid))
+ if (oidset_contains(blobs_done, oid))
continue;
buf = read_object_file(oid, &type, &size);
@@ -1249,25 +1289,36 @@ int fsck_finish(struct fsck_options *options)
if (is_promisor_object(oid))
continue;
ret |= report(options,
- oid, OBJ_BLOB,
- FSCK_MSG_GITMODULES_MISSING,
- "unable to read .gitmodules blob");
+ oid, OBJ_BLOB, msg_missing,
+ "unable to read %s blob", blob_type);
continue;
}
if (type == OBJ_BLOB)
ret |= fsck_blob(oid, buf, size, options);
else
- ret |= report(options,
- oid, type,
- FSCK_MSG_GITMODULES_BLOB,
- "non-blob found at .gitmodules");
+ ret |= report(options, oid, type, msg_type,
+ "non-blob found at %s", blob_type);
free(buf);
}
+ oidset_clear(blobs_found);
+ oidset_clear(blobs_done);
+
+ return ret;
+}
+
+int fsck_finish(struct fsck_options *options)
+{
+ int ret = 0;
+
+ ret |= fsck_blobs(&options->gitmodules_found, &options->gitmodules_done,
+ FSCK_MSG_GITMODULES_MISSING, FSCK_MSG_GITMODULES_BLOB,
+ options, ".gitmodules");
+ ret |= fsck_blobs(&options->gitattributes_found, &options->gitattributes_done,
+ FSCK_MSG_GITATTRIBUTES_MISSING, FSCK_MSG_GITATTRIBUTES_BLOB,
+ options, ".gitattributes");
- oidset_clear(&options->gitmodules_found);
- oidset_clear(&options->gitmodules_done);
return ret;
}
diff --git a/fsck.h b/fsck.h
index 6fbce68ad6..fcecf4101c 100644
--- a/fsck.h
+++ b/fsck.h
@@ -59,6 +59,10 @@ enum fsck_msg_type {
FUNC(GITMODULES_URL, ERROR) \
FUNC(GITMODULES_PATH, ERROR) \
FUNC(GITMODULES_UPDATE, ERROR) \
+ FUNC(GITATTRIBUTES_MISSING, ERROR) \
+ FUNC(GITATTRIBUTES_LARGE, ERROR) \
+ FUNC(GITATTRIBUTES_LINE_LENGTH, ERROR) \
+ FUNC(GITATTRIBUTES_BLOB, ERROR) \
/* warnings */ \
FUNC(EMPTY_NAME, WARN) \
FUNC(FULL_PATHNAME, WARN) \
@@ -133,6 +137,8 @@ struct fsck_options {
struct oidset skiplist;
struct oidset gitmodules_found;
struct oidset gitmodules_done;
+ struct oidset gitattributes_found;
+ struct oidset gitattributes_done;
kh_oid_map_t *object_names;
};
@@ -140,18 +146,24 @@ struct fsck_options {
.skiplist = OIDSET_INIT, \
.gitmodules_found = OIDSET_INIT, \
.gitmodules_done = OIDSET_INIT, \
+ .gitattributes_found = OIDSET_INIT, \
+ .gitattributes_done = OIDSET_INIT, \
.error_func = fsck_error_function \
}
#define FSCK_OPTIONS_STRICT { \
.strict = 1, \
.gitmodules_found = OIDSET_INIT, \
.gitmodules_done = OIDSET_INIT, \
+ .gitattributes_found = OIDSET_INIT, \
+ .gitattributes_done = OIDSET_INIT, \
.error_func = fsck_error_function, \
}
#define FSCK_OPTIONS_MISSING_GITMODULES { \
.strict = 1, \
.gitmodules_found = OIDSET_INIT, \
.gitmodules_done = OIDSET_INIT, \
+ .gitattributes_found = OIDSET_INIT, \
+ .gitattributes_done = OIDSET_INIT, \
.error_func = fsck_error_cb_print_missing_gitmodules, \
}
diff --git a/git-bisect.sh b/git-bisect.sh
deleted file mode 100755
index dfce4b4f44..0000000000
--- a/git-bisect.sh
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/bin/sh
-
-USAGE='[help|start|bad|good|new|old|terms|skip|next|reset|visualize|view|replay|log|run]'
-LONG_USAGE='git bisect help
- print this long help message.
-git bisect start [--term-{new,bad}=<term> --term-{old,good}=<term>]
- [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]
- reset bisect state and start bisection.
-git bisect (bad|new) [<rev>]
- mark <rev> a known-bad revision/
- a revision after change in a given property.
-git bisect (good|old) [<rev>...]
- mark <rev>... known-good revisions/
- revisions before change in a given property.
-git bisect terms [--term-good | --term-bad]
- show the terms used for old and new commits (default: bad, good)
-git bisect skip [(<rev>|<range>)...]
- mark <rev>... untestable revisions.
-git bisect next
- find next bisection to test and check it out.
-git bisect reset [<commit>]
- finish bisection search and go back to commit.
-git bisect (visualize|view)
- show bisect status in gitk.
-git bisect replay <logfile>
- replay bisection log.
-git bisect log
- show bisect log.
-git bisect run <cmd>...
- use <cmd>... to automatically bisect.
-
-Please use "git help bisect" to get the full man page.'
-
-OPTIONS_SPEC=
-. git-sh-setup
-
-TERM_BAD=bad
-TERM_GOOD=good
-
-get_terms () {
- if test -s "$GIT_DIR/BISECT_TERMS"
- then
- {
- read TERM_BAD
- read TERM_GOOD
- } <"$GIT_DIR/BISECT_TERMS"
- fi
-}
-
-case "$#" in
-0)
- usage ;;
-*)
- cmd="$1"
- get_terms
- shift
- case "$cmd" in
- help)
- git bisect -h ;;
- bad|good|new|old|"$TERM_BAD"|"$TERM_GOOD")
- git bisect--helper state "$cmd" "$@" ;;
- log)
- git bisect--helper log || exit ;;
- *)
- git bisect--helper "$cmd" "$@" ;;
- esac
-esac
diff --git a/git-compat-util.h b/git-compat-util.h
index 4824c8cad4..4f0028ce60 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -97,8 +97,14 @@ struct strbuf;
# define BARF_UNLESS_AN_ARRAY(arr) \
BUILD_ASSERT_OR_ZERO(!__builtin_types_compatible_p(__typeof__(arr), \
__typeof__(&(arr)[0])))
+# define BARF_UNLESS_COPYABLE(dst, src) \
+ BUILD_ASSERT_OR_ZERO(__builtin_types_compatible_p(__typeof__(*(dst)), \
+ __typeof__(*(src))))
#else
# define BARF_UNLESS_AN_ARRAY(arr) 0
+# define BARF_UNLESS_COPYABLE(dst, src) \
+ BUILD_ASSERT_OR_ZERO(0 ? ((*(dst) = *(src)), 0) : \
+ sizeof(*(dst)) == sizeof(*(src)))
#endif
/*
* ARRAY_SIZE - get the number of elements in a visible array
@@ -341,11 +347,13 @@ struct itimerval {
#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
@@ -1020,6 +1028,14 @@ static inline unsigned long cast_size_t_to_ulong(size_t a)
return (unsigned long)a;
}
+static inline int cast_size_t_to_int(size_t a)
+{
+ if (a > INT_MAX)
+ die("number too large to represent as int on this platform: %"PRIuMAX,
+ (uintmax_t)a);
+ return (int)a;
+}
+
/*
* Limit size of IO chunks, because huge chunks only cause pain. OS X
* 64-bit is buggy, returning EINVAL if len >= INT_MAX; and even in
@@ -1092,7 +1108,7 @@ int xstrncmpz(const char *s, const char *t, size_t len);
#define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult(sizeof(*(x)), (alloc)))
#define COPY_ARRAY(dst, src, n) copy_array((dst), (src), (n), sizeof(*(dst)) + \
- BUILD_ASSERT_OR_ZERO(sizeof(*(dst)) == sizeof(*(src))))
+ BARF_UNLESS_COPYABLE((dst), (src)))
static inline void copy_array(void *dst, const void *src, size_t n, size_t size)
{
if (n)
@@ -1100,13 +1116,18 @@ static inline void copy_array(void *dst, const void *src, size_t n, size_t size)
}
#define MOVE_ARRAY(dst, src, n) move_array((dst), (src), (n), sizeof(*(dst)) + \
- BUILD_ASSERT_OR_ZERO(sizeof(*(dst)) == sizeof(*(src))))
+ BARF_UNLESS_COPYABLE((dst), (src)))
static inline void move_array(void *dst, const void *src, size_t n, size_t size)
{
if (n)
memmove(dst, src, st_mult(size, n));
}
+#define DUP_ARRAY(dst, src, n) do { \
+ size_t dup_array_n_ = (n); \
+ COPY_ARRAY(ALLOC_ARRAY((dst), dup_array_n_), (src), dup_array_n_); \
+} while (0)
+
/*
* These functions help you allocate structs with flex arrays, and copy
* the data directly into the array. For example, if you had:
@@ -1476,14 +1497,19 @@ int open_nofollow(const char *path, int flags);
#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 --git a/git-curl-compat.h b/git-curl-compat.h
index 56a83b6bbd..fd96b3cdff 100644
--- a/git-curl-compat.h
+++ b/git-curl-compat.h
@@ -126,4 +126,12 @@
#define GIT_CURL_HAVE_CURLSSLSET_NO_BACKENDS
#endif
+/**
+ * CURLOPT_PROTOCOLS_STR and CURLOPT_REDIR_PROTOCOLS_STR were added in 7.85.0,
+ * released in August 2022.
+ */
+#if LIBCURL_VERSION_NUM >= 0x075500
+#define GIT_CURL_HAVE_CURLOPT_PROTOCOLS_STR 1
+#endif
+
#endif
diff --git a/git-submodule.sh b/git-submodule.sh
index 9a50f2e912..7f9582d923 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -244,6 +244,9 @@ cmd_update()
-q|--quiet)
quiet=1
;;
+ -v|--verbose)
+ quiet=0
+ ;;
--progress)
progress=1
;;
diff --git a/git.c b/git.c
index 10202a7f12..96b0a2837d 100644
--- a/git.c
+++ b/git.c
@@ -14,9 +14,8 @@
* RUN_SETUP for reading from the configuration file.
*/
#define NEED_WORK_TREE (1<<3)
-#define SUPPORT_SUPER_PREFIX (1<<4)
-#define DELAY_PAGER_CONFIG (1<<5)
-#define NO_PARSEOPT (1<<6) /* parse-options is not used */
+#define DELAY_PAGER_CONFIG (1<<4)
+#define NO_PARSEOPT (1<<5) /* parse-options is not used */
struct cmd_struct {
const char *cmd;
@@ -29,8 +28,7 @@ const char git_usage_string[] =
" [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
" [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]\n"
" [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
- " [--super-prefix=<path>] [--config-env=<name>=<envvar>]\n"
- " <command> [<args>]");
+ " [--config-env=<name>=<envvar>] <command> [<args>]");
const char git_more_info_string[] =
N_("'git help -a' and 'git help -g' list available subcommands and some\n"
@@ -226,20 +224,6 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
setenv(GIT_WORK_TREE_ENVIRONMENT, cmd, 1);
if (envchanged)
*envchanged = 1;
- } else if (!strcmp(cmd, "--super-prefix")) {
- if (*argc < 2) {
- fprintf(stderr, _("no prefix given for --super-prefix\n" ));
- usage(git_usage_string);
- }
- setenv(GIT_SUPER_PREFIX_ENVIRONMENT, (*argv)[1], 1);
- if (envchanged)
- *envchanged = 1;
- (*argv)++;
- (*argc)--;
- } else if (skip_prefix(cmd, "--super-prefix=", &cmd)) {
- setenv(GIT_SUPER_PREFIX_ENVIRONMENT, cmd, 1);
- if (envchanged)
- *envchanged = 1;
} else if (!strcmp(cmd, "--bare")) {
char *cwd = xgetcwd();
is_bare_repository_cfg = 1;
@@ -449,11 +433,6 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
trace_repo_setup(prefix);
commit_pager_choice();
- if (!help && get_super_prefix()) {
- if (!(p->option & SUPPORT_SUPER_PREFIX))
- die(_("%s doesn't support --super-prefix"), p->cmd);
- }
-
if (!help && p->option & NEED_WORK_TREE)
setup_work_tree();
@@ -492,7 +471,7 @@ static struct cmd_struct commands[] = {
{ "annotate", cmd_annotate, RUN_SETUP },
{ "apply", cmd_apply, RUN_SETUP_GENTLY },
{ "archive", cmd_archive, RUN_SETUP_GENTLY },
- { "bisect--helper", cmd_bisect__helper, RUN_SETUP },
+ { "bisect", cmd_bisect, RUN_SETUP },
{ "blame", cmd_blame, RUN_SETUP },
{ "branch", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },
{ "bugreport", cmd_bugreport, RUN_SETUP_GENTLY },
@@ -504,7 +483,7 @@ static struct cmd_struct commands[] = {
{ "check-ref-format", cmd_check_ref_format, NO_PARSEOPT },
{ "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
{ "checkout--worker", cmd_checkout__worker,
- RUN_SETUP | NEED_WORK_TREE | SUPPORT_SUPER_PREFIX },
+ RUN_SETUP | NEED_WORK_TREE },
{ "checkout-index", cmd_checkout_index,
RUN_SETUP | NEED_WORK_TREE},
{ "cherry", cmd_cherry, RUN_SETUP },
@@ -528,7 +507,6 @@ static struct cmd_struct commands[] = {
{ "diff-index", cmd_diff_index, RUN_SETUP | NO_PARSEOPT },
{ "diff-tree", cmd_diff_tree, RUN_SETUP | NO_PARSEOPT },
{ "difftool", cmd_difftool, RUN_SETUP_GENTLY },
- { "env--helper", cmd_env__helper },
{ "fast-export", cmd_fast_export, RUN_SETUP },
{ "fast-import", cmd_fast_import, RUN_SETUP | NO_PARSEOPT },
{ "fetch", cmd_fetch, RUN_SETUP },
@@ -539,7 +517,7 @@ static struct cmd_struct commands[] = {
{ "format-patch", cmd_format_patch, RUN_SETUP },
{ "fsck", cmd_fsck, RUN_SETUP },
{ "fsck-objects", cmd_fsck, RUN_SETUP },
- { "fsmonitor--daemon", cmd_fsmonitor__daemon, SUPPORT_SUPER_PREFIX | RUN_SETUP },
+ { "fsmonitor--daemon", cmd_fsmonitor__daemon, RUN_SETUP },
{ "gc", cmd_gc, RUN_SETUP },
{ "get-tar-commit-id", cmd_get_tar_commit_id, NO_PARSEOPT },
{ "grep", cmd_grep, RUN_SETUP_GENTLY },
@@ -583,7 +561,7 @@ static struct cmd_struct commands[] = {
{ "pull", cmd_pull, RUN_SETUP | NEED_WORK_TREE },
{ "push", cmd_push, RUN_SETUP },
{ "range-diff", cmd_range_diff, RUN_SETUP | USE_PAGER },
- { "read-tree", cmd_read_tree, RUN_SETUP | SUPPORT_SUPER_PREFIX},
+ { "read-tree", cmd_read_tree, RUN_SETUP },
{ "rebase", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },
{ "receive-pack", cmd_receive_pack },
{ "reflog", cmd_reflog, RUN_SETUP },
@@ -610,7 +588,7 @@ static struct cmd_struct commands[] = {
{ "stash", cmd_stash, RUN_SETUP | NEED_WORK_TREE },
{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
{ "stripspace", cmd_stripspace },
- { "submodule--helper", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX },
+ { "submodule--helper", cmd_submodule__helper, RUN_SETUP },
{ "switch", cmd_switch, RUN_SETUP | NEED_WORK_TREE },
{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
{ "tag", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },
@@ -727,9 +705,6 @@ static void execv_dashed_external(const char **argv)
struct child_process cmd = CHILD_PROCESS_INIT;
int status;
- if (get_super_prefix())
- die(_("%s doesn't support --super-prefix"), argv[0]);
-
if (use_pager == -1 && !is_builtin(argv[0]))
use_pager = check_pager_config(argv[0]);
commit_pager_choice();
@@ -799,9 +774,6 @@ static int run_argv(int *argcp, const char ***argv)
*/
trace2_cmd_name("_run_git_alias_");
- if (get_super_prefix())
- die("%s doesn't support --super-prefix", **argv);
-
commit_pager_choice();
strvec_push(&cmd.args, "git");
diff --git a/help.c b/help.c
index f1e090a442..812af4cdea 100644
--- a/help.c
+++ b/help.c
@@ -563,7 +563,7 @@ static int git_unknown_cmd_config(const char *var, const char *value, void *cb)
if (skip_prefix(var, "alias.", &p))
add_cmdname(&aliases, p, strlen(p));
- return git_default_config(var, value, cb);
+ return 0;
}
static int levenshtein_compare(const void *p1, const void *p2)
diff --git a/http-fetch.c b/http-fetch.c
index 31bc5c7767..258fec2068 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -5,6 +5,7 @@
#include "walker.h"
#include "strvec.h"
#include "urlmatch.h"
+#include "trace2.h"
static const char http_fetch_usage[] = "git http-fetch "
"[-c] [-t] [-a] [-v] [--recover] [-w ref] [--stdin | --packfile=hash | commit-id] url";
@@ -137,6 +138,8 @@ int cmd_main(int argc, const char **argv)
if (nongit)
die(_("not a git repository"));
+ trace2_cmd_name("http-fetch");
+
git_config(git_default_config, NULL);
if (packfile) {
diff --git a/http-push.c b/http-push.c
index 5f4340a36e..7f71316456 100644
--- a/http-push.c
+++ b/http-push.c
@@ -198,13 +198,13 @@ static void curl_setup_http(CURL *curl, const char *url,
const char *custom_req, struct buffer *buffer,
curl_write_callback write_fn)
{
- curl_easy_setopt(curl, CURLOPT_PUT, 1);
+ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_INFILE, buffer);
curl_easy_setopt(curl, CURLOPT_INFILESIZE, buffer->buf.len);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer);
- curl_easy_setopt(curl, CURLOPT_IOCTLFUNCTION, ioctl_buffer);
- curl_easy_setopt(curl, CURLOPT_IOCTLDATA, buffer);
+ curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, seek_buffer);
+ curl_easy_setopt(curl, CURLOPT_SEEKDATA, buffer);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_fn);
curl_easy_setopt(curl, CURLOPT_NOBODY, 0);
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, custom_req);
diff --git a/http.c b/http.c
index 8a5ba3f477..c4b6ddef28 100644
--- a/http.c
+++ b/http.c
@@ -157,21 +157,19 @@ size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
return size / eltsize;
}
-curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp)
+int seek_buffer(void *clientp, curl_off_t offset, int origin)
{
struct buffer *buffer = clientp;
- switch (cmd) {
- case CURLIOCMD_NOP:
- return CURLIOE_OK;
-
- case CURLIOCMD_RESTARTREAD:
- buffer->posn = 0;
- return CURLIOE_OK;
-
- default:
- return CURLIOE_UNKNOWNCMD;
+ if (origin != SEEK_SET)
+ BUG("seek_buffer only handles SEEK_SET");
+ if (offset < 0 || offset >= buffer->buf.len) {
+ error("curl seek would be outside of buffer");
+ return CURL_SEEKFUNC_FAIL;
}
+
+ buffer->posn = offset;
+ return CURL_SEEKFUNC_OK;
}
size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_)
@@ -766,20 +764,37 @@ void setup_curl_trace(CURL *handle)
curl_easy_setopt(handle, CURLOPT_DEBUGDATA, NULL);
}
-static long get_curl_allowed_protocols(int from_user)
+static void proto_list_append(struct strbuf *list, const char *proto)
{
- long allowed_protocols = 0;
+ if (!list)
+ return;
+ if (list->len)
+ strbuf_addch(list, ',');
+ strbuf_addstr(list, proto);
+}
- if (is_transport_allowed("http", from_user))
- allowed_protocols |= CURLPROTO_HTTP;
- if (is_transport_allowed("https", from_user))
- allowed_protocols |= CURLPROTO_HTTPS;
- if (is_transport_allowed("ftp", from_user))
- allowed_protocols |= CURLPROTO_FTP;
- if (is_transport_allowed("ftps", from_user))
- allowed_protocols |= CURLPROTO_FTPS;
+static long get_curl_allowed_protocols(int from_user, struct strbuf *list)
+{
+ long bits = 0;
- return allowed_protocols;
+ if (is_transport_allowed("http", from_user)) {
+ bits |= CURLPROTO_HTTP;
+ proto_list_append(list, "http");
+ }
+ if (is_transport_allowed("https", from_user)) {
+ bits |= CURLPROTO_HTTPS;
+ proto_list_append(list, "https");
+ }
+ if (is_transport_allowed("ftp", from_user)) {
+ bits |= CURLPROTO_FTP;
+ proto_list_append(list, "ftp");
+ }
+ if (is_transport_allowed("ftps", from_user)) {
+ bits |= CURLPROTO_FTPS;
+ proto_list_append(list, "ftps");
+ }
+
+ return bits;
}
#ifdef GIT_CURL_HAVE_CURL_HTTP_VERSION_2
@@ -923,10 +938,26 @@ static CURL *get_curl_handle(void)
curl_easy_setopt(result, CURLOPT_MAXREDIRS, 20);
curl_easy_setopt(result, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
+
+#ifdef GIT_CURL_HAVE_CURLOPT_PROTOCOLS_STR
+ {
+ struct strbuf buf = STRBUF_INIT;
+
+ get_curl_allowed_protocols(0, &buf);
+ curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS_STR, buf.buf);
+ strbuf_reset(&buf);
+
+ get_curl_allowed_protocols(-1, &buf);
+ curl_easy_setopt(result, CURLOPT_PROTOCOLS_STR, buf.buf);
+ strbuf_release(&buf);
+ }
+#else
curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS,
- get_curl_allowed_protocols(0));
+ get_curl_allowed_protocols(0, NULL));
curl_easy_setopt(result, CURLOPT_PROTOCOLS,
- get_curl_allowed_protocols(-1));
+ get_curl_allowed_protocols(-1, NULL));
+#endif
+
if (getenv("GIT_CURL_VERBOSE"))
http_trace_curl_no_data();
setup_curl_trace(result);
diff --git a/http.h b/http.h
index 3c94c47910..77c042706c 100644
--- a/http.h
+++ b/http.h
@@ -40,7 +40,7 @@ struct buffer {
size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *strbuf);
size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *strbuf);
size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf);
-curlioerr ioctl_buffer(CURL *handle, int cmd, void *clientp);
+int seek_buffer(void *clientp, curl_off_t offset, int origin);
/* Slot lifecycle functions */
struct active_request_slot *get_active_slot(void);
diff --git a/line-range.c b/line-range.c
index 955a8a9535..47bf0d6f1a 100644
--- a/line-range.c
+++ b/line-range.c
@@ -135,7 +135,7 @@ static const char *find_funcname_matching_regexp(xdemitconf_t *xecfg, const char
{
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 @@ static const char *find_funcname_matching_regexp(xdemitconf_t *xecfg, const char
/* 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 @@ static const char *find_funcname_matching_regexp(xdemitconf_t *xecfg, const char
return bol;
start = eol;
}
+ return NULL;
}
static const char *parse_range_funcname(
diff --git a/list-objects-filter-options.c b/list-objects-filter-options.c
index 5339660238..ee01bcd2cc 100644
--- a/list-objects-filter-options.c
+++ b/list-objects-filter-options.c
@@ -290,10 +290,6 @@ int opt_parse_list_objects_filter(const struct option *opt,
const char *arg, int unset)
{
struct list_objects_filter_options *filter_options = opt->value;
- opt_lof_init init = (opt_lof_init)opt->defval;
-
- if (init)
- filter_options = init(opt->value);
if (unset || !arg)
list_objects_filter_set_no_filter(filter_options);
diff --git a/list-objects-filter-options.h b/list-objects-filter-options.h
index 7eeadab2dd..1fe393f447 100644
--- a/list-objects-filter-options.h
+++ b/list-objects-filter-options.h
@@ -111,27 +111,13 @@ void parse_list_objects_filter(
* The opt->value to opt_parse_list_objects_filter() is either a
* "struct list_objects_filter_option *" when using
* OPT_PARSE_LIST_OBJECTS_FILTER().
- *
- * Or, if using no "struct option" field is used by the callback,
- * except the "defval" which is expected to be an "opt_lof_init"
- * function, which is called with the "opt->value" and must return a
- * pointer to the ""struct list_objects_filter_option *" to be used.
- *
- * The OPT_PARSE_LIST_OBJECTS_FILTER_INIT() can be used e.g. the
- * "struct list_objects_filter_option" is embedded in a "struct
- * rev_info", which the "defval" could be tasked with lazily
- * initializing. See cmd_pack_objects() for an example.
*/
int opt_parse_list_objects_filter(const struct option *opt,
const char *arg, int unset);
-typedef struct list_objects_filter_options *(*opt_lof_init)(void *);
-#define OPT_PARSE_LIST_OBJECTS_FILTER_INIT(fo, init) \
- { OPTION_CALLBACK, 0, "filter", (fo), N_("args"), \
- N_("object filtering"), 0, opt_parse_list_objects_filter, \
- (intptr_t)(init) }
#define OPT_PARSE_LIST_OBJECTS_FILTER(fo) \
- OPT_PARSE_LIST_OBJECTS_FILTER_INIT((fo), NULL)
+ OPT_CALLBACK(0, "filter", (fo), N_("args"), \
+ N_("object filtering"), opt_parse_list_objects_filter)
/*
* Translates abbreviated numbers in the filter's filter_spec into their
diff --git a/list-objects-filter.c b/list-objects-filter.c
index b9543545ca..7ed21cb299 100644
--- a/list-objects-filter.c
+++ b/list-objects-filter.c
@@ -70,13 +70,13 @@ struct filter {
};
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 enum list_objects_filter_result filter_blobs_none(
}
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 int filter_trees_update_omits(
}
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 @@ static enum list_objects_filter_result filter_blobs_limit(
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 enum list_objects_filter_result filter_sparse(
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 @@ struct filter_object_type_data {
};
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 @@ static enum list_objects_filter_result filter_combine(
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 --git a/list-objects.c b/list-objects.c
index 250d9de41c..7528fe1db2 100644
--- a/list-objects.c
+++ b/list-objects.c
@@ -81,36 +81,6 @@ static void process_blob(struct traversal_context *ctx,
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 @@ static void process_tree_contents(struct traversal_context *ctx,
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 --git a/ll-merge.c b/ll-merge.c
index 22a603e8af..130d26501c 100644
--- a/ll-merge.c
+++ b/ll-merge.c
@@ -391,7 +391,7 @@ enum ll_merge_result ll_merge(mmbuffer_t *result_buf,
normalize_file(theirs, path, istate);
}
- git_check_attr(istate, path, check);
+ git_check_attr(istate, NULL, path, check);
ll_driver_name = check->items[0].value;
if (check->items[1].value) {
marker_size = atoi(check->items[1].value);
@@ -419,7 +419,7 @@ int ll_merge_marker_size(struct index_state *istate, const char *path)
if (!check)
check = attr_check_initl("conflict-marker-size", NULL);
- git_check_attr(istate, path, check);
+ git_check_attr(istate, NULL, path, check);
if (check->items[0].value) {
marker_size = atoi(check->items[0].value);
if (marker_size <= 0)
diff --git a/ls-refs.c b/ls-refs.c
index fb6769742c..697d4beb8d 100644
--- a/ls-refs.c
+++ b/ls-refs.c
@@ -194,8 +194,9 @@ int ls_refs(struct repository *r, struct packet_reader *request)
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 --git a/merge-recursive.c b/merge-recursive.c
index 2fd0aa9687..0948b3ea96 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -412,7 +412,7 @@ static int unpack_trees_start(struct merge_options *opt,
{
int rc;
struct tree_desc t[3];
- struct index_state tmp_index = { NULL };
+ struct index_state tmp_index = INDEX_STATE_INIT;
memset(&opt->priv->unpack_opts, 0, sizeof(opt->priv->unpack_opts));
if (opt->priv->call_depth)
diff --git a/object-file.c b/object-file.c
index 26290554bb..ce9efae994 100644
--- a/object-file.c
+++ b/object-file.c
@@ -1211,35 +1211,25 @@ static int quick_has_loose(struct repository *r,
}
/*
- * Map the loose object at "path" if it is not NULL, or the path found by
- * searching for a loose object named "oid".
+ * Map and close the given loose object fd. The path argument is used for
+ * error reporting.
*/
-static void *map_loose_object_1(struct repository *r, const char *path,
- const struct object_id *oid, unsigned long *size)
+static void *map_fd(int fd, const char *path, unsigned long *size)
{
- void *map;
- int fd;
-
- if (path)
- fd = git_open(path);
- else
- fd = open_loose_object(r, oid, &path);
- map = NULL;
- if (fd >= 0) {
- struct stat st;
+ void *map = NULL;
+ struct stat st;
- if (!fstat(fd, &st)) {
- *size = xsize_t(st.st_size);
- if (!*size) {
- /* mmap() is forbidden on empty files */
- error(_("object file %s is empty"), path);
- close(fd);
- return NULL;
- }
- map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (!fstat(fd, &st)) {
+ *size = xsize_t(st.st_size);
+ if (!*size) {
+ /* mmap() is forbidden on empty files */
+ error(_("object file %s is empty"), path);
+ close(fd);
+ return NULL;
}
- close(fd);
+ map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0);
}
+ close(fd);
return map;
}
@@ -1247,7 +1237,12 @@ void *map_loose_object(struct repository *r,
const struct object_id *oid,
unsigned long *size)
{
- return map_loose_object_1(r, NULL, oid, size);
+ const char *p;
+ int fd = open_loose_object(r, oid, &p);
+
+ if (fd < 0)
+ return NULL;
+ return map_fd(fd, p, size);
}
enum unpack_loose_header_result unpack_loose_header(git_zstream *stream,
@@ -1427,7 +1422,9 @@ static int loose_object_info(struct repository *r,
struct object_info *oi, int flags)
{
int status = 0;
+ int fd;
unsigned long mapsize;
+ const char *path;
void *map;
git_zstream stream;
char hdr[MAX_HEADER_LEN];
@@ -1448,7 +1445,6 @@ static int loose_object_info(struct repository *r,
* object even exists.
*/
if (!oi->typep && !oi->type_name && !oi->sizep && !oi->contentp) {
- const char *path;
struct stat st;
if (!oi->disk_sizep && (flags & OBJECT_INFO_QUICK))
return quick_has_loose(r, oid) ? 0 : -1;
@@ -1459,7 +1455,13 @@ static int loose_object_info(struct repository *r,
return 0;
}
- map = map_loose_object(r, oid, &mapsize);
+ fd = open_loose_object(r, oid, &path);
+ if (fd < 0) {
+ if (errno != ENOENT)
+ error_errno(_("unable to open loose object %s"), oid_to_hex(oid));
+ return -1;
+ }
+ map = map_fd(fd, path, &mapsize);
if (!map)
return -1;
@@ -1497,6 +1499,10 @@ static int loose_object_info(struct repository *r,
break;
}
+ if (status && (flags & OBJECT_INFO_DIE_IF_CORRUPT))
+ die(_("loose object %s (stored in %s) is corrupt"),
+ oid_to_hex(oid), path);
+
git_inflate_end(&stream);
cleanup:
munmap(map, mapsize);
@@ -1575,9 +1581,6 @@ static int do_oid_object_info_extended(struct repository *r,
if (find_pack_entry(r, real, &e))
break;
- if (flags & OBJECT_INFO_IGNORE_LOOSE)
- return -1;
-
/* Most likely it's a loose object. */
if (!loose_object_info(r, real, oi, flags))
return 0;
@@ -1609,6 +1612,15 @@ static int do_oid_object_info_extended(struct repository *r,
continue;
}
+ if (flags & OBJECT_INFO_DIE_IF_CORRUPT) {
+ const struct packed_git *p;
+ if ((flags & OBJECT_INFO_LOOKUP_REPLACE) && !oideq(real, oid))
+ die(_("replacement %s not found for %s"),
+ oid_to_hex(real), oid_to_hex(oid));
+ if ((p = has_packed_and_bad(r, real)))
+ die(_("packed object %s (stored in %s) is corrupt"),
+ oid_to_hex(real), p->pack_name);
+ }
return -1;
}
@@ -1659,21 +1671,6 @@ int oid_object_info(struct repository *r,
return type;
}
-static void *read_object(struct repository *r,
- const struct object_id *oid, enum object_type *type,
- unsigned long *size)
-{
- struct object_info oi = OBJECT_INFO_INIT;
- void *content;
- oi.typep = type;
- oi.sizep = size;
- oi.contentp = &content;
-
- if (oid_object_info_extended(r, oid, &oi, 0) < 0)
- return NULL;
- return content;
-}
-
int pretend_object_file(void *buf, unsigned long len, enum object_type type,
struct object_id *oid)
{
@@ -1695,46 +1692,25 @@ int pretend_object_file(void *buf, unsigned long len, enum object_type type,
/*
* This function dies on corrupt objects; the callers who want to
- * deal with them should arrange to call read_object() and give error
- * messages themselves.
+ * deal with them should arrange to call oid_object_info_extended() and give
+ * error messages themselves.
*/
-void *read_object_file_extended(struct repository *r,
- const struct object_id *oid,
- enum object_type *type,
- unsigned long *size,
- int lookup_replace)
+void *repo_read_object_file(struct repository *r,
+ const struct object_id *oid,
+ enum object_type *type,
+ unsigned long *size)
{
+ struct object_info oi = OBJECT_INFO_INIT;
+ unsigned flags = OBJECT_INFO_DIE_IF_CORRUPT | OBJECT_INFO_LOOKUP_REPLACE;
void *data;
- const struct packed_git *p;
- const char *path;
- struct stat st;
- const struct object_id *repl = lookup_replace ?
- lookup_replace_object(r, oid) : oid;
-
- errno = 0;
- data = read_object(r, repl, type, size);
- if (data)
- return data;
-
- obj_read_lock();
- if (errno && errno != ENOENT)
- die_errno(_("failed to read object %s"), oid_to_hex(oid));
-
- /* die if we replaced an object with one that does not exist */
- if (repl != oid)
- die(_("replacement %s not found for %s"),
- oid_to_hex(repl), oid_to_hex(oid));
-
- if (!stat_loose_object(r, repl, &st, &path))
- die(_("loose object %s (stored in %s) is corrupt"),
- oid_to_hex(repl), path);
- if ((p = has_packed_and_bad(r, repl)))
- die(_("packed object %s (stored in %s) is corrupt"),
- oid_to_hex(repl), p->pack_name);
- obj_read_unlock();
+ oi.typep = type;
+ oi.sizep = size;
+ oi.contentp = &data;
+ if (oid_object_info_extended(r, oid, &oi, flags))
+ return NULL;
- return NULL;
+ return data;
}
void *read_object_with_reference(struct repository *r,
@@ -1864,13 +1840,6 @@ out:
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 +1984,8 @@ static int write_loose_object_common(git_hash_ctx *c,
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;
@@ -2269,6 +2238,7 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
{
void *buf;
unsigned long len;
+ struct object_info oi = OBJECT_INFO_INIT;
enum object_type type;
char hdr[MAX_HEADER_LEN];
int hdrlen;
@@ -2276,8 +2246,10 @@ int force_object_loose(const struct object_id *oid, time_t mtime)
if (has_loose_object(oid))
return 0;
- buf = read_object(the_repository, oid, &type, &len);
- if (!buf)
+ oi.typep = &type;
+ oi.sizep = &len;
+ oi.contentp = &buf;
+ if (oid_object_info_extended(the_repository, oid, &oi, 0))
return error(_("cannot read object for %s"), oid_to_hex(oid));
hdrlen = format_object_header(hdr, sizeof(hdr), type, len);
ret = write_loose_object(oid, hdr, hdrlen, buf, len, mtime, 0);
@@ -2792,13 +2764,16 @@ int read_loose_object(const char *path,
struct object_info *oi)
{
int ret = -1;
+ int fd;
void *map = NULL;
unsigned long mapsize;
git_zstream stream;
char hdr[MAX_HEADER_LEN];
unsigned long *size = oi->sizep;
- map = map_loose_object_1(the_repository, path, NULL, &mapsize);
+ fd = git_open(path);
+ if (fd >= 0)
+ map = map_fd(fd, path, &mapsize);
if (!map) {
error_errno(_("unable to mmap %s"), path);
goto out;
diff --git a/object-store.h b/object-store.h
index 1be57abaf1..1a713d89d7 100644
--- a/object-store.h
+++ b/object-store.h
@@ -241,17 +241,10 @@ const char *loose_object_path(struct repository *r, struct strbuf *buf,
void *map_loose_object(struct repository *r, const struct object_id *oid,
unsigned long *size);
-void *read_object_file_extended(struct repository *r,
- const struct object_id *oid,
- enum object_type *type,
- unsigned long *size, int lookup_replace);
-static inline void *repo_read_object_file(struct repository *r,
- const struct object_id *oid,
- enum object_type *type,
- unsigned long *size)
-{
- return read_object_file_extended(r, oid, type, size, 1);
-}
+void *repo_read_object_file(struct repository *r,
+ const struct object_id *oid,
+ enum object_type *type,
+ unsigned long *size);
#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
#define read_object_file(oid, type, size) repo_read_object_file(the_repository, oid, type, size)
#endif
@@ -358,8 +351,7 @@ void assert_oid_type(const struct object_id *oid, enum object_type expect);
/*
* Enabling the object read lock allows multiple threads to safely call the
* following functions in parallel: repo_read_object_file(), read_object_file(),
- * read_object_file_extended(), read_object_with_reference(), read_object(),
- * oid_object_info() and oid_object_info_extended().
+ * read_object_with_reference(), oid_object_info() and oid_object_info_extended().
*
* obj_read_lock() and obj_read_unlock() may also be used to protect other
* section which cannot execute in parallel with object reading. Since the used
@@ -434,19 +426,20 @@ struct object_info {
#define OBJECT_INFO_ALLOW_UNKNOWN_TYPE 2
/* Do not retry packed storage after checking packed and loose storage */
#define OBJECT_INFO_QUICK 8
-/* Do not check loose object */
-#define OBJECT_INFO_IGNORE_LOOSE 16
/*
* Do not attempt to fetch the object if missing (even if fetch_is_missing is
* nonzero).
*/
-#define OBJECT_INFO_SKIP_FETCH_OBJECT 32
+#define OBJECT_INFO_SKIP_FETCH_OBJECT 16
/*
* This is meant for bulk prefetching of missing blobs in a partial
* clone. Implies OBJECT_INFO_SKIP_FETCH_OBJECT and OBJECT_INFO_QUICK
*/
#define OBJECT_INFO_FOR_PREFETCH (OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK)
+/* Die if object corruption (not just an object being missing) was detected. */
+#define OBJECT_INFO_DIE_IF_CORRUPT 32
+
int oid_object_info_extended(struct repository *r,
const struct object_id *,
struct object_info *, unsigned flags);
diff --git a/object.c b/object.c
index 682b852a46..344087de4d 100644
--- a/object.c
+++ b/object.c
@@ -212,8 +212,7 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id
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 @@ struct object *parse_object_with_flags(struct repository *r,
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 --git a/pack-bitmap.c b/pack-bitmap.c
index 440407f1be..d2a42abf28 100644
--- a/pack-bitmap.c
+++ b/pack-bitmap.c
@@ -354,8 +354,8 @@ static int open_midx_bitmap_1(struct bitmap_index *bitmap_git,
if (bitmap_git->pack || bitmap_git->midx) {
struct strbuf buf = STRBUF_INIT;
get_midx_filename(&buf, midx->object_dir);
- /* ignore extra bitmap file; we can only handle one */
- warning(_("ignoring extra bitmap file: '%s'"), buf.buf);
+ trace2_data_string("bitmap", the_repository,
+ "ignoring extra midx bitmap file", buf.buf);
close(fd);
strbuf_release(&buf);
return -1;
@@ -411,9 +411,6 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git
struct stat st;
char *bitmap_name;
- if (open_pack_index(packfile))
- return -1;
-
bitmap_name = pack_bitmap_filename(packfile);
fd = git_open(bitmap_name);
@@ -432,8 +429,8 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git
}
if (bitmap_git->pack || bitmap_git->midx) {
- /* ignore extra bitmap file; we can only handle one */
- warning(_("ignoring extra bitmap file: '%s'"), packfile->pack_name);
+ trace2_data_string("bitmap", the_repository,
+ "ignoring extra bitmap file", packfile->pack_name);
close(fd);
return -1;
}
@@ -458,6 +455,8 @@ static int open_pack_bitmap_1(struct bitmap_index *bitmap_git, struct packed_git
return -1;
}
+ trace2_data_string("bitmap", the_repository, "opened bitmap file",
+ packfile->pack_name);
return 0;
}
@@ -525,11 +524,16 @@ static int open_pack_bitmap(struct repository *r,
struct packed_git *p;
int ret = -1;
- assert(!bitmap_git->map);
-
for (p = get_all_packs(r); p; p = p->next) {
- if (open_pack_bitmap_1(bitmap_git, p) == 0)
+ if (open_pack_bitmap_1(bitmap_git, p) == 0) {
ret = 0;
+ /*
+ * The only reason to keep looking is to report
+ * duplicates.
+ */
+ if (!trace2_is_enabled())
+ break;
+ }
}
return ret;
@@ -553,11 +557,20 @@ static int open_midx_bitmap(struct repository *r,
static int open_bitmap(struct repository *r,
struct bitmap_index *bitmap_git)
{
+ int found;
+
assert(!bitmap_git->map);
- if (!open_midx_bitmap(r, bitmap_git))
- return 0;
- return open_pack_bitmap(r, bitmap_git);
+ found = !open_midx_bitmap(r, bitmap_git);
+
+ /*
+ * these will all be skipped if we opened a midx bitmap; but run it
+ * anyway if tracing is enabled to report the duplicates
+ */
+ if (!found || trace2_is_enabled())
+ found |= !open_pack_bitmap(r, bitmap_git);
+
+ return found ? 0 : -1;
}
struct bitmap_index *prepare_bitmap_git(struct repository *r)
diff --git a/pack-write.c b/pack-write.c
index 00787e306d..3363729748 100644
--- a/pack-write.c
+++ b/pack-write.c
@@ -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 --git a/packfile.c b/packfile.c
index c0d7dd93f4..79e21ab18e 100644
--- a/packfile.c
+++ b/packfile.c
@@ -1650,22 +1650,6 @@ struct unpack_entry_stack_ent {
unsigned long size;
};
-static void *read_object(struct repository *r,
- const struct object_id *oid,
- enum object_type *type,
- unsigned long *size)
-{
- struct object_info oi = OBJECT_INFO_INIT;
- void *content;
- oi.typep = type;
- oi.sizep = size;
- oi.contentp = &content;
-
- if (oid_object_info_extended(r, oid, &oi, 0) < 0)
- return NULL;
- return content;
-}
-
void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
enum object_type *final_type, unsigned long *final_size)
{
@@ -1798,6 +1782,8 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
uint32_t pos;
struct object_id base_oid;
if (!(offset_to_pack_pos(p, obj_offset, &pos))) {
+ struct object_info oi = OBJECT_INFO_INIT;
+
nth_packed_object_id(&base_oid, p,
pack_pos_to_index(p, pos));
error("failed to read delta base object %s"
@@ -1805,7 +1791,13 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
oid_to_hex(&base_oid), (uintmax_t)obj_offset,
p->pack_name);
mark_bad_packed_object(p, &base_oid);
- base = read_object(r, &base_oid, &type, &base_size);
+
+ oi.typep = &type;
+ oi.sizep = &base_size;
+ oi.contentp = &base;
+ if (oid_object_info_extended(r, &base_oid, &oi, 0) < 0)
+ base = NULL;
+
external_base = base;
}
}
diff --git a/parse-options.c b/parse-options.c
index a1ec932f0f..fd4743293f 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -702,8 +702,7 @@ static struct option *preprocess_options(struct parse_opt_ctx_t *ctx,
if (!nr_aliases)
return NULL;
- ALLOC_ARRAY(newopt, nr + 1);
- COPY_ARRAY(newopt, options, nr + 1);
+ DUP_ARRAY(newopt, options, nr + 1);
/* each alias has two string pointers and NULL */
CALLOC_ARRAY(ctx->alias_groups, 3 * (nr_aliases + 1));
diff --git a/parse-options.h b/parse-options.h
index b6ef86e0d1..50d852f299 100644
--- a/parse-options.h
+++ b/parse-options.h
@@ -369,6 +369,10 @@ int parse_opt_tracking_mode(const struct option *, const char *, int);
{ OPTION_CALLBACK, 0, "abbrev", (var), N_("n"), \
N_("use <n> digits to display object names"), \
PARSE_OPT_OPTARG, &parse_opt_abbrev_cb, 0 }
+#define OPT__SUPER_PREFIX(var) \
+ OPT_STRING_F(0, "super-prefix", (var), N_("prefix"), \
+ N_("prefixed path to initial superproject"), PARSE_OPT_HIDDEN)
+
#define OPT__COLOR(var, h) \
OPT_COLOR_FLAG(0, "color", (var), (h))
#define OPT_COLUMN(s, l, v, h) \
diff --git a/pathspec.c b/pathspec.c
index 46e77a85fe..dbcfe7b321 100644
--- a/pathspec.c
+++ b/pathspec.c
@@ -681,8 +681,7 @@ void copy_pathspec(struct pathspec *dst, const struct pathspec *src)
int i, j;
*dst = *src;
- ALLOC_ARRAY(dst->items, dst->nr);
- COPY_ARRAY(dst->items, src->items, dst->nr);
+ DUP_ARRAY(dst->items, src->items, dst->nr);
for (i = 0; i < dst->nr; i++) {
struct pathspec_item *d = &dst->items[i];
@@ -691,8 +690,7 @@ void copy_pathspec(struct pathspec *dst, const struct pathspec *src)
d->match = xstrdup(s->match);
d->original = xstrdup(s->original);
- ALLOC_ARRAY(d->attr_match, d->attr_match_nr);
- COPY_ARRAY(d->attr_match, s->attr_match, d->attr_match_nr);
+ DUP_ARRAY(d->attr_match, s->attr_match, d->attr_match_nr);
for (j = 0; j < d->attr_match_nr; j++) {
const char *value = s->attr_match[j].value;
d->attr_match[j].value = xstrdup_or_null(value);
@@ -732,7 +730,7 @@ int match_pathspec_attrs(struct index_state *istate,
if (name[namelen])
name = to_free = xmemdupz(name, namelen);
- git_check_attr(istate, name, item->attr_check);
+ git_check_attr(istate, NULL, name, item->attr_check);
free(to_free);
diff --git a/pretty.c b/pretty.c
index 6cb363ae1c..1e1e21878c 100644
--- a/pretty.c
+++ b/pretty.c
@@ -14,6 +14,13 @@
#include "trailer.h"
#include "run-command.h"
+/*
+ * The limit for formatting directives, which enable the caller to append
+ * arbitrarily many bytes to the formatted buffer. This includes padding
+ * and wrapping formatters.
+ */
+#define FORMATTING_LIMIT (16 * 1024)
+
static char *user_format;
static struct cmt_fmt_map {
const char *name;
@@ -994,7 +1001,9 @@ static void strbuf_wrap(struct strbuf *sb, size_t pos,
if (pos)
strbuf_add(&tmp, sb->buf, pos);
strbuf_add_wrapped_text(&tmp, sb->buf + pos,
- (int) indent1, (int) indent2, (int) width);
+ cast_size_t_to_int(indent1),
+ cast_size_t_to_int(indent2),
+ cast_size_t_to_int(width));
strbuf_swap(&tmp, sb);
strbuf_release(&tmp);
}
@@ -1120,9 +1129,18 @@ static size_t parse_padding_placeholder(const char *placeholder,
const char *end = start + strcspn(start, ",)");
char *next;
int width;
- if (!end || end == start)
+ if (!*end || end == start)
return 0;
width = strtol(start, &next, 10);
+
+ /*
+ * We need to limit the amount of padding, or otherwise this
+ * would allow the user to pad the buffer by arbitrarily many
+ * bytes and thus cause resource exhaustion.
+ */
+ if (width < -FORMATTING_LIMIT || width > FORMATTING_LIMIT)
+ return 0;
+
if (next == start || width == 0)
return 0;
if (width < 0) {
@@ -1405,6 +1423,16 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */
if (*next != ')')
return 0;
}
+
+ /*
+ * We need to limit the format here as it allows the
+ * user to prepend arbitrarily many bytes to the buffer
+ * when rewrapping.
+ */
+ if (width > FORMATTING_LIMIT ||
+ indent1 > FORMATTING_LIMIT ||
+ indent2 > FORMATTING_LIMIT)
+ return 0;
rewrap_message_tail(sb, c, width, indent1, indent2);
return end - placeholder + 1;
} else
@@ -1670,19 +1698,21 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
struct format_commit_context *c)
{
struct strbuf local_sb = STRBUF_INIT;
- int total_consumed = 0, len, padding = c->padding;
+ size_t total_consumed = 0;
+ int len, padding = c->padding;
+
if (padding < 0) {
const char *start = strrchr(sb->buf, '\n');
int occupied;
if (!start)
start = sb->buf;
- occupied = utf8_strnwidth(start, -1, 1);
+ occupied = utf8_strnwidth(start, strlen(start), 1);
occupied += c->pretty_ctx->graph_width;
padding = (-padding) - occupied;
}
while (1) {
int modifier = *placeholder == 'C';
- int consumed = format_commit_one(&local_sb, placeholder, c);
+ size_t consumed = format_commit_one(&local_sb, placeholder, c);
total_consumed += consumed;
if (!modifier)
@@ -1694,7 +1724,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
placeholder++;
total_consumed++;
}
- len = utf8_strnwidth(local_sb.buf, -1, 1);
+ len = utf8_strnwidth(local_sb.buf, local_sb.len, 1);
if (c->flush_type == flush_left_and_steal) {
const char *ch = sb->buf + sb->len - 1;
@@ -1709,7 +1739,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
if (*ch != 'm')
break;
p = ch - 1;
- while (ch - p < 10 && *p != '\033')
+ while (p > sb->buf && ch - p < 10 && *p != '\033')
p--;
if (*p != '\033' ||
ch + 1 - p != display_mode_esc_sequence_len(p))
@@ -1748,7 +1778,7 @@ static size_t format_and_pad_commit(struct strbuf *sb, /* in UTF-8 */
}
strbuf_addbuf(sb, &local_sb);
} else {
- int sb_len = sb->len, offset = 0;
+ size_t sb_len = sb->len, offset = 0;
if (c->flush_type == flush_left)
offset = padding - len;
else if (c->flush_type == flush_both)
@@ -1771,8 +1801,7 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
const char *placeholder,
void *context)
{
- int consumed;
- size_t orig_len;
+ size_t consumed, orig_len;
enum {
NO_MAGIC,
ADD_LF_BEFORE_NON_EMPTY,
@@ -1793,9 +1822,21 @@ static size_t format_commit_item(struct strbuf *sb, /* in UTF-8 */
default:
break;
}
- if (magic != NO_MAGIC)
+ if (magic != NO_MAGIC) {
placeholder++;
+ switch (placeholder[0]) {
+ case 'w':
+ /*
+ * `%+w()` cannot ever expand to a non-empty string,
+ * and it potentially changes the layout of preceding
+ * contents. We're thus not able to handle the magic in
+ * this combination and refuse the pattern.
+ */
+ return 0;
+ };
+ }
+
orig_len = sb->len;
if (((struct format_commit_context *)context)->flush_type != no_flush)
consumed = format_and_pad_commit(sb, placeholder, context);
diff --git a/range-diff.c b/range-diff.c
index 8b7d81adc1..8255ab4349 100644
--- a/range-diff.c
+++ b/range-diff.c
@@ -269,14 +269,18 @@ static void find_exact_matches(struct string_list *a, struct string_list *b)
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 @@ static void patch_diff(const char *a, const char *b,
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 --git a/read-cache.c b/read-cache.c
index 46f5e497b1..d191741f60 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -1817,6 +1817,8 @@ static int verify_hdr(const struct cache_header *hdr, unsigned long size)
git_hash_ctx c;
unsigned char hash[GIT_MAX_RAWSZ];
int hdr_version;
+ unsigned char *start, *end;
+ struct object_id oid;
if (hdr->hdr_signature != htonl(CACHE_SIGNATURE))
return error(_("bad signature 0x%08x"), hdr->hdr_signature);
@@ -1827,10 +1829,16 @@ static int verify_hdr(const struct cache_header *hdr, unsigned long size)
if (!verify_index_checksum)
return 0;
+ end = (unsigned char *)hdr + size;
+ start = end - the_hash_algo->rawsz;
+ oidread(&oid, start);
+ if (oideq(&oid, null_oid()))
+ return 0;
+
the_hash_algo->init_fn(&c);
the_hash_algo->update_fn(&c, hdr, size - the_hash_algo->rawsz);
the_hash_algo->final_fn(hash, &c);
- if (!hasheq(hash, (unsigned char *)hdr + size - the_hash_algo->rawsz))
+ if (!hasheq(hash, start))
return error(_("bad index file sha1 signature"));
return 0;
}
@@ -2292,12 +2300,12 @@ static void set_new_index_sparsity(struct index_state *istate)
* If the index's repo exists, mark it sparse according to
* repo settings.
*/
- if (istate->repo) {
- prepare_repo_settings(istate->repo);
- if (!istate->repo->settings.command_requires_full_index &&
- is_sparse_index_allowed(istate, 0))
- istate->sparse_index = 1;
- }
+ if (!istate->repo)
+ return;
+ prepare_repo_settings(istate->repo);
+ if (!istate->repo->settings.command_requires_full_index &&
+ is_sparse_index_allowed(istate, 0))
+ istate->sparse_index = 1;
}
/* remember to discard_cache() before reading a different cache! */
@@ -2490,9 +2498,10 @@ int read_index_from(struct index_state *istate, const char *path,
trace_performance_enter();
if (split_index->base)
- discard_index(split_index->base);
+ release_index(split_index->base);
else
- CALLOC_ARRAY(split_index->base, 1);
+ ALLOC_ARRAY(split_index->base, 1);
+ index_state_init(split_index->base);
base_oid_hex = oid_to_hex(&split_index->base_oid);
base_path = xstrfmt("%s/sharedindex.%s", gitdir, base_oid_hex);
@@ -2531,7 +2540,13 @@ int is_index_unborn(struct index_state *istate)
return (!istate->cache_nr && !istate->timestamp.sec);
}
-void discard_index(struct index_state *istate)
+void index_state_init(struct index_state *istate)
+{
+ struct index_state blank = INDEX_STATE_INIT;
+ memcpy(istate, &blank, sizeof(*istate));
+}
+
+void release_index(struct index_state *istate)
{
/*
* Cache entries in istate->cache[] should have been allocated
@@ -2543,20 +2558,17 @@ void discard_index(struct index_state *istate)
validate_cache_entries(istate);
resolve_undo_clear_index(istate);
- istate->cache_nr = 0;
- istate->cache_changed = 0;
- istate->timestamp.sec = 0;
- istate->timestamp.nsec = 0;
free_name_hash(istate);
cache_tree_free(&(istate->cache_tree));
- istate->initialized = 0;
- istate->fsmonitor_has_run_once = 0;
- FREE_AND_NULL(istate->fsmonitor_last_update);
- FREE_AND_NULL(istate->cache);
- istate->cache_alloc = 0;
+ free(istate->fsmonitor_last_update);
+ free(istate->cache);
discard_split_index(istate);
free_untracked_cache(istate->untracked);
- istate->untracked = NULL;
+
+ if (istate->sparse_checkout_patterns) {
+ clear_pattern_list(istate->sparse_checkout_patterns);
+ FREE_AND_NULL(istate->sparse_checkout_patterns);
+ }
if (istate->ce_mem_pool) {
mem_pool_discard(istate->ce_mem_pool, should_validate_cache_entries());
@@ -2564,6 +2576,12 @@ void discard_index(struct index_state *istate)
}
}
+void discard_index(struct index_state *istate)
+{
+ release_index(istate);
+ index_state_init(istate);
+}
+
/*
* Validate the cache entries of this index.
* All cache entries associated with this index
@@ -2915,9 +2933,13 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
int ieot_entries = 1;
struct index_entry_offset_table *ieot = NULL;
int nr, nr_threads;
+ struct repository *r = istate->repo ? istate->repo : the_repository;
f = hashfd(tempfile->fd, tempfile->filename.buf);
+ prepare_repo_settings(r);
+ f->skip_hash = r->settings.index_skip_hash;
+
for (i = removed = extended = 0; i < entries; i++) {
if (cache[i]->ce_flags & CE_REMOVE)
removed++;
diff --git a/ref-filter.c b/ref-filter.c
index 9dc2cd1451..f8203c6b05 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -228,6 +228,22 @@ static int strbuf_addf_ret(struct strbuf *sb, int ret, const char *fmt, ...)
return ret;
}
+static int err_no_arg(struct strbuf *sb, const char *name)
+{
+ size_t namelen = strchrnul(name, ':') - name;
+ strbuf_addf(sb, _("%%(%.*s) does not take arguments"),
+ (int)namelen, name);
+ return -1;
+}
+
+static int err_bad_arg(struct strbuf *sb, const char *name, const char *arg)
+{
+ size_t namelen = strchrnul(name, ':') - name;
+ strbuf_addf(sb, _("unrecognized %%(%.*s) argument: %s"),
+ (int)namelen, name, arg);
+ return -1;
+}
+
static int color_atom_parser(struct ref_format *format, struct used_atom *atom,
const char *color_value, struct strbuf *err)
{
@@ -262,7 +278,7 @@ static int refname_atom_parser_internal(struct refname_atom *atom, const char *a
if (strtol_i(arg, 10, &atom->rstrip))
return strbuf_addf_ret(err, -1, _("Integer value expected refname:rstrip=%s"), arg);
} else
- return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), name, arg);
+ return err_bad_arg(err, name, arg);
return 0;
}
@@ -317,7 +333,7 @@ static int objecttype_atom_parser(struct ref_format *format, struct used_atom *a
const char *arg, struct strbuf *err)
{
if (arg)
- return strbuf_addf_ret(err, -1, _("%%(objecttype) does not take arguments"));
+ return err_no_arg(err, "objecttype");
if (*atom->name == '*')
oi_deref.info.typep = &oi_deref.type;
else
@@ -341,7 +357,7 @@ static int objectsize_atom_parser(struct ref_format *format, struct used_atom *a
else
oi.info.disk_sizep = &oi.disk_size;
} else
- return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "objectsize", arg);
+ return err_bad_arg(err, "objectsize", arg);
return 0;
}
@@ -349,7 +365,7 @@ static int deltabase_atom_parser(struct ref_format *format, struct used_atom *at
const char *arg, struct strbuf *err)
{
if (arg)
- return strbuf_addf_ret(err, -1, _("%%(deltabase) does not take arguments"));
+ return err_no_arg(err, "deltabase");
if (*atom->name == '*')
oi_deref.info.delta_base_oid = &oi_deref.delta_base_oid;
else
@@ -361,7 +377,7 @@ static int body_atom_parser(struct ref_format *format, struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (arg)
- return strbuf_addf_ret(err, -1, _("%%(body) does not take arguments"));
+ return err_no_arg(err, "body");
atom->u.contents.option = C_BODY_DEP;
return 0;
}
@@ -374,7 +390,7 @@ static int subject_atom_parser(struct ref_format *format, struct used_atom *atom
else if (!strcmp(arg, "sanitize"))
atom->u.contents.option = C_SUB_SANITIZE;
else
- return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "subject", arg);
+ return err_bad_arg(err, "subject", arg);
return 0;
}
@@ -428,7 +444,7 @@ static int contents_atom_parser(struct ref_format *format, struct used_atom *ato
if (strtoul_ui(arg, 10, &atom->u.contents.nlines))
return strbuf_addf_ret(err, -1, _("positive value expected contents:lines=%s"), arg);
} else
- return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "contents", arg);
+ return err_bad_arg(err, "contents", arg);
return 0;
}
@@ -440,7 +456,7 @@ static int raw_atom_parser(struct ref_format *format, struct used_atom *atom,
else if (!strcmp(arg, "size"))
atom->u.raw_data.option = RAW_LENGTH;
else
- return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "raw", arg);
+ return err_bad_arg(err, "raw", arg);
return 0;
}
@@ -459,7 +475,7 @@ static int oid_atom_parser(struct ref_format *format, struct used_atom *atom,
if (atom->u.oid.length < MINIMUM_ABBREV)
atom->u.oid.length = MINIMUM_ABBREV;
} else
- return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), atom->name, arg);
+ return err_bad_arg(err, atom->name, arg);
return 0;
}
@@ -473,7 +489,7 @@ static int person_email_atom_parser(struct ref_format *format, struct used_atom
else if (!strcmp(arg, "localpart"))
atom->u.email_option.option = EO_LOCALPART;
else
- return strbuf_addf_ret(err, -1, _("unrecognized email option: %s"), arg);
+ return err_bad_arg(err, atom->name, arg);
return 0;
}
@@ -557,7 +573,7 @@ static int if_atom_parser(struct ref_format *format, struct used_atom *atom,
} else if (skip_prefix(arg, "notequals=", &atom->u.if_then_else.str)) {
atom->u.if_then_else.cmp_status = COMPARE_UNEQUAL;
} else
- return strbuf_addf_ret(err, -1, _("unrecognized %%(%s) argument: %s"), "if", arg);
+ return err_bad_arg(err, "if", arg);
return 0;
}
@@ -565,14 +581,16 @@ static int rest_atom_parser(struct ref_format *format, struct used_atom *atom,
const char *arg, struct strbuf *err)
{
if (arg)
- return strbuf_addf_ret(err, -1, _("%%(rest) does not take arguments"));
+ return err_no_arg(err, "rest");
format->use_rest = 1;
return 0;
}
static int head_atom_parser(struct ref_format *format, struct used_atom *atom,
- const char *arg, struct strbuf *unused_err)
+ const char *arg, struct strbuf *err)
{
+ if (arg)
+ return err_no_arg(err, "HEAD");
atom->u.head = resolve_refdup("HEAD", RESOLVE_REF_READING, NULL, NULL);
return 0;
}
@@ -1191,7 +1209,7 @@ static const char *copy_name(const char *buf)
{
const char *cp;
for (cp = buf; *cp && *cp != '\n'; cp++) {
- if (!strncmp(cp, " <", 2))
+ if (starts_with(cp, " <"))
return xmemdupz(buf, cp - buf);
}
return xstrdup("");
@@ -1358,6 +1376,7 @@ static void find_subpos(const char *buf,
/* parse signature first; we might not even have a subject line */
parse_signature(buf, end - buf, &payload, &signature);
+ strbuf_release(&payload);
/* skip past header until we hit empty line */
while (*buf && *buf != '\n') {
@@ -2128,8 +2147,9 @@ static int for_each_fullref_in_pattern(struct ref_filter *filter,
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 --git a/reflog.c b/reflog.c
index 78e9350e20..04630f56ec 100644
--- a/reflog.c
+++ b/reflog.c
@@ -193,7 +193,6 @@ static void mark_reachable(struct expire_reflog_policy_cb *cb)
commit_list_insert(commit, &leftover);
continue;
}
- commit->object.flags |= REACHABLE;
parent = commit->parents;
while (parent) {
commit = parent->item;
@@ -371,6 +370,9 @@ void reflog_expiry_cleanup(void *cb_data)
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 --git a/refs.c b/refs.c
index 2c7e88b190..e31dbcda59 100644
--- a/refs.c
+++ b/refs.c
@@ -1723,9 +1723,10 @@ static void find_longest_prefixes(struct string_list *out,
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 @@ int for_each_fullref_in_prefixes(const char *namespace,
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 --git a/refs.h b/refs.h
index 3266fd8f57..935cdd1ece 100644
--- a/refs.h
+++ b/refs.h
@@ -354,8 +354,10 @@ int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data);
*
* 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 --git a/refs/packed-backend.c b/refs/packed-backend.c
index c1c71d183e..6f5a0709fb 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -1263,7 +1263,8 @@ static int write_with_updates(struct packed_ref_store *refs,
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 --git a/remote-curl.c b/remote-curl.c
index 72dfb8fb86..a76b6405eb 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -717,25 +717,23 @@ static size_t rpc_out(void *ptr, size_t eltsize,
return avail;
}
-static curlioerr rpc_ioctl(CURL *handle, int cmd, void *clientp)
+static int rpc_seek(void *clientp, curl_off_t offset, int origin)
{
struct rpc_state *rpc = clientp;
- switch (cmd) {
- case CURLIOCMD_NOP:
- return CURLIOE_OK;
+ if (origin != SEEK_SET)
+ BUG("rpc_seek only handles SEEK_SET, not %d", origin);
- case CURLIOCMD_RESTARTREAD:
- if (rpc->initial_buffer) {
- rpc->pos = 0;
- return CURLIOE_OK;
+ if (rpc->initial_buffer) {
+ if (offset < 0 || offset > rpc->len) {
+ error("curl seek would be outside of rpc buffer");
+ return CURL_SEEKFUNC_FAIL;
}
- error(_("unable to rewind rpc post data - try increasing http.postBuffer"));
- return CURLIOE_FAILRESTART;
-
- default:
- return CURLIOE_UNKNOWNCMD;
+ rpc->pos = offset;
+ return CURL_SEEKFUNC_OK;
}
+ error(_("unable to rewind rpc post data - try increasing http.postBuffer"));
+ return CURL_SEEKFUNC_FAIL;
}
struct check_pktline_state {
@@ -959,8 +957,8 @@ retry:
rpc->initial_buffer = 1;
curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, rpc_out);
curl_easy_setopt(slot->curl, CURLOPT_INFILE, rpc);
- curl_easy_setopt(slot->curl, CURLOPT_IOCTLFUNCTION, rpc_ioctl);
- curl_easy_setopt(slot->curl, CURLOPT_IOCTLDATA, rpc);
+ curl_easy_setopt(slot->curl, CURLOPT_SEEKFUNCTION, rpc_seek);
+ curl_easy_setopt(slot->curl, CURLOPT_SEEKDATA, rpc);
if (options.verbosity > 1) {
fprintf(stderr, "POST %s (chunked)\n", rpc->service_name);
fflush(stderr);
diff --git a/remote.h b/remote.h
index 1c4621b414..1ebbe42792 100644
--- a/remote.h
+++ b/remote.h
@@ -234,6 +234,11 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
const struct string_list *server_options,
int stateless_rpc);
+/* Used for protocol v2 in order to retrieve refs from a remote */
+struct bundle_list;
+int get_remote_bundle_uri(int fd_out, struct packet_reader *reader,
+ struct bundle_list *bundles, int stateless_rpc);
+
int resolve_remote_symref(struct ref *ref, struct ref *list);
/*
diff --git a/repo-settings.c b/repo-settings.c
index 3021921c53..3dbd3f0e2e 100644
--- a/repo-settings.c
+++ b/repo-settings.c
@@ -47,6 +47,7 @@ void prepare_repo_settings(struct repository *r)
}
if (manyfiles) {
r->settings.index_version = 4;
+ r->settings.index_skip_hash = 1;
r->settings.core_untracked_cache = UNTRACKED_CACHE_WRITE;
}
@@ -61,6 +62,7 @@ void prepare_repo_settings(struct repository *r)
repo_cfg_bool(r, "pack.usesparse", &r->settings.pack_use_sparse, 1);
repo_cfg_bool(r, "core.multipackindex", &r->settings.core_multi_pack_index, 1);
repo_cfg_bool(r, "index.sparse", &r->settings.sparse_index, 0);
+ repo_cfg_bool(r, "index.skiphash", &r->settings.index_skip_hash, r->settings.index_skip_hash);
/*
* The GIT_TEST_MULTI_PACK_INDEX variable is special in that
diff --git a/repository.c b/repository.c
index 3427085fd6..a5805fa33b 100644
--- a/repository.c
+++ b/repository.c
@@ -302,8 +302,10 @@ int repo_read_index(struct repository *repo)
{
int res;
- if (!repo->index)
- CALLOC_ARRAY(repo->index, 1);
+ if (!repo->index) {
+ ALLOC_ARRAY(repo->index, 1);
+ index_state_init(repo->index);
+ }
/* Complete the double-reference */
if (!repo->index->repo)
diff --git a/repository.h b/repository.h
index 6c461c5b9d..e8c67ffe16 100644
--- a/repository.h
+++ b/repository.h
@@ -42,6 +42,7 @@ struct repo_settings {
struct fsmonitor_settings *fsmonitor; /* lazily loaded */
int index_version;
+ int index_skip_hash;
enum untracked_cache_setting core_untracked_cache;
int pack_use_sparse;
diff --git a/revision.c b/revision.c
index 439e34a7c5..fb090886f5 100644
--- a/revision.c
+++ b/revision.c
@@ -600,10 +600,12 @@ static struct commit *one_relevant_parent(const struct rev_info *revs,
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_add_remove(struct diff_options *options,
}
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;
@@ -1808,7 +1813,7 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)
worktrees = get_worktrees();
for (p = worktrees; *p; p++) {
struct worktree *wt = *p;
- struct index_state istate = { NULL };
+ struct index_state istate = INDEX_STATE_INIT;
if (wt->is_current)
continue; /* current index already taken care of */
@@ -3054,6 +3059,7 @@ void release_revisions(struct rev_info *revs)
date_mode_release(&revs->date_mode);
release_revisions_mailmap(revs->mailmap);
free_grep_patterns(&revs->grep_filter);
+ graph_clear(revs->graph);
/* TODO (need to handle "no_free"): diff_free(&revs->diffopt) */
diff_free(&revs->pruning);
reflog_walk_info_release(revs->reflog_info);
diff --git a/run-command.c b/run-command.c
index 48b9ba6d6f..50cc011654 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1019,7 +1019,7 @@ static void *run_thread(void *data)
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGPIPE);
- if (pthread_sigmask(SIG_BLOCK, &mask, NULL) < 0) {
+ if (pthread_sigmask(SIG_BLOCK, &mask, NULL)) {
ret = error("unable to block SIGPIPE in async thread");
return (void *)ret;
}
@@ -1853,7 +1853,7 @@ enum start_bg_result start_bg_command(struct child_process *cmd,
*
* We also assume that `start_command()` does not add
* us to the cleanup list. And that it calls
- * calls `child_process_clear()`.
+ * `child_process_clear()`.
*/
sbgr = SBGR_ERROR;
goto done;
diff --git a/scalar.c b/scalar.c
index 6c52243cdf..b49bb8c24e 100644
--- a/scalar.c
+++ b/scalar.c
@@ -143,6 +143,7 @@ static int set_recommended_config(int reconfigure)
{ "credential.validate", "false", 1 }, /* GCM4W-only */
{ "gc.auto", "0", 1 },
{ "gui.GCWarning", "false", 1 },
+ { "index.skipHash", "false", 1 },
{ "index.threads", "true", 1 },
{ "index.version", "4", 1 },
{ "merge.stat", "false", 1 },
diff --git a/sequencer.c b/sequencer.c
index 9827e1adcb..3e4a197289 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -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"
@@ -2897,6 +2896,7 @@ static void read_strategy_opts(struct replay_opts *opts, struct strbuf *buf)
strbuf_reset(buf);
if (!read_oneliner(buf, rebase_path_strategy(), 0))
return;
+ free(opts->strategy);
opts->strategy = strbuf_detach(buf, NULL);
if (!read_oneliner(buf, rebase_path_strategy_opts(), 0))
return;
@@ -5745,8 +5745,8 @@ static void todo_list_add_exec_commands(struct todo_list *todo_list,
base_items[i].command = TODO_EXEC;
base_items[i].offset_in_buf = base_offset;
- base_items[i].arg_offset = base_offset + strlen("exec ");
- base_items[i].arg_len = command_len - strlen("exec ");
+ base_items[i].arg_offset = base_offset;
+ base_items[i].arg_len = command_len;
base_offset += command_len + 1;
}
diff --git a/serve.c b/serve.c
index 733347f602..cbf4a143cf 100644
--- a/serve.c
+++ b/serve.c
@@ -7,6 +7,7 @@
#include "protocol-caps.h"
#include "serve.h"
#include "upload-pack.h"
+#include "bundle-uri.h"
static int advertise_sid = -1;
static int client_hash_algo = GIT_HASH_SHA1;
@@ -135,6 +136,11 @@ static struct protocol_capability capabilities[] = {
.advertise = always_advertise,
.command = cap_object_info,
},
+ {
+ .name = "bundle-uri",
+ .advertise = bundle_uri_advertise,
+ .command = bundle_uri_command,
+ },
};
void protocol_v2_advertise_capabilities(void)
diff --git a/sparse-index.c b/sparse-index.c
index 8c269dab80..86e3b99870 100644
--- a/sparse-index.c
+++ b/sparse-index.c
@@ -299,7 +299,7 @@ void expand_index(struct index_state *istate, struct pattern_list *pl)
* If the index is already full, then keep it full. We will convert
* it to a sparse index on write, if possible.
*/
- if (!istate || istate->sparse_index == INDEX_EXPANDED)
+ if (istate->sparse_index == INDEX_EXPANDED)
return;
/*
@@ -424,6 +424,8 @@ void expand_index(struct index_state *istate, struct pattern_list *pl)
void ensure_full_index(struct index_state *istate)
{
+ if (!istate)
+ BUG("ensure_full_index() must get an index!");
expand_index(istate, NULL);
}
@@ -547,7 +549,7 @@ void expand_to_path(struct index_state *istate,
if (in_expand_to_path)
return;
- if (!istate || !istate->sparse_index)
+ if (!istate->sparse_index)
return;
if (!istate->repo)
diff --git a/split-index.c b/split-index.c
index 9d0ccc30d0..a5b56c0c37 100644
--- a/split-index.c
+++ b/split-index.c
@@ -90,7 +90,8 @@ void move_cache_to_base_index(struct index_state *istate)
mem_pool_combine(istate->ce_mem_pool, istate->split_index->base->ce_mem_pool);
}
- CALLOC_ARRAY(si->base, 1);
+ ALLOC_ARRAY(si->base, 1);
+ index_state_init(si->base);
si->base->version = istate->version;
/* zero timestamp disables racy test in ce_write_index() */
si->base->timestamp = istate->timestamp;
diff --git a/strbuf.c b/strbuf.c
index 0890b1405c..c383f41a3c 100644
--- a/strbuf.c
+++ b/strbuf.c
@@ -1200,3 +1200,9 @@ int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
free(path2);
return res;
}
+
+void strbuf_strip_file_from_path(struct strbuf *sb)
+{
+ char *path_sep = find_last_dir_sep(sb->buf);
+ strbuf_setlen(sb, path_sep ? path_sep - sb->buf + 1 : 0);
+}
diff --git a/strbuf.h b/strbuf.h
index 76965a17d4..f6dbb9681e 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -664,6 +664,17 @@ int launch_sequence_editor(const char *path, struct strbuf *buffer,
int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
const char *const *env);
+/*
+ * Remove the filename from the provided path string. If the path
+ * contains a trailing separator, then the path is considered a directory
+ * and nothing is modified.
+ *
+ * Examples:
+ * - "/path/to/file" -> "/path/to/"
+ * - "/path/to/dir/" -> "/path/to/dir/"
+ */
+void strbuf_strip_file_from_path(struct strbuf *sb);
+
void strbuf_add_lines(struct strbuf *sb,
const char *prefix,
const char *buf,
diff --git a/streaming.c b/streaming.c
index 7b2f8b2b93..27841dc1d9 100644
--- a/streaming.c
+++ b/streaming.c
@@ -38,7 +38,7 @@ struct git_istream {
union {
struct {
- char *buf; /* from read_object() */
+ char *buf; /* from oid_object_info_extended() */
unsigned long read_ptr;
} incore;
@@ -388,12 +388,17 @@ static ssize_t read_istream_incore(struct git_istream *st, char *buf, size_t sz)
static int open_istream_incore(struct git_istream *st, struct repository *r,
const struct object_id *oid, enum object_type *type)
{
- st->u.incore.buf = read_object_file_extended(r, oid, type, &st->size, 0);
+ struct object_info oi = OBJECT_INFO_INIT;
+
st->u.incore.read_ptr = 0;
st->close = close_istream_incore;
st->read = read_istream_incore;
- return st->u.incore.buf ? 0 : -1;
+ oi.typep = type;
+ oi.sizep = &st->size;
+ oi.contentp = (void **)&st->u.incore.buf;
+ return oid_object_info_extended(r, oid, &oi,
+ OBJECT_INFO_DIE_IF_CORRUPT);
}
/*****************************************************************************
diff --git a/submodule.c b/submodule.c
index 8ac2fca855..3a0dfc417c 100644
--- a/submodule.c
+++ b/submodule.c
@@ -832,7 +832,7 @@ static void changed_submodule_data_clear(struct changed_submodule_data *cs_data)
}
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;
@@ -2054,14 +2054,6 @@ void submodule_unset_core_worktree(const struct submodule *sub)
strbuf_release(&config_path);
}
-static const char *get_super_prefix_or_empty(void)
-{
- const char *s = get_super_prefix();
- if (!s)
- s = "";
- return s;
-}
-
static int submodule_has_dirty_index(const struct submodule *sub)
{
struct child_process cp = CHILD_PROCESS_INIT;
@@ -2080,7 +2072,7 @@ static int submodule_has_dirty_index(const struct submodule *sub)
return finish_command(&cp);
}
-static void submodule_reset_index(const char *path)
+static void submodule_reset_index(const char *path, const char *super_prefix)
{
struct child_process cp = CHILD_PROCESS_INIT;
prepare_submodule_repo_env(&cp.env);
@@ -2089,10 +2081,10 @@ static void submodule_reset_index(const char *path)
cp.no_stdin = 1;
cp.dir = path;
- strvec_pushf(&cp.args, "--super-prefix=%s%s/",
- get_super_prefix_or_empty(), path);
/* TODO: determine if this might overwright untracked files */
strvec_pushl(&cp.args, "read-tree", "-u", "--reset", NULL);
+ strvec_pushf(&cp.args, "--super-prefix=%s%s/",
+ (super_prefix ? super_prefix : ""), path);
strvec_push(&cp.args, empty_tree_oid_hex());
@@ -2105,10 +2097,9 @@ static void submodule_reset_index(const char *path)
* For edge cases (a submodule coming into existence or removing a submodule)
* pass NULL for old or new respectively.
*/
-int submodule_move_head(const char *path,
- const char *old_head,
- const char *new_head,
- unsigned flags)
+int submodule_move_head(const char *path, const char *super_prefix,
+ const char *old_head, const char *new_head,
+ unsigned flags)
{
int ret = 0;
struct child_process cp = CHILD_PROCESS_INIT;
@@ -2145,7 +2136,8 @@ int submodule_move_head(const char *path,
if (!(flags & SUBMODULE_MOVE_HEAD_DRY_RUN)) {
if (old_head) {
if (!submodule_uses_gitfile(path))
- absorb_git_dir_into_superproject(path);
+ absorb_git_dir_into_superproject(path,
+ super_prefix);
} else {
struct strbuf gitdir = STRBUF_INIT;
submodule_name_to_gitdir(&gitdir, the_repository,
@@ -2154,7 +2146,7 @@ int submodule_move_head(const char *path,
strbuf_release(&gitdir);
/* make sure the index is clean as well */
- submodule_reset_index(path);
+ submodule_reset_index(path, super_prefix);
}
if (old_head && (flags & SUBMODULE_MOVE_HEAD_FORCE)) {
@@ -2172,9 +2164,9 @@ int submodule_move_head(const char *path,
cp.no_stdin = 1;
cp.dir = path;
- strvec_pushf(&cp.args, "--super-prefix=%s%s/",
- get_super_prefix_or_empty(), path);
strvec_pushl(&cp.args, "read-tree", "--recurse-submodules", NULL);
+ strvec_pushf(&cp.args, "--super-prefix=%s%s/",
+ (super_prefix ? super_prefix : ""), path);
if (flags & SUBMODULE_MOVE_HEAD_DRY_RUN)
strvec_push(&cp.args, "-n");
@@ -2274,7 +2266,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name)
* Embeds a single submodules git directory into the superprojects git dir,
* non recursively.
*/
-static void relocate_single_git_dir_into_superproject(const char *path)
+static void relocate_single_git_dir_into_superproject(const char *path,
+ const char *super_prefix)
{
char *old_git_dir = NULL, *real_old_git_dir = NULL, *real_new_git_dir = NULL;
struct strbuf new_gitdir = STRBUF_INIT;
@@ -2304,7 +2297,7 @@ static void relocate_single_git_dir_into_superproject(const char *path)
real_new_git_dir = real_pathdup(new_gitdir.buf, 1);
fprintf(stderr, _("Migrating git directory of '%s%s' from\n'%s' to\n'%s'\n"),
- get_super_prefix_or_empty(), path,
+ super_prefix ? super_prefix : "", path,
real_old_git_dir, real_new_git_dir);
relocate_gitdir(path, real_old_git_dir, real_new_git_dir);
@@ -2315,7 +2308,8 @@ static void relocate_single_git_dir_into_superproject(const char *path)
strbuf_release(&new_gitdir);
}
-static void absorb_git_dir_into_superproject_recurse(const char *path)
+static void absorb_git_dir_into_superproject_recurse(const char *path,
+ const char *super_prefix)
{
struct child_process cp = CHILD_PROCESS_INIT;
@@ -2323,10 +2317,11 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)
cp.dir = path;
cp.git_cmd = 1;
cp.no_stdin = 1;
- strvec_pushf(&cp.args, "--super-prefix=%s%s/",
- get_super_prefix_or_empty(), path);
strvec_pushl(&cp.args, "submodule--helper",
"absorbgitdirs", NULL);
+ strvec_pushf(&cp.args, "--super-prefix=%s%s/", super_prefix ?
+ super_prefix : "", path);
+
prepare_submodule_repo_env(&cp.env);
if (run_command(&cp))
die(_("could not recurse into submodule '%s'"), path);
@@ -2337,7 +2332,8 @@ static void absorb_git_dir_into_superproject_recurse(const char *path)
* having its git directory within the working tree to the git dir nested
* in its superprojects git dir under modules/.
*/
-void absorb_git_dir_into_superproject(const char *path)
+void absorb_git_dir_into_superproject(const char *path,
+ const char *super_prefix)
{
int err_code;
const char *sub_git_dir;
@@ -2379,14 +2375,14 @@ void absorb_git_dir_into_superproject(const char *path)
char *real_common_git_dir = real_pathdup(get_git_common_dir(), 1);
if (!starts_with(real_sub_git_dir, real_common_git_dir))
- relocate_single_git_dir_into_superproject(path);
+ relocate_single_git_dir_into_superproject(path, super_prefix);
free(real_sub_git_dir);
free(real_common_git_dir);
}
strbuf_release(&gitdir);
- absorb_git_dir_into_superproject_recurse(path);
+ absorb_git_dir_into_superproject_recurse(path, super_prefix);
}
int get_superproject_working_tree(struct strbuf *buf)
diff --git a/submodule.h b/submodule.h
index b52a4ff1e7..c55a25ca37 100644
--- a/submodule.h
+++ b/submodule.h
@@ -150,9 +150,8 @@ int validate_submodule_git_dir(char *git_dir, const char *submodule_name);
#define SUBMODULE_MOVE_HEAD_DRY_RUN (1<<0)
#define SUBMODULE_MOVE_HEAD_FORCE (1<<1)
-int submodule_move_head(const char *path,
- const char *old,
- const char *new_head,
+int submodule_move_head(const char *path, const char *super_prefix,
+ const char *old_head, const char *new_head,
unsigned flags);
void submodule_unset_core_worktree(const struct submodule *sub);
@@ -164,7 +163,8 @@ void submodule_unset_core_worktree(const struct submodule *sub);
*/
void prepare_submodule_repo_env(struct strvec *env);
-void absorb_git_dir_into_superproject(const char *path);
+void absorb_git_dir_into_superproject(const char *path,
+ const char *super_prefix);
/*
* Return the absolute path of the working tree of the superproject, which this
diff --git a/t/helper/test-bundle-uri.c b/t/helper/test-bundle-uri.c
index 25afd39342..b18e760310 100644
--- a/t/helper/test-bundle-uri.c
+++ b/t/helper/test-bundle-uri.c
@@ -3,6 +3,10 @@
#include "bundle-uri.h"
#include "strbuf.h"
#include "string-list.h"
+#include "transport.h"
+#include "ref-filter.h"
+#include "remote.h"
+#include "refs.h"
enum input_mode {
KEY_VALUE_PAIRS,
@@ -36,6 +40,8 @@ static int cmd__bundle_uri_parse(int argc, const char **argv, enum input_mode mo
init_bundle_list(&list);
+ list.baseURI = xstrdup("<uri>");
+
switch (mode) {
case KEY_VALUE_PAIRS:
if (argc != 1)
@@ -68,6 +74,39 @@ usage:
usage_with_options(usage, options);
}
+static int cmd_ls_remote(int argc, const char **argv)
+{
+ const char *dest;
+ struct remote *remote;
+ struct transport *transport;
+ int status = 0;
+
+ dest = argc > 1 ? argv[1] : NULL;
+
+ remote = remote_get(dest);
+ if (!remote) {
+ if (dest)
+ die(_("bad repository '%s'"), dest);
+ die(_("no remote configured to get bundle URIs from"));
+ }
+ if (!remote->url_nr)
+ die(_("remote '%s' has no configured URL"), dest);
+
+ transport = transport_get(remote, NULL);
+ if (transport_get_remote_bundle_uri(transport) < 0) {
+ error(_("could not get the bundle-uri list"));
+ status = 1;
+ goto cleanup;
+ }
+
+ print_bundle_list(stdout, transport->bundles);
+
+cleanup:
+ if (transport_disconnect(transport))
+ return 1;
+ return status;
+}
+
int cmd__bundle_uri(int argc, const char **argv)
{
const char *usage[] = {
@@ -88,6 +127,8 @@ int cmd__bundle_uri(int argc, const char **argv)
return cmd__bundle_uri_parse(argc - 1, argv + 1, KEY_VALUE_PAIRS);
if (!strcmp(argv[1], "parse-config"))
return cmd__bundle_uri_parse(argc - 1, argv + 1, CONFIG_FILE);
+ if (!strcmp(argv[1], "ls-remote"))
+ return cmd_ls_remote(argc - 1, argv + 1);
error("there is no test-tool bundle-uri tool '%s'", argv[1]);
usage:
diff --git a/builtin/env--helper.c b/t/helper/test-env-helper.c
index ea04c16636..66c88b8ff3 100644
--- a/builtin/env--helper.c
+++ b/t/helper/test-env-helper.c
@@ -1,9 +1,9 @@
-#include "builtin.h"
+#include "test-tool.h"
#include "config.h"
#include "parse-options.h"
static char const * const env__helper_usage[] = {
- N_("git env--helper --type=[bool|ulong] <options> <env-var>"),
+ "test-tool env-helper --type=[bool|ulong] <options> <env-var>",
NULL
};
@@ -24,12 +24,12 @@ static int option_parse_type(const struct option *opt, const char *arg,
else if (!strcmp(arg, "ulong"))
*cmdmode = ENV_HELPER_TYPE_ULONG;
else
- die(_("unrecognized --type argument, %s"), arg);
+ die("unrecognized --type argument, %s", arg);
return 0;
}
-int cmd_env__helper(int argc, const char **argv, const char *prefix)
+int cmd__env_helper(int argc, const char **argv)
{
int exit_code = 0;
const char *env_variable = NULL;
@@ -39,17 +39,17 @@ int cmd_env__helper(int argc, const char **argv, const char *prefix)
unsigned long ret_ulong, default_ulong;
enum cmdmode cmdmode = 0;
struct option opts[] = {
- OPT_CALLBACK_F(0, "type", &cmdmode, N_("type"),
- N_("value is given this type"), PARSE_OPT_NONEG,
+ OPT_CALLBACK_F(0, "type", &cmdmode, "type",
+ "value is given this type", PARSE_OPT_NONEG,
option_parse_type),
- OPT_STRING(0, "default", &env_default, N_("value"),
- N_("default for git_env_*(...) to fall back on")),
+ OPT_STRING(0, "default", &env_default, "value",
+ "default for git_env_*(...) to fall back on"),
OPT_BOOL(0, "exit-code", &exit_code,
- N_("be quiet only use git_env_*() value as exit code")),
+ "be quiet only use git_env_*() value as exit code"),
OPT_END(),
};
- argc = parse_options(argc, argv, prefix, opts, env__helper_usage,
+ argc = parse_options(argc, argv, NULL, opts, env__helper_usage,
PARSE_OPT_KEEP_UNKNOWN_OPT);
if (env_default && !*env_default)
usage_with_options(env__helper_usage, opts);
@@ -64,7 +64,7 @@ int cmd_env__helper(int argc, const char **argv, const char *prefix)
if (env_default) {
default_int = git_parse_maybe_bool(env_default);
if (default_int == -1) {
- error(_("option `--default' expects a boolean value with `--type=bool`, not `%s`"),
+ error("option `--default' expects a boolean value with `--type=bool`, not `%s`",
env_default);
usage_with_options(env__helper_usage, opts);
}
@@ -79,7 +79,7 @@ int cmd_env__helper(int argc, const char **argv, const char *prefix)
case ENV_HELPER_TYPE_ULONG:
if (env_default) {
if (!git_parse_ulong(env_default, &default_ulong)) {
- error(_("option `--default' expects an unsigned long value with `--type=ulong`, not `%s`"),
+ error("option `--default' expects an unsigned long value with `--type=ulong`, not `%s`",
env_default);
usage_with_options(env__helper_usage, opts);
}
diff --git a/t/helper/test-fake-ssh.c b/t/helper/test-fake-ssh.c
index 2e576bcc11..27323cb367 100644
--- a/t/helper/test-fake-ssh.c
+++ b/t/helper/test-fake-ssh.c
@@ -17,6 +17,7 @@ int cmd_main(int argc, const char **argv)
f = fopen(buf.buf, "w");
if (!f)
die("Could not write to %s", buf.buf);
+ strbuf_release(&buf);
for (i = 0; i < argc; i++)
fprintf(f, "%s%s", i > 0 ? " " : "", i > 0 ? argv[i] : "ssh:");
fprintf(f, "\n");
diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c
index 7eb1a26a30..abe8a785eb 100644
--- a/t/helper/test-tool.c
+++ b/t/helper/test-tool.c
@@ -28,6 +28,7 @@ static struct test_cmd cmds[] = {
{ "dump-fsmonitor", cmd__dump_fsmonitor },
{ "dump-split-index", cmd__dump_split_index },
{ "dump-untracked-cache", cmd__dump_untracked_cache },
+ { "env-helper", cmd__env_helper },
{ "example-decorate", cmd__example_decorate },
{ "fast-rebase", cmd__fast_rebase },
{ "fsmonitor-client", cmd__fsmonitor_client },
diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h
index 2e20a16eb8..ea2672436c 100644
--- a/t/helper/test-tool.h
+++ b/t/helper/test-tool.h
@@ -22,6 +22,7 @@ int cmd__dump_fsmonitor(int argc, const char **argv);
int cmd__dump_split_index(int argc, const char **argv);
int cmd__dump_untracked_cache(int argc, const char **argv);
int cmd__dump_reftable(int argc, const char **argv);
+int cmd__env_helper(int argc, const char **argv);
int cmd__example_decorate(int argc, const char **argv);
int cmd__fast_rebase(int argc, const char **argv);
int cmd__fsmonitor_client(int argc, const char **argv);
diff --git a/t/interop/interop-lib.sh b/t/interop/interop-lib.sh
index 3e0a2911d4..62f4481b6e 100644
--- a/t/interop/interop-lib.sh
+++ b/t/interop/interop-lib.sh
@@ -68,7 +68,7 @@ generate_wrappers () {
wrap_git .bin/git.a "$DIR_A" &&
wrap_git .bin/git.b "$DIR_B" &&
write_script .bin/git <<-\EOF &&
- echo >&2 fatal: test tried to run generic git
+ echo >&2 fatal: test tried to run generic git: $*
exit 1
EOF
PATH=$(pwd)/.bin:$PATH
diff --git a/t/lib-bundle-uri-protocol.sh b/t/lib-bundle-uri-protocol.sh
new file mode 100644
index 0000000000..a4a1af8d02
--- /dev/null
+++ b/t/lib-bundle-uri-protocol.sh
@@ -0,0 +1,216 @@
+# Set up and run tests of the 'bundle-uri' command in protocol v2
+#
+# The test that includes this script should set BUNDLE_URI_PROTOCOL
+# to one of "file", "git", or "http".
+
+BUNDLE_URI_TEST_PARENT=
+BUNDLE_URI_TEST_URI=
+BUNDLE_URI_TEST_BUNDLE_URI=
+case "$BUNDLE_URI_PROTOCOL" in
+file)
+ BUNDLE_URI_PARENT=file_parent
+ BUNDLE_URI_REPO_URI="file://$PWD/file_parent"
+ BUNDLE_URI_BUNDLE_URI="$BUNDLE_URI_REPO_URI/fake.bdl"
+ test_set_prereq BUNDLE_URI_FILE
+ ;;
+git)
+ . "$TEST_DIRECTORY"/lib-git-daemon.sh
+ start_git_daemon --export-all --enable=receive-pack
+ BUNDLE_URI_PARENT="$GIT_DAEMON_DOCUMENT_ROOT_PATH/parent"
+ BUNDLE_URI_REPO_URI="$GIT_DAEMON_URL/parent"
+ BUNDLE_URI_BUNDLE_URI="https://example.com/fake.bdl"
+ test_set_prereq BUNDLE_URI_GIT
+ ;;
+http)
+ . "$TEST_DIRECTORY"/lib-httpd.sh
+ start_httpd
+ BUNDLE_URI_PARENT="$HTTPD_DOCUMENT_ROOT_PATH/http_parent"
+ BUNDLE_URI_REPO_URI="$HTTPD_URL/smart/http_parent"
+ BUNDLE_URI_BUNDLE_URI="https://example.com/fake.bdl"
+ test_set_prereq BUNDLE_URI_HTTP
+ ;;
+*)
+ BUG "Need to pass valid BUNDLE_URI_PROTOCOL (was \"$BUNDLE_URI_PROTOCOL\")"
+ ;;
+esac
+
+test_expect_success "setup protocol v2 $BUNDLE_URI_PROTOCOL:// tests" '
+ git init "$BUNDLE_URI_PARENT" &&
+ test_commit -C "$BUNDLE_URI_PARENT" one &&
+ git -C "$BUNDLE_URI_PARENT" config uploadpack.advertiseBundleURIs true
+'
+
+case "$BUNDLE_URI_PROTOCOL" in
+http)
+ test_expect_success "setup config for $BUNDLE_URI_PROTOCOL:// tests" '
+ git -C "$BUNDLE_URI_PARENT" config http.receivepack true
+ '
+ ;;
+*)
+ ;;
+esac
+BUNDLE_URI_BUNDLE_URI_ESCAPED=$(echo "$BUNDLE_URI_BUNDLE_URI" | test_uri_escape)
+
+test_expect_success "connect with $BUNDLE_URI_PROTOCOL:// using protocol v2: no bundle-uri" '
+ test_when_finished "rm -f log" &&
+ test_when_finished "git -C \"$BUNDLE_URI_PARENT\" config uploadpack.advertiseBundleURIs true" &&
+ git -C "$BUNDLE_URI_PARENT" config uploadpack.advertiseBundleURIs false &&
+
+ GIT_TRACE_PACKET="$PWD/log" \
+ git \
+ -c protocol.version=2 \
+ ls-remote --symref "$BUNDLE_URI_REPO_URI" \
+ >actual 2>err &&
+
+ # Server responded using protocol v2
+ grep "< version 2" log &&
+
+ ! grep bundle-uri log
+'
+
+test_expect_success "connect with $BUNDLE_URI_PROTOCOL:// using protocol v2: have bundle-uri" '
+ test_when_finished "rm -f log" &&
+
+ GIT_TRACE_PACKET="$PWD/log" \
+ git \
+ -c protocol.version=2 \
+ ls-remote --symref "$BUNDLE_URI_REPO_URI" \
+ >actual 2>err &&
+
+ # Server responded using protocol v2
+ grep "< version 2" log &&
+
+ # Server advertised bundle-uri capability
+ grep "< bundle-uri" log
+'
+
+test_expect_success "clone with $BUNDLE_URI_PROTOCOL:// using protocol v2: request bundle-uris" '
+ test_when_finished "rm -rf log* cloned*" &&
+
+ GIT_TRACE_PACKET="$PWD/log" \
+ git \
+ -c transfer.bundleURI=false \
+ -c protocol.version=2 \
+ clone "$BUNDLE_URI_REPO_URI" cloned \
+ >actual 2>err &&
+
+ # Server responded using protocol v2
+ grep "< version 2" log &&
+
+ # Server advertised bundle-uri capability
+ grep "< bundle-uri" log &&
+
+ # Client did not issue bundle-uri command
+ ! grep "> command=bundle-uri" log &&
+
+ GIT_TRACE_PACKET="$PWD/log" \
+ git \
+ -c transfer.bundleURI=true \
+ -c protocol.version=2 \
+ clone "$BUNDLE_URI_REPO_URI" cloned2 \
+ >actual 2>err &&
+
+ # Server responded using protocol v2
+ grep "< version 2" log &&
+
+ # Server advertised bundle-uri capability
+ grep "< bundle-uri" log &&
+
+ # Client issued bundle-uri command
+ grep "> command=bundle-uri" log &&
+
+ GIT_TRACE_PACKET="$PWD/log3" \
+ git \
+ -c transfer.bundleURI=true \
+ -c protocol.version=2 \
+ clone --bundle-uri="$BUNDLE_URI_BUNDLE_URI" \
+ "$BUNDLE_URI_REPO_URI" cloned3 \
+ >actual 2>err &&
+
+ # Server responded using protocol v2
+ grep "< version 2" log3 &&
+
+ # Server advertised bundle-uri capability
+ grep "< bundle-uri" log3 &&
+
+ # Client did not issue bundle-uri command (--bundle-uri override)
+ ! grep "> command=bundle-uri" log3
+'
+
+# The remaining tests will all assume transfer.bundleURI=true
+#
+# This test can be removed when transfer.bundleURI is enabled by default.
+test_expect_success 'enable transfer.bundleURI for remaining tests' '
+ git config --global transfer.bundleURI true
+'
+
+test_expect_success "test bundle-uri with $BUNDLE_URI_PROTOCOL:// using protocol v2" '
+ test_config -C "$BUNDLE_URI_PARENT" \
+ bundle.only.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED" &&
+
+ # All data about bundle URIs
+ cat >expect <<-EOF &&
+ [bundle]
+ version = 1
+ mode = all
+ [bundle "only"]
+ uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED
+ EOF
+
+ test-tool bundle-uri \
+ ls-remote \
+ "$BUNDLE_URI_REPO_URI" \
+ >actual &&
+ test_cmp_config_output expect actual
+'
+
+test_expect_success "test bundle-uri with $BUNDLE_URI_PROTOCOL:// using protocol v2 and extra data" '
+ test_config -C "$BUNDLE_URI_PARENT" \
+ bundle.only.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED" &&
+
+ # Extra data should be ignored
+ test_config -C "$BUNDLE_URI_PARENT" bundle.only.extra bogus &&
+
+ # All data about bundle URIs
+ cat >expect <<-EOF &&
+ [bundle]
+ version = 1
+ mode = all
+ [bundle "only"]
+ uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED
+ EOF
+
+ test-tool bundle-uri \
+ ls-remote \
+ "$BUNDLE_URI_REPO_URI" \
+ >actual &&
+ test_cmp_config_output expect actual
+'
+
+test_expect_success "test bundle-uri with $BUNDLE_URI_PROTOCOL:// using protocol v2 with list" '
+ test_config -C "$BUNDLE_URI_PARENT" \
+ bundle.bundle1.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED-1.bdl" &&
+ test_config -C "$BUNDLE_URI_PARENT" \
+ bundle.bundle2.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED-2.bdl" &&
+ test_config -C "$BUNDLE_URI_PARENT" \
+ bundle.bundle3.uri "$BUNDLE_URI_BUNDLE_URI_ESCAPED-3.bdl" &&
+
+ # All data about bundle URIs
+ cat >expect <<-EOF &&
+ [bundle]
+ version = 1
+ mode = all
+ [bundle "bundle1"]
+ uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED-1.bdl
+ [bundle "bundle2"]
+ uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED-2.bdl
+ [bundle "bundle3"]
+ uri = $BUNDLE_URI_BUNDLE_URI_ESCAPED-3.bdl
+ EOF
+
+ test-tool bundle-uri \
+ ls-remote \
+ "$BUNDLE_URI_REPO_URI" \
+ >actual &&
+ test_cmp_config_output expect actual
+'
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 502b4bcf9e..8ea31d187a 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -815,7 +815,8 @@ test_expect_success 'test_oid provides sane info by default' '
grep "^00*\$" actual &&
rawsz="$(test_oid rawsz)" &&
hexsz="$(test_oid hexsz)" &&
- test "$hexsz" -eq $(wc -c <actual) &&
+ # +1 accounts for the trailing newline
+ test $(( $hexsz + 1)) -eq $(wc -c <actual) &&
test $(( $rawsz * 2)) -eq "$hexsz"
'
@@ -826,7 +827,7 @@ test_expect_success 'test_oid can look up data for SHA-1' '
grep "^00*\$" actual &&
rawsz="$(test_oid rawsz)" &&
hexsz="$(test_oid hexsz)" &&
- test $(wc -c <actual) -eq 40 &&
+ test $(wc -c <actual) -eq 41 &&
test "$rawsz" -eq 20 &&
test "$hexsz" -eq 40
'
@@ -838,7 +839,7 @@ test_expect_success 'test_oid can look up data for SHA-256' '
grep "^00*\$" actual &&
rawsz="$(test_oid rawsz)" &&
hexsz="$(test_oid hexsz)" &&
- test $(wc -c <actual) -eq 64 &&
+ test $(wc -c <actual) -eq 65 &&
test "$rawsz" -eq 32 &&
test "$hexsz" -eq 64
'
diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
index f7ee2f2ff0..a8af15b91c 100755
--- a/t/t0003-attributes.sh
+++ b/t/t0003-attributes.sh
@@ -25,7 +25,15 @@ attr_check_quote () {
git check-attr test -- "$path" >actual &&
echo "\"$quoted_path\": test: $expect" >expect &&
test_cmp expect actual
+}
+
+attr_check_source () {
+ path="$1" expect="$2" source="$3" git_opts="$4" &&
+ git $git_opts check-attr --source $source test -- "$path" >actual 2>err &&
+ echo "$path: test: $expect" >expect &&
+ test_cmp expect actual &&
+ test_must_be_empty err
}
test_expect_success 'open-quoted pathname' '
@@ -33,7 +41,6 @@ test_expect_success 'open-quoted pathname' '
attr_check a unspecified
'
-
test_expect_success 'setup' '
mkdir -p a/b/d a/c b &&
(
@@ -80,12 +87,23 @@ test_expect_success 'setup' '
EOF
'
+test_expect_success 'setup branches' '
+ mkdir -p foo/bar &&
+ test_commit --printf "add .gitattributes" foo/bar/.gitattributes \
+ "f test=f\na/i test=n\n" tag-1 &&
+ test_commit --printf "add .gitattributes" foo/bar/.gitattributes \
+ "g test=g\na/i test=m\n" tag-2 &&
+ rm foo/bar/.gitattributes
+'
+
test_expect_success 'command line checks' '
test_must_fail git check-attr &&
test_must_fail git check-attr -- &&
test_must_fail git check-attr test &&
test_must_fail git check-attr test -- &&
test_must_fail git check-attr -- f &&
+ test_must_fail git check-attr --source &&
+ test_must_fail git check-attr --source not-a-valid-ref &&
echo "f" | test_must_fail git check-attr --stdin &&
echo "f" | test_must_fail git check-attr --stdin -- f &&
echo "f" | test_must_fail git check-attr --stdin test -- f &&
@@ -203,9 +221,12 @@ test_expect_success 'attribute test: read paths from stdin' '
test_cmp expect actual
'
-test_expect_success 'attribute test: --all option' '
+test_expect_success 'setup --all option' '
grep -v unspecified <expect-all | sort >specified-all &&
- sed -e "s/:.*//" <expect-all | uniq >stdin-all &&
+ sed -e "s/:.*//" <expect-all | uniq >stdin-all
+'
+
+test_expect_success 'attribute test: --all option' '
git check-attr --stdin --all <stdin-all >tmp &&
sort tmp >actual &&
test_cmp specified-all actual
@@ -284,6 +305,15 @@ test_expect_success 'using --git-dir and --work-tree' '
)
'
+test_expect_success 'using --source' '
+ attr_check_source foo/bar/f f tag-1 &&
+ attr_check_source foo/bar/a/i n tag-1 &&
+ attr_check_source foo/bar/f unspecified tag-2 &&
+ attr_check_source foo/bar/a/i m tag-2 &&
+ attr_check_source foo/bar/g g tag-2 &&
+ attr_check_source foo/bar/g unspecified tag-1
+'
+
test_expect_success 'setup bare' '
git clone --template= --bare . bare.git
'
@@ -303,6 +333,18 @@ test_expect_success 'bare repository: check that .gitattribute is ignored' '
)
'
+test_expect_success 'bare repository: with --source' '
+ (
+ cd bare.git &&
+ attr_check_source foo/bar/f f tag-1 &&
+ attr_check_source foo/bar/a/i n tag-1 &&
+ attr_check_source foo/bar/f unspecified tag-2 &&
+ attr_check_source foo/bar/a/i m tag-2 &&
+ attr_check_source foo/bar/g g tag-2 &&
+ attr_check_source foo/bar/g unspecified tag-1
+ )
+'
+
test_expect_success 'bare repository: check that --cached honors index' '
(
cd bare.git &&
@@ -376,4 +418,63 @@ test_expect_success SYMLINKS 'symlinks not respected in-tree' '
test_i18ngrep "unable to access.*gitattributes" err
'
+test_expect_success 'large attributes line ignored in tree' '
+ test_when_finished "rm .gitattributes" &&
+ printf "path %02043d" 1 >.gitattributes &&
+ git check-attr --all path >actual 2>err &&
+ echo "warning: ignoring overly long attributes line 1" >expect &&
+ test_cmp expect err &&
+ test_must_be_empty actual
+'
+
+test_expect_success 'large attributes line ignores trailing content in tree' '
+ test_when_finished "rm .gitattributes" &&
+ # older versions of Git broke lines at 2048 bytes; the 2045 bytes
+ # of 0-padding here is accounting for the three bytes of "a 1", which
+ # would knock "trailing" to the "next" line, where it would be
+ # erroneously parsed.
+ printf "a %02045dtrailing attribute\n" 1 >.gitattributes &&
+ git check-attr --all trailing >actual 2>err &&
+ echo "warning: ignoring overly long attributes line 1" >expect &&
+ test_cmp expect err &&
+ test_must_be_empty actual
+'
+
+test_expect_success EXPENSIVE 'large attributes file ignored in tree' '
+ test_when_finished "rm .gitattributes" &&
+ dd if=/dev/zero of=.gitattributes bs=101M count=1 2>/dev/null &&
+ git check-attr --all path >/dev/null 2>err &&
+ echo "warning: ignoring overly large gitattributes file ${SQ}.gitattributes${SQ}" >expect &&
+ test_cmp expect err
+'
+
+test_expect_success 'large attributes line ignored in index' '
+ test_when_finished "git update-index --remove .gitattributes" &&
+ blob=$(printf "path %02043d" 1 | git hash-object -w --stdin) &&
+ git update-index --add --cacheinfo 100644,$blob,.gitattributes &&
+ git check-attr --cached --all path >actual 2>err &&
+ echo "warning: ignoring overly long attributes line 1" >expect &&
+ test_cmp expect err &&
+ test_must_be_empty actual
+'
+
+test_expect_success 'large attributes line ignores trailing content in index' '
+ test_when_finished "git update-index --remove .gitattributes" &&
+ blob=$(printf "a %02045dtrailing attribute\n" 1 | git hash-object -w --stdin) &&
+ git update-index --add --cacheinfo 100644,$blob,.gitattributes &&
+ git check-attr --cached --all trailing >actual 2>err &&
+ echo "warning: ignoring overly long attributes line 1" >expect &&
+ test_cmp expect err &&
+ test_must_be_empty actual
+'
+
+test_expect_success EXPENSIVE 'large attributes file ignored in index' '
+ test_when_finished "git update-index --remove .gitattributes" &&
+ blob=$(dd if=/dev/zero bs=101M count=1 2>/dev/null | git hash-object -w --stdin) &&
+ git update-index --add --cacheinfo 100644,$blob,.gitattributes &&
+ git check-attr --cached --all path >/dev/null 2>err &&
+ echo "warning: ignoring overly large gitattributes blob ${SQ}.gitattributes${SQ}" >expect &&
+ test_cmp expect err
+'
+
test_done
diff --git a/t/t0006-date.sh b/t/t0006-date.sh
index 2490162071..e18b160286 100755
--- a/t/t0006-date.sh
+++ b/t/t0006-date.sh
@@ -88,6 +88,13 @@ check_parse 2008-02-14 bad
check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 +0000'
check_parse '2008-02-14 20:30:45 -0500' '2008-02-14 20:30:45 -0500'
check_parse '2008.02.14 20:30:45 -0500' '2008-02-14 20:30:45 -0500'
+check_parse '20080214T20:30:45' '2008-02-14 20:30:45 +0000'
+check_parse '20080214T20:30' '2008-02-14 20:30:00 +0000'
+check_parse '20080214T20' '2008-02-14 20:00:00 +0000'
+check_parse '20080214T203045' '2008-02-14 20:30:45 +0000'
+check_parse '20080214T2030' '2008-02-14 20:30:00 +0000'
+check_parse '20080214T000000.20' '2008-02-14 00:00:00 +0000'
+check_parse '20080214T00:00:00.20' '2008-02-14 00:00:00 +0000'
check_parse '20080214T203045-04:00' '2008-02-14 20:30:45 -0400'
check_parse '20080214T203045 -04:00' '2008-02-14 20:30:45 -0400'
check_parse '20080214T203045.019-04:00' '2008-02-14 20:30:45 -0400'
@@ -99,6 +106,7 @@ check_parse '2008-02-14 20:30:45 -05' '2008-02-14 20:30:45 -0500'
check_parse '2008-02-14 20:30:45 -:30' '2008-02-14 20:30:45 +0000'
check_parse '2008-02-14 20:30:45 -05:00' '2008-02-14 20:30:45 -0500'
check_parse '2008-02-14 20:30:45' '2008-02-14 20:30:45 -0500' EST5
+check_parse 'Thu, 7 Apr 2005 15:14:13 -0700' '2005-04-07 15:14:13 -0700'
check_approxidate() {
echo "$1 -> $2 +0000" >expect
diff --git a/t/t0007-git-var.sh b/t/t0007-git-var.sh
index e56f4b9ac5..eeb8539c1b 100755
--- a/t/t0007-git-var.sh
+++ b/t/t0007-git-var.sh
@@ -5,6 +5,12 @@ test_description='basic sanity checks for git var'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
+sane_unset_all_editors () {
+ sane_unset GIT_EDITOR &&
+ sane_unset VISUAL &&
+ sane_unset EDITOR
+}
+
test_expect_success 'get GIT_AUTHOR_IDENT' '
test_tick &&
echo "$GIT_AUTHOR_NAME <$GIT_AUTHOR_EMAIL> $GIT_AUTHOR_DATE" >expect &&
@@ -47,6 +53,100 @@ test_expect_success 'get GIT_DEFAULT_BRANCH with configuration' '
)
'
+test_expect_success 'get GIT_EDITOR without configuration' '
+ (
+ sane_unset_all_editors &&
+ test_expect_code 1 git var GIT_EDITOR >out &&
+ test_must_be_empty out
+ )
+'
+
+test_expect_success 'get GIT_EDITOR with configuration' '
+ test_config core.editor foo &&
+ (
+ sane_unset_all_editors &&
+ echo foo >expect &&
+ git var GIT_EDITOR >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'get GIT_EDITOR with environment variable GIT_EDITOR' '
+ (
+ sane_unset_all_editors &&
+ echo bar >expect &&
+ GIT_EDITOR=bar git var GIT_EDITOR >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'get GIT_EDITOR with environment variable EDITOR' '
+ (
+ sane_unset_all_editors &&
+ echo bar >expect &&
+ EDITOR=bar git var GIT_EDITOR >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'get GIT_EDITOR with configuration and environment variable GIT_EDITOR' '
+ test_config core.editor foo &&
+ (
+ sane_unset_all_editors &&
+ echo bar >expect &&
+ GIT_EDITOR=bar git var GIT_EDITOR >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'get GIT_EDITOR with configuration and environment variable EDITOR' '
+ test_config core.editor foo &&
+ (
+ sane_unset_all_editors &&
+ echo foo >expect &&
+ EDITOR=bar git var GIT_EDITOR >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'get GIT_SEQUENCE_EDITOR without configuration' '
+ (
+ sane_unset GIT_SEQUENCE_EDITOR &&
+ git var GIT_EDITOR >expect &&
+ git var GIT_SEQUENCE_EDITOR >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'get GIT_SEQUENCE_EDITOR with configuration' '
+ test_config sequence.editor foo &&
+ (
+ sane_unset GIT_SEQUENCE_EDITOR &&
+ echo foo >expect &&
+ git var GIT_SEQUENCE_EDITOR >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'get GIT_SEQUENCE_EDITOR with environment variable' '
+ (
+ sane_unset GIT_SEQUENCE_EDITOR &&
+ echo bar >expect &&
+ GIT_SEQUENCE_EDITOR=bar git var GIT_SEQUENCE_EDITOR >actual &&
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'get GIT_SEQUENCE_EDITOR with configuration and environment variable' '
+ test_config sequence.editor foo &&
+ (
+ sane_unset GIT_SEQUENCE_EDITOR &&
+ echo bar >expect &&
+ GIT_SEQUENCE_EDITOR=bar git var GIT_SEQUENCE_EDITOR >actual &&
+ test_cmp expect actual
+ )
+'
+
# For git var -l, we check only a representative variable;
# testing the whole output would make our test too brittle with
# respect to unrelated changes in the test suite's environment.
diff --git a/t/t0017-env-helper.sh b/t/t0017-env-helper.sh
index 2e42fba956..fc14ba091c 100755
--- a/t/t0017-env-helper.sh
+++ b/t/t0017-env-helper.sh
@@ -1,87 +1,87 @@
#!/bin/sh
-test_description='test env--helper'
+test_description='test test-tool env-helper'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
-test_expect_success 'env--helper usage' '
- test_must_fail git env--helper &&
- test_must_fail git env--helper --type=bool &&
- test_must_fail git env--helper --type=ulong &&
- test_must_fail git env--helper --type=bool &&
- test_must_fail git env--helper --type=bool --default &&
- test_must_fail git env--helper --type=bool --default= &&
- test_must_fail git env--helper --defaultxyz
+test_expect_success 'test-tool env-helper usage' '
+ test_must_fail test-tool env-helper &&
+ test_must_fail test-tool env-helper --type=bool &&
+ test_must_fail test-tool env-helper --type=ulong &&
+ test_must_fail test-tool env-helper --type=bool &&
+ test_must_fail test-tool env-helper --type=bool --default &&
+ test_must_fail test-tool env-helper --type=bool --default= &&
+ test_must_fail test-tool env-helper --defaultxyz
'
-test_expect_success 'env--helper bad default values' '
- test_must_fail git env--helper --type=bool --default=1xyz MISSING &&
- test_must_fail git env--helper --type=ulong --default=1xyz MISSING
+test_expect_success 'test-tool env-helper bad default values' '
+ test_must_fail test-tool env-helper --type=bool --default=1xyz MISSING &&
+ test_must_fail test-tool env-helper --type=ulong --default=1xyz MISSING
'
-test_expect_success 'env--helper --type=bool' '
+test_expect_success 'test-tool env-helper --type=bool' '
# Test various --default bool values
echo true >expected &&
- git env--helper --type=bool --default=1 MISSING >actual &&
+ test-tool env-helper --type=bool --default=1 MISSING >actual &&
test_cmp expected actual &&
- git env--helper --type=bool --default=yes MISSING >actual &&
+ test-tool env-helper --type=bool --default=yes MISSING >actual &&
test_cmp expected actual &&
- git env--helper --type=bool --default=true MISSING >actual &&
+ test-tool env-helper --type=bool --default=true MISSING >actual &&
test_cmp expected actual &&
echo false >expected &&
- test_must_fail git env--helper --type=bool --default=0 MISSING >actual &&
+ test_must_fail test-tool env-helper --type=bool --default=0 MISSING >actual &&
test_cmp expected actual &&
- test_must_fail git env--helper --type=bool --default=no MISSING >actual &&
+ test_must_fail test-tool env-helper --type=bool --default=no MISSING >actual &&
test_cmp expected actual &&
- test_must_fail git env--helper --type=bool --default=false MISSING >actual &&
+ test_must_fail test-tool env-helper --type=bool --default=false MISSING >actual &&
test_cmp expected actual &&
# No output with --exit-code
- git env--helper --type=bool --default=true --exit-code MISSING >actual.out 2>actual.err &&
+ test-tool env-helper --type=bool --default=true --exit-code MISSING >actual.out 2>actual.err &&
test_must_be_empty actual.out &&
test_must_be_empty actual.err &&
- test_must_fail git env--helper --type=bool --default=false --exit-code MISSING >actual.out 2>actual.err &&
+ test_must_fail test-tool env-helper --type=bool --default=false --exit-code MISSING >actual.out 2>actual.err &&
test_must_be_empty actual.out &&
test_must_be_empty actual.err &&
# Existing variable
- EXISTS=true git env--helper --type=bool --default=false --exit-code EXISTS >actual.out 2>actual.err &&
+ EXISTS=true test-tool env-helper --type=bool --default=false --exit-code EXISTS >actual.out 2>actual.err &&
test_must_be_empty actual.out &&
test_must_be_empty actual.err &&
test_must_fail \
env EXISTS=false \
- git env--helper --type=bool --default=true --exit-code EXISTS >actual.out 2>actual.err &&
+ test-tool env-helper --type=bool --default=true --exit-code EXISTS >actual.out 2>actual.err &&
test_must_be_empty actual.out &&
test_must_be_empty actual.err
'
-test_expect_success 'env--helper --type=ulong' '
+test_expect_success 'test-tool env-helper --type=ulong' '
echo 1234567890 >expected &&
- git env--helper --type=ulong --default=1234567890 MISSING >actual.out 2>actual.err &&
+ test-tool env-helper --type=ulong --default=1234567890 MISSING >actual.out 2>actual.err &&
test_cmp expected actual.out &&
test_must_be_empty actual.err &&
echo 0 >expected &&
- test_must_fail git env--helper --type=ulong --default=0 MISSING >actual &&
+ test_must_fail test-tool env-helper --type=ulong --default=0 MISSING >actual &&
test_cmp expected actual &&
- git env--helper --type=ulong --default=1234567890 --exit-code MISSING >actual.out 2>actual.err &&
+ test-tool env-helper --type=ulong --default=1234567890 --exit-code MISSING >actual.out 2>actual.err &&
test_must_be_empty actual.out &&
test_must_be_empty actual.err &&
- EXISTS=1234567890 git env--helper --type=ulong --default=0 EXISTS --exit-code >actual.out 2>actual.err &&
+ EXISTS=1234567890 test-tool env-helper --type=ulong --default=0 EXISTS --exit-code >actual.out 2>actual.err &&
test_must_be_empty actual.out &&
test_must_be_empty actual.err &&
echo 1234567890 >expected &&
- EXISTS=1234567890 git env--helper --type=ulong --default=0 EXISTS >actual.out 2>actual.err &&
+ EXISTS=1234567890 test-tool env-helper --type=ulong --default=0 EXISTS >actual.out 2>actual.err &&
test_cmp expected actual.out &&
test_must_be_empty actual.err
'
-test_expect_success 'env--helper reads config thanks to trace2' '
+test_expect_success 'test-tool env-helper reads config thanks to trace2' '
mkdir home &&
git config -f home/.gitconfig include.path cycle &&
git config -f home/cycle include.path .gitconfig &&
@@ -93,7 +93,7 @@ test_expect_success 'env--helper reads config thanks to trace2' '
test_must_fail \
env HOME="$(pwd)/home" GIT_TEST_ENV_HELPER=true \
- git -C cycle env--helper --type=bool --default=0 --exit-code GIT_TEST_ENV_HELPER 2>err &&
+ test-tool -C cycle env-helper --type=bool --default=0 --exit-code GIT_TEST_ENV_HELPER 2>err &&
grep "exceeded maximum include depth" err
'
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index abecd75e4e..46abbeed68 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -8,8 +8,8 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-terminal.sh
-TEST_ROOT="$PWD"
-PATH=$TEST_ROOT:$PATH
+PATH=$PWD:$PATH
+TEST_ROOT="$(pwd)"
write_script <<\EOF "$TEST_ROOT/rot13.sh"
tr \
diff --git a/t/t0068-for-each-repo.sh b/t/t0068-for-each-repo.sh
index c6e0d65563..3648d439a8 100755
--- a/t/t0068-for-each-repo.sh
+++ b/t/t0068-for-each-repo.sh
@@ -2,6 +2,7 @@
test_description='git for-each-repo builtin'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'run based on configured value' '
diff --git a/t/t0070-fundamental.sh b/t/t0070-fundamental.sh
index 8d59905ef0..574de34198 100755
--- a/t/t0070-fundamental.sh
+++ b/t/t0070-fundamental.sh
@@ -6,6 +6,7 @@ test_description='check that the most basic functions work
Verify wrappers and compatibility functions.
'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'character classes (isspace, isalpha etc.)' '
diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh
index 516a6112fd..3fb1b0c162 100755
--- a/t/t1001-read-tree-m-2way.sh
+++ b/t/t1001-read-tree-m-2way.sh
@@ -370,7 +370,7 @@ test_expect_success 'read-tree supports the super-prefix' '
cat <<-EOF >expect &&
error: Updating '\''fictional/a'\'' would lose untracked files in it
EOF
- test_must_fail git --super-prefix fictional/ read-tree -u -m "$treeH" "$treeM" 2>actual &&
+ test_must_fail git read-tree --super-prefix fictional/ -u -m "$treeH" "$treeM" 2>actual &&
test_cmp expect actual
'
diff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh
index 742f0fa909..595b24c0ad 100755
--- a/t/t1011-read-tree-sparse-checkout.sh
+++ b/t/t1011-read-tree-sparse-checkout.sh
@@ -12,6 +12,7 @@ test_description='sparse checkout tests
'
TEST_CREATE_REPO_NO_TEMPLATE=1
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-read-tree.sh
diff --git a/t/t1022-read-tree-partial-clone.sh b/t/t1022-read-tree-partial-clone.sh
index da53971635..cca4380e43 100755
--- a/t/t1022-read-tree-partial-clone.sh
+++ b/t/t1022-read-tree-partial-clone.sh
@@ -3,7 +3,7 @@
test_description='git read-tree in partial clones'
TEST_NO_CREATE_REPO=1
-
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'read-tree in partial clone prefetches in one batch' '
diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh
index b563d6c263..627267be15 100755
--- a/t/t1091-sparse-checkout-builtin.sh
+++ b/t/t1091-sparse-checkout-builtin.sh
@@ -238,7 +238,7 @@ test_expect_success 'cone mode: match patterns' '
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 @@ test_expect_success 'pattern-checks: starting "*"' '
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 --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh
index 93a2f91f8a..58d6da7feb 100755
--- a/t/t1301-shared-repo.sh
+++ b/t/t1301-shared-repo.sh
@@ -8,6 +8,7 @@ test_description='Test shared repository initialization'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_CREATE_REPO_NO_TEMPLATE=1
. ./test-lib.sh
# Remove a default ACL from the test dir if possible.
@@ -25,6 +26,7 @@ test_expect_success 'shared = 0400 (faulty permission u-w)' '
for u in 002 022
do
test_expect_success POSIXPERM "shared=1 does not clear bits preset by umask $u" '
+ test_when_finished "rm -rf sub" &&
mkdir sub && (
cd sub &&
umask $u &&
@@ -42,12 +44,9 @@ do
;;
esac
'
- rm -rf sub
done
test_expect_success 'shared=all' '
- mkdir sub &&
- cd sub &&
git init --template= --shared=all &&
test 2 = $(git config core.sharedrepository)
'
@@ -132,6 +131,7 @@ test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' '
'
test_expect_success POSIXPERM 'forced modes' '
+ test_when_finished "rm -rf new" &&
mkdir -p templates/hooks &&
echo update-server-info >templates/hooks/post-update &&
chmod +x templates/hooks/post-update &&
@@ -140,7 +140,8 @@ test_expect_success POSIXPERM 'forced modes' '
(
cd new &&
umask 002 &&
- git init --shared=0660 --template=templates &&
+ git init --shared=0660 --template=../templates &&
+ test_path_is_file .git/hooks/post-update &&
>frotz &&
git add frotz &&
git commit -a -m initial &&
@@ -173,6 +174,7 @@ test_expect_success POSIXPERM 'forced modes' '
'
test_expect_success POSIXPERM 'remote init does not use config from cwd' '
+ test_when_finished "rm -rf child.git" &&
git config core.sharedrepository 0666 &&
umask 0022 &&
git init --bare child.git &&
@@ -192,7 +194,7 @@ test_expect_success POSIXPERM 're-init respects core.sharedrepository (local)' '
'
test_expect_success POSIXPERM 're-init respects core.sharedrepository (remote)' '
- rm -rf child.git &&
+ test_when_finished "rm -rf child.git" &&
umask 0022 &&
git init --bare --shared=0666 child.git &&
test_path_is_missing child.git/foo &&
@@ -203,7 +205,7 @@ test_expect_success POSIXPERM 're-init respects core.sharedrepository (remote)'
'
test_expect_success POSIXPERM 'template can set core.sharedrepository' '
- rm -rf child.git &&
+ test_when_finished "rm -rf child.git" &&
umask 0022 &&
git config core.sharedrepository 0666 &&
cp .git/config templates/config &&
diff --git a/t/t1302-repo-version.sh b/t/t1302-repo-version.sh
index 0acabb6d11..7cf80bf66a 100755
--- a/t/t1302-repo-version.sh
+++ b/t/t1302-repo-version.sh
@@ -27,7 +27,7 @@ test_expect_success 'setup' '
'
test_expect_success 'gitdir selection on normal repos' '
- echo $(test_oid version) >expect &&
+ test_oid version >expect &&
git config core.repositoryformatversion >actual &&
git -C test config core.repositoryformatversion >actual2 &&
test_cmp expect actual &&
diff --git a/t/t1404-update-ref-errors.sh b/t/t1404-update-ref-errors.sh
index 13c2b43bba..b5606d93b5 100755
--- a/t/t1404-update-ref-errors.sh
+++ b/t/t1404-update-ref-errors.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='Test git update-ref error handling'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Create some references, perhaps run pack-refs --all, then try to
diff --git a/t/t1409-avoid-packing-refs.sh b/t/t1409-avoid-packing-refs.sh
index be12fb6350..f23c0152a8 100755
--- a/t/t1409-avoid-packing-refs.sh
+++ b/t/t1409-avoid-packing-refs.sh
@@ -2,6 +2,7 @@
test_description='avoid rewriting packed-refs unnecessarily'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Add an identifying mark to the packed-refs file header line. This
diff --git a/t/t1413-reflog-detach.sh b/t/t1413-reflog-detach.sh
index 934688a1ee..d2a4822d46 100755
--- a/t/t1413-reflog-detach.sh
+++ b/t/t1413-reflog-detach.sh
@@ -4,6 +4,7 @@ test_description='Test reflog interaction with detached HEAD'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
reset_state () {
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index ace4556788..de0f6d5e7f 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -999,4 +999,28 @@ test_expect_success 'fsck error and recovery on invalid object type' '
)
'
+test_expect_success 'fsck error on gitattributes with excessive line lengths' '
+ blob=$(printf "pattern %02048d" 1 | git hash-object -w --stdin) &&
+ test_when_finished "remove_object $blob" &&
+ tree=$(printf "100644 blob %s\t%s\n" $blob .gitattributes | git mktree) &&
+ test_when_finished "remove_object $tree" &&
+ cat >expected <<-EOF &&
+ error in blob $blob: gitattributesLineLength: .gitattributes has too long lines to parse
+ EOF
+ test_must_fail git fsck --no-dangling >actual 2>&1 &&
+ test_cmp expected actual
+'
+
+test_expect_success 'fsck error on gitattributes with excessive size' '
+ blob=$(test-tool genzeros $((100 * 1024 * 1024 + 1)) | git hash-object -w --stdin) &&
+ test_when_finished "remove_object $blob" &&
+ tree=$(printf "100644 blob %s\t%s\n" $blob .gitattributes | git mktree) &&
+ test_when_finished "remove_object $tree" &&
+ cat >expected <<-EOF &&
+ error in blob $blob: gitattributesLarge: .gitattributes too large to parse
+ EOF
+ test_must_fail git fsck --no-dangling >actual 2>&1 &&
+ test_cmp expected actual
+'
+
test_done
diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh
index 81de584ea2..37ee5091b5 100755
--- a/t/t1500-rev-parse.sh
+++ b/t/t1500-rev-parse.sh
@@ -195,7 +195,7 @@ test_expect_success 'rev-parse --is-shallow-repository in non-shallow repo' '
'
test_expect_success 'rev-parse --show-object-format in repo' '
- echo "$(test_oid algo)" >expect &&
+ test_oid algo >expect &&
git rev-parse --show-object-format >actual &&
test_cmp expect actual &&
git rev-parse --show-object-format=storage >actual &&
diff --git a/t/t1501-work-tree.sh b/t/t1501-work-tree.sh
index b75558040f..ae6528aece 100755
--- a/t/t1501-work-tree.sh
+++ b/t/t1501-work-tree.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='test separate work tree'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t1509-root-work-tree.sh b/t/t1509-root-work-tree.sh
index 553a3f601b..c799f5b6ac 100755
--- a/t/t1509-root-work-tree.sh
+++ b/t/t1509-root-work-tree.sh
@@ -221,7 +221,8 @@ test_expect_success 'setup' '
rm -rf /.git &&
echo "Initialized empty Git repository in /.git/" > expected &&
git init > result &&
- test_cmp expected result
+ test_cmp expected result &&
+ git config --global --add safe.directory /
'
test_vars 'auto gitdir, root' ".git" "/" ""
@@ -242,7 +243,7 @@ say "auto bare gitdir"
# DESTROYYYYY!!!!!
test_expect_success 'setup' '
rm -rf /refs /objects /info /hooks &&
- rm -f /expected /ls.expected /me /result &&
+ rm -f /HEAD /expected /ls.expected /me /result &&
cd / &&
echo "Initialized empty Git repository in /" > expected &&
git init --bare > result &&
@@ -255,4 +256,9 @@ test_expect_success 'go to /foo' 'cd /foo'
test_vars 'auto gitdir, root' "/" "" ""
+test_expect_success 'cleanup root' '
+ rm -rf /.git /refs /objects /info /hooks /branches /foo &&
+ rm -f /HEAD /config /description /expected /ls.expected /me /result
+'
+
test_done
diff --git a/t/t1600-index.sh b/t/t1600-index.sh
index 010989f90e..0ebbae1305 100755
--- a/t/t1600-index.sh
+++ b/t/t1600-index.sh
@@ -65,6 +65,36 @@ test_expect_success 'out of bounds index.version issues warning' '
)
'
+test_expect_success 'index.skipHash config option' '
+ rm -f .git/index &&
+ git -c index.skipHash=true add a &&
+ test_trailing_hash .git/index >hash &&
+ echo $(test_oid zero) >expect &&
+ test_cmp expect hash &&
+ git fsck &&
+
+ rm -f .git/index &&
+ git -c feature.manyFiles=true add a &&
+ test_trailing_hash .git/index >hash &&
+ cmp expect hash &&
+
+ rm -f .git/index &&
+ git -c feature.manyFiles=true \
+ -c index.skipHash=false add a &&
+ test_trailing_hash .git/index >hash &&
+ ! cmp expect hash &&
+
+ test_commit start &&
+ git -c protocol.file.allow=always submodule add ./ sub &&
+ git config index.skipHash false &&
+ git -C sub config index.skipHash true &&
+ >sub/file &&
+ git -C sub add a &&
+ test_trailing_hash .git/modules/sub/index >hash &&
+ test_cmp expect hash &&
+ git -C sub fsck
+'
+
test_index_version () {
INDEX_VERSION_CONFIG=$1 &&
FEATURE_MANY_FILES=$2 &&
diff --git a/t/t2012-checkout-last.sh b/t/t2012-checkout-last.sh
index 1f6c4ed042..4b6372f4c3 100755
--- a/t/t2012-checkout-last.sh
+++ b/t/t2012-checkout-last.sh
@@ -5,6 +5,7 @@ test_description='checkout can switch to last branch and merge base'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t2018-checkout-branch.sh b/t/t2018-checkout-branch.sh
index 771c3c3c50..8581ad3437 100755
--- a/t/t2018-checkout-branch.sh
+++ b/t/t2018-checkout-branch.sh
@@ -3,6 +3,7 @@
test_description='checkout'
TEST_CREATE_REPO_NO_TEMPLATE=1
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Arguments: [!] <branch> <oid> [<checkout options>]
diff --git a/t/t2025-checkout-no-overlay.sh b/t/t2025-checkout-no-overlay.sh
index 8f13341cf8..3832c3de81 100755
--- a/t/t2025-checkout-no-overlay.sh
+++ b/t/t2025-checkout-no-overlay.sh
@@ -2,6 +2,7 @@
test_description='checkout --no-overlay <tree-ish> -- <pathspec>'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t3009-ls-files-others-nonsubmodule.sh b/t/t3009-ls-files-others-nonsubmodule.sh
index 963f3462b7..14218b3424 100755
--- a/t/t3009-ls-files-others-nonsubmodule.sh
+++ b/t/t3009-ls-files-others-nonsubmodule.sh
@@ -18,6 +18,7 @@ This test runs git ls-files --others with the following working tree:
git repository with a commit and an untracked file
'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup: directories' '
diff --git a/t/t3010-ls-files-killed-modified.sh b/t/t3010-ls-files-killed-modified.sh
index 580e158f99..054178703d 100755
--- a/t/t3010-ls-files-killed-modified.sh
+++ b/t/t3010-ls-files-killed-modified.sh
@@ -41,6 +41,8 @@ Also for modification test, the cache and working tree have:
We should report path0, path1, path2/file2, path3/file3, path7 and path8
modified without reporting path9 and path10. submod1 is also modified.
'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'git update-index --add to add various paths.' '
diff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh
index f1f09abdd9..3884694165 100755
--- a/t/t3050-subprojects-fetch.sh
+++ b/t/t3050-subprojects-fetch.sh
@@ -2,6 +2,7 @@
test_description='fetching and pushing project with subproject'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t3060-ls-files-with-tree.sh b/t/t3060-ls-files-with-tree.sh
index 52f76f7b57..c4a72ae446 100755
--- a/t/t3060-ls-files-with-tree.sh
+++ b/t/t3060-ls-files-with-tree.sh
@@ -8,6 +8,8 @@ test_description='git ls-files test (--with-tree).
This test runs git ls-files --with-tree and in particular in
a scenario known to trigger a crash with some versions of git.
'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t3104-ls-tree-format.sh b/t/t3104-ls-tree-format.sh
index 383896667b..3adb206a93 100755
--- a/t/t3104-ls-tree-format.sh
+++ b/t/t3104-ls-tree-format.sh
@@ -20,7 +20,6 @@ test_ls_tree_format () {
format=$1 &&
opts=$2 &&
fmtopts=$3 &&
- shift 2 &&
test_expect_success "ls-tree '--format=<$format>' is like options '$opts $fmtopts'" '
git ls-tree $opts -r HEAD >expect &&
@@ -36,6 +35,12 @@ test_ls_tree_format () {
'
}
+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 --git a/t/t3204-branch-name-interpretation.sh b/t/t3204-branch-name-interpretation.sh
index 793bf4d269..3399344f25 100755
--- a/t/t3204-branch-name-interpretation.sh
+++ b/t/t3204-branch-name-interpretation.sh
@@ -57,6 +57,16 @@ test_expect_success 'create branch with pseudo-qualified name' '
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 --git a/t/t3409-rebase-environ.sh b/t/t3409-rebase-environ.sh
index 83ffb39d9f..acaf5558db 100755
--- a/t/t3409-rebase-environ.sh
+++ b/t/t3409-rebase-environ.sh
@@ -2,6 +2,7 @@
test_description='git rebase interactive environment'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t3413-rebase-hook.sh b/t/t3413-rebase-hook.sh
index 9fab0d779b..e8456831e8 100755
--- a/t/t3413-rebase-hook.sh
+++ b/t/t3413-rebase-hook.sh
@@ -5,6 +5,7 @@ test_description='git rebase with its hook(s)'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t3428-rebase-signoff.sh b/t/t3428-rebase-signoff.sh
index f6993b7e14..e1b1e94764 100755
--- a/t/t3428-rebase-signoff.sh
+++ b/t/t3428-rebase-signoff.sh
@@ -5,6 +5,7 @@ test_description='git rebase --signoff
This test runs git rebase --signoff and make sure that it works.
'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# A simple file to commit
diff --git a/t/t3429-rebase-edit-todo.sh b/t/t3429-rebase-edit-todo.sh
index abd66f3602..8e0d03969a 100755
--- a/t/t3429-rebase-edit-todo.sh
+++ b/t/t3429-rebase-edit-todo.sh
@@ -2,6 +2,7 @@
test_description='rebase should reread the todo file if an exec modifies it'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-rebase.sh
diff --git a/t/t3433-rebase-across-mode-change.sh b/t/t3433-rebase-across-mode-change.sh
index 05df964670..c8172b0852 100755
--- a/t/t3433-rebase-across-mode-change.sh
+++ b/t/t3433-rebase-across-mode-change.sh
@@ -2,6 +2,7 @@
test_description='git rebase across mode change'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t3920-crlf-messages.sh b/t/t3920-crlf-messages.sh
index 4c661d4d54..67fd2345af 100755
--- a/t/t3920-crlf-messages.sh
+++ b/t/t3920-crlf-messages.sh
@@ -12,7 +12,7 @@ create_crlf_ref () {
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 --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index de1da4673d..012f155e10 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -2281,7 +2281,7 @@ test_expect_success 'format-patch --attach cover-letter only is non-multipart' '
test_line_count = 1 output
'
-test_expect_success 'format-patch --pretty=mboxrd' '
+test_expect_success '-c format.mboxrd format-patch' '
sp=" " &&
cat >msg <<-INPUT_END &&
mboxrd should escape the body
@@ -2316,7 +2316,9 @@ test_expect_success 'format-patch --pretty=mboxrd' '
INPUT_END
C=$(git commit-tree HEAD^^{tree} -p HEAD <msg) &&
- git format-patch --pretty=mboxrd --stdout -1 $C~1..$C >patch &&
+ git -c format.mboxrd format-patch --stdout -1 $C~1..$C >patch &&
+ git format-patch --pretty=mboxrd --stdout -1 $C~1..$C >compat &&
+ test_cmp patch compat &&
git grep -h --no-index -A11 \
"^>From could trip up a loose mbox parser" patch >actual &&
test_cmp expect actual
diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh
index f3e20dd5bb..b298f220e0 100755
--- a/t/t4015-diff-whitespace.sh
+++ b/t/t4015-diff-whitespace.sh
@@ -1638,7 +1638,7 @@ test_expect_success 'no effect on diff from --color-moved with --word-diff' '
test_cmp expect actual
'
-test_expect_success !SANITIZE_LEAK 'no effect on show from --color-moved with --word-diff' '
+test_expect_success 'no effect on show from --color-moved with --word-diff' '
git show --color-moved --word-diff >actual &&
git show --word-diff >expect &&
test_cmp expect actual
@@ -2024,7 +2024,7 @@ test_expect_success '--color-moved rewinds for MIN_ALNUM_COUNT' '
test_cmp expected actual
'
-test_expect_success !SANITIZE_LEAK 'move detection with submodules' '
+test_expect_success 'move detection with submodules' '
test_create_repo bananas &&
echo ripe >bananas/recipe &&
git -C bananas add recipe &&
diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh
index 7cb9909293..787605ce3f 100755
--- a/t/t4023-diff-rename-typechange.sh
+++ b/t/t4023-diff-rename-typechange.sh
@@ -52,8 +52,8 @@ test_expect_success setup '
'
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 regular files' '
'
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 'cross renames to be detected for typechange' '
'
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 --git a/t/t4044-diff-index-unique-abbrev.sh b/t/t4044-diff-index-unique-abbrev.sh
index 29e49d2290..9f6043daba 100755
--- a/t/t4044-diff-index-unique-abbrev.sh
+++ b/t/t4044-diff-index-unique-abbrev.sh
@@ -34,12 +34,12 @@ test_expect_success 'setup' '
100644 blob $(test_oid hash2) foo
EOF
- echo "$(test_oid val1)" > foo &&
+ test_oid val1 > foo &&
git add foo &&
git commit -m "initial" &&
git cat-file -p HEAD: > actual &&
test_cmp expect_initial actual &&
- echo "$(test_oid val2)" > foo &&
+ test_oid val2 > foo &&
git commit -a -m "update" &&
git cat-file -p HEAD: > actual &&
test_cmp expect_update actual
diff --git a/t/t4045-diff-relative.sh b/t/t4045-diff-relative.sh
index fab351b48a..9b46c4c1be 100755
--- a/t/t4045-diff-relative.sh
+++ b/t/t4045-diff-relative.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='diff --relative tests'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -162,6 +164,35 @@ check_diff_relative_option subdir file2 true --no-relative --relative
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 --git a/t/t4046-diff-unmerged.sh b/t/t4046-diff-unmerged.sh
index 0ae0cd3a52..ffaf69335f 100755
--- a/t/t4046-diff-unmerged.sh
+++ b/t/t4046-diff-unmerged.sh
@@ -86,4 +86,14 @@ test_expect_success 'diff-files -3' '
test_cmp diff-files-3.expect diff-files-3.actual
'
+test_expect_success 'diff --stat' '
+ for path in $paths
+ do
+ echo " $path | Unmerged" || return 1
+ done >diff-stat.expect &&
+ echo " 0 files changed" >>diff-stat.expect &&
+ git diff --cached --stat >diff-stat.actual &&
+ test_cmp diff-stat.expect diff-stat.actual
+'
+
test_done
diff --git a/t/t4052-stat-output.sh b/t/t4052-stat-output.sh
index b5c281edaa..3ee27e277d 100755
--- a/t/t4052-stat-output.sh
+++ b/t/t4052-stat-output.sh
@@ -8,6 +8,7 @@ test_description='test --stat output of various commands'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-terminal.sh
diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh
index 3feadf0e35..4e9fa0403d 100755
--- a/t/t4053-diff-no-index.sh
+++ b/t/t4053-diff-no-index.sh
@@ -2,6 +2,7 @@
test_description='diff --no-index'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t4067-diff-partial-clone.sh b/t/t4067-diff-partial-clone.sh
index 28f42a4046..f60f5cbd65 100755
--- a/t/t4067-diff-partial-clone.sh
+++ b/t/t4067-diff-partial-clone.sh
@@ -2,6 +2,7 @@
test_description='behavior of diff when reading objects in a partial clone'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'git show batches blobs' '
diff --git a/t/t4111-apply-subdir.sh b/t/t4111-apply-subdir.sh
index 1618a6dbc7..e9a87d761d 100755
--- a/t/t4111-apply-subdir.sh
+++ b/t/t4111-apply-subdir.sh
@@ -2,6 +2,7 @@
test_description='patching from inconvenient places'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t4135-apply-weird-filenames.sh b/t/t4135-apply-weird-filenames.sh
index 6bc3fb97a7..d3502c6fdd 100755
--- a/t/t4135-apply-weird-filenames.sh
+++ b/t/t4135-apply-weird-filenames.sh
@@ -2,6 +2,7 @@
test_description='git apply with weird postimage filenames'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t4150-am.sh b/t/t4150-am.sh
index cdad4b6880..78cf1c880e 100755
--- a/t/t4150-am.sh
+++ b/t/t4150-am.sh
@@ -345,6 +345,21 @@ test_expect_success 'am with failing applypatch-msg hook' '
test_cmp_rev first HEAD
'
+test_expect_success 'am with failing applypatch-msg hook (no verify)' '
+ rm -fr .git/rebase-apply &&
+ git reset --hard &&
+ git checkout first &&
+ test_hook applypatch-msg <<-\EOF &&
+ echo hook-message >"$1"
+ exit 1
+ EOF
+ git am --no-verify patch1 &&
+ test_path_is_missing .git/rebase-apply &&
+ git diff --exit-code second &&
+ git log -1 --format=format:%B >actual &&
+ test_cmp msg actual
+'
+
test_expect_success 'am with pre-applypatch hook' '
rm -fr .git/rebase-apply &&
git reset --hard &&
@@ -374,6 +389,23 @@ test_expect_success 'am with failing pre-applypatch hook' '
test_cmp_rev first HEAD
'
+test_expect_success 'am with failing pre-applypatch hook (no verify)' '
+ rm -fr .git/rebase-apply &&
+ git reset --hard &&
+ git checkout first &&
+ touch empty-file &&
+ test_hook pre-applypatch <<-\EOF &&
+ rm empty-file
+ exit 1
+ EOF
+ git am --no-verify patch1 &&
+ test_path_is_missing .git/rebase-apply &&
+ test_path_is_file empty-file &&
+ git diff --exit-code second &&
+ git log -1 --format=format:%B >actual &&
+ test_cmp msg actual
+'
+
test_expect_success 'am with post-applypatch hook' '
rm -fr .git/rebase-apply &&
git reset --hard &&
@@ -1033,7 +1065,7 @@ test_expect_success 'am --patch-format=mboxrd handles mboxrd' '
>From extra escape for reversibility
INPUT_END
git commit -F msg &&
- git format-patch --pretty=mboxrd --stdout -1 >mboxrd1 &&
+ git -c format.mboxrd format-patch --stdout -1 >mboxrd1 &&
grep "^>From could trip up a loose mbox parser" mboxrd1 &&
git checkout -f first &&
git am --patch-format=mboxrd mboxrd1 &&
diff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh
index cd1cab3e54..fa7f987284 100755
--- a/t/t4203-mailmap.sh
+++ b/t/t4203-mailmap.sh
@@ -1022,4 +1022,69 @@ test_expect_success '--mailmap enables mailmap in cat-file for annotated tag obj
test_cmp expect actual
'
+test_expect_success 'git cat-file -s returns correct size with --use-mailmap' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ git cat-file commit HEAD >commit.out &&
+ echo $(wc -c <commit.out) >expect &&
+ git cat-file --use-mailmap commit HEAD >commit.out &&
+ echo $(wc -c <commit.out) >>expect &&
+ git cat-file -s HEAD >actual &&
+ git cat-file --use-mailmap -s HEAD >>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file -s returns correct size with --use-mailmap for tag objects' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ Orig <orig@example.com> C O Mitter <committer@example.com>
+ EOF
+ git tag -a -m "annotated tag" v3 &&
+ git cat-file tag v3 >tag.out &&
+ echo $(wc -c <tag.out) >expect &&
+ git cat-file --use-mailmap tag v3 >tag.out &&
+ echo $(wc -c <tag.out) >>expect &&
+ git cat-file -s v3 >actual &&
+ git cat-file --use-mailmap -s v3 >>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-check returns correct size with --use-mailmap' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ git cat-file commit HEAD >commit.out &&
+ commit_size=$(wc -c <commit.out) &&
+ commit_sha=$(git rev-parse HEAD) &&
+ echo $commit_sha commit $commit_size >expect &&
+ git cat-file --use-mailmap commit HEAD >commit.out &&
+ commit_size=$(wc -c <commit.out) &&
+ echo $commit_sha commit $commit_size >>expect &&
+ echo "HEAD" >in &&
+ git cat-file --batch-check <in >actual &&
+ git cat-file --use-mailmap --batch-check <in >>actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'git cat-file --batch-command returns correct size with --use-mailmap' '
+ test_when_finished "rm .mailmap" &&
+ cat >.mailmap <<-\EOF &&
+ C O Mitter <committer@example.com> Orig <orig@example.com>
+ EOF
+ git cat-file commit HEAD >commit.out &&
+ commit_size=$(wc -c <commit.out) &&
+ commit_sha=$(git rev-parse HEAD) &&
+ echo $commit_sha commit $commit_size >expect &&
+ git cat-file --use-mailmap commit HEAD >commit.out &&
+ commit_size=$(wc -c <commit.out) &&
+ echo $commit_sha commit $commit_size >>expect &&
+ echo "info HEAD" >in &&
+ git cat-file --batch-command <in >actual &&
+ git cat-file --use-mailmap --batch-command <in >>actual &&
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t4205-log-pretty-formats.sh b/t/t4205-log-pretty-formats.sh
index e448ef2928..3e7ad9d5de 100755
--- a/t/t4205-log-pretty-formats.sh
+++ b/t/t4205-log-pretty-formats.sh
@@ -156,7 +156,7 @@ test_expect_success 'NUL termination with --reflog --pretty=oneline' '
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
@@ -1018,4 +1018,80 @@ test_expect_success '%(describe:abbrev=...) vs git describe --abbrev=...' '
test_cmp expect actual
'
+test_expect_success 'log --pretty with space stealing' '
+ printf mm0 >expect &&
+ git log -1 --pretty="format:mm%>>|(1)%x30" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --pretty with invalid padding format' '
+ printf "%s%%<(20" "$(git rev-parse HEAD)" >expect &&
+ git log -1 --pretty="format:%H%<(20" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --pretty with magical wrapping directives' '
+ commit_id=$(git commit-tree HEAD^{tree} -m "describe me") &&
+ git tag describe-me $commit_id &&
+ printf "\n(tag:\ndescribe-me)%%+w(2)" >expect &&
+ git log -1 --pretty="format:%w(1)%+d%+w(2)" $commit_id >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success SIZE_T_IS_64BIT 'log --pretty with overflowing wrapping directive' '
+ printf "%%w(2147483649,1,1)0" >expect &&
+ git log -1 --pretty="format:%w(2147483649,1,1)%x30" >actual &&
+ test_cmp expect actual &&
+ printf "%%w(1,2147483649,1)0" >expect &&
+ git log -1 --pretty="format:%w(1,2147483649,1)%x30" >actual &&
+ test_cmp expect actual &&
+ printf "%%w(1,1,2147483649)0" >expect &&
+ git log -1 --pretty="format:%w(1,1,2147483649)%x30" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success SIZE_T_IS_64BIT 'log --pretty with overflowing padding directive' '
+ printf "%%<(2147483649)0" >expect &&
+ git log -1 --pretty="format:%<(2147483649)%x30" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --pretty with padding and preceding control chars' '
+ printf "\20\20 0" >expect &&
+ git log -1 --pretty="format:%x10%x10%>|(4)%x30" >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'log --pretty truncation with control chars' '
+ test_commit "$(printf "\20\20\20\20xxxx")" file contents commit-with-control-chars &&
+ printf "\20\20\20\20x.." >expect &&
+ git log -1 --pretty="format:%<(3,trunc)%s" commit-with-control-chars >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' '
+ # We only assert that this command does not crash. This needs to be
+ # executed with the address sanitizer to demonstrate failure.
+ git log -1 --pretty="format:%>(2147483646)%x41%41%>(2147483646)%x41" >/dev/null
+'
+
+test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'set up huge commit' '
+ test-tool genzeros 2147483649 | tr "\000" "1" >expect &&
+ huge_commit=$(git commit-tree -F expect HEAD^{tree})
+'
+
+test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message' '
+ git log -1 --format="%B%<(1)%x30" $huge_commit >actual &&
+ echo 0 >>expect &&
+ test_cmp expect actual
+'
+
+test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'log --pretty with huge commit message does not cause allocation failure' '
+ test_must_fail git log -1 --format="%<(1)%B" $huge_commit 2>error &&
+ cat >expect <<-EOF &&
+ fatal: number too large to represent as int on this platform: 2147483649
+ EOF
+ test_cmp expect error
+'
+
test_done
diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh
index ac9e4d0928..c6540e822f 100755
--- a/t/t4211-line-log.sh
+++ b/t/t4211-line-log.sh
@@ -315,4 +315,26 @@ test_expect_success 'line-log with --before' '
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 --git a/t/t4213-log-tabexpand.sh b/t/t4213-log-tabexpand.sh
index 53a4af3244..590fce95e9 100755
--- a/t/t4213-log-tabexpand.sh
+++ b/t/t4213-log-tabexpand.sh
@@ -2,6 +2,7 @@
test_description='log/show --expand-tabs'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
HT=" "
diff --git a/t/t4301-merge-tree-write-tree.sh b/t/t4301-merge-tree-write-tree.sh
index cac85591b5..250f721795 100755
--- a/t/t4301-merge-tree-write-tree.sh
+++ b/t/t4301-merge-tree-write-tree.sh
@@ -141,7 +141,7 @@ test_expect_success 'test conflict notices and such' '
# Commit O: foo, olddir/{a,b,c}
# Commit A: modify foo, newdir/{a,b,c}
# Commit B: modify foo differently & rename foo -> olddir/bar
-# Expected: CONFLICT(content) for for newdir/bar (not olddir/bar or foo)
+# Expected: CONFLICT(content) for newdir/bar (not olddir/bar or foo)
test_expect_success 'directory rename + content conflict' '
# Setup
@@ -653,7 +653,7 @@ test_expect_success 'mod6: chains of rename/rename(1to2) and add/add via collidi
# Commit O: foo, olddir/{a,b,c}
# Commit A: delete foo, rename olddir/ -> newdir/, add newdir/bar/file
# Commit B: modify foo & rename foo -> olddir/bar
-# Expected: CONFLICT(content) for for newdir/bar (not olddir/bar or foo)
+# Expected: CONFLICT(content) for newdir/bar (not olddir/bar or foo)
test_expect_success 'directory rename + rename/delete + modify/delete + directory/file conflict' '
# Setup
@@ -860,4 +860,66 @@ test_expect_success '--stdin with both a successful and a conflicted merge' '
test_cmp expect actual
'
+
+test_expect_success '--merge-base is incompatible with --stdin' '
+ test_must_fail git merge-tree --merge-base=side1 --stdin 2>expect &&
+
+ grep "^fatal: --merge-base is incompatible with --stdin" expect
+'
+
+# specify merge-base as parent of branch2
+# git merge-tree --write-tree --merge-base=c2 c1 c3
+# Commit c1: add file1
+# Commit c2: add file2 after c1
+# Commit c3: add file3 after c2
+# Expected: add file3, and file2 does NOT appear
+
+test_expect_success 'specify merge-base as parent of branch2' '
+ # Setup
+ test_when_finished "rm -rf base-b2-p" &&
+ git init base-b2-p &&
+ test_commit -C base-b2-p c1 file1 &&
+ test_commit -C base-b2-p c2 file2 &&
+ test_commit -C base-b2-p c3 file3 &&
+
+ # Testing
+ TREE_OID=$(git -C base-b2-p merge-tree --write-tree --merge-base=c2 c1 c3) &&
+
+ q_to_tab <<-EOF >expect &&
+ 100644 blob $(git -C base-b2-p rev-parse c1:file1)Qfile1
+ 100644 blob $(git -C base-b2-p rev-parse c3:file3)Qfile3
+ EOF
+
+ git -C base-b2-p ls-tree $TREE_OID >actual &&
+ test_cmp expect actual
+'
+
+# Since the earlier tests have verified that individual merge-tree calls
+# are doing the right thing, this test case is only used to verify that
+# we can also trigger merges via --stdin, and that when we do we get
+# the same answer as running a bunch of separate merges.
+
+test_expect_success 'check the input format when --stdin is passed' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ test_commit -C repo c1 &&
+ test_commit -C repo c2 &&
+ test_commit -C repo c3 &&
+ printf "c1 c3\nc2 -- c1 c3\nc2 c3" | git -C repo merge-tree --stdin >actual &&
+
+ printf "1\0" >expect &&
+ git -C repo merge-tree --write-tree -z c1 c3 >>expect &&
+ printf "\0" >>expect &&
+
+ printf "1\0" >>expect &&
+ git -C repo merge-tree --write-tree -z --merge-base=c2 c1 c3 >>expect &&
+ printf "\0" >>expect &&
+
+ printf "1\0" >>expect &&
+ git -C repo merge-tree --write-tree -z c2 c3 >>expect &&
+ printf "\0" >>expect &&
+
+ test_cmp expect actual
+'
+
test_done
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index 6d693eef82..7d8dee41b0 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -428,8 +428,9 @@ test_bitmap_cases () {
test_line_count = 2 packs &&
test_line_count = 2 bitmaps &&
- git rev-list --use-bitmap-index HEAD 2>err &&
- grep "ignoring extra bitmap file" err
+ GIT_TRACE2_EVENT=$(pwd)/trace2.txt git rev-list --use-bitmap-index HEAD &&
+ grep "opened bitmap" trace2.txt &&
+ grep "ignoring extra bitmap" trace2.txt
)
'
}
diff --git a/t/t5313-pack-bounds-checks.sh b/t/t5313-pack-bounds-checks.sh
index cc4cfaa9d3..ceaa6700a2 100755
--- a/t/t5313-pack-bounds-checks.sh
+++ b/t/t5313-pack-bounds-checks.sh
@@ -59,7 +59,7 @@ test_expect_success 'setup' '
test_expect_success 'set up base packfile and variables' '
# the hash of this content starts with ff, which
# makes some later computations much simpler
- echo $(test_oid oidfff) >file &&
+ test_oid oidfff >file &&
git add file &&
git commit -m base &&
git repack -ad &&
diff --git a/t/t5314-pack-cycle-detection.sh b/t/t5314-pack-cycle-detection.sh
index 73a241743a..82734b9a3c 100755
--- a/t/t5314-pack-cycle-detection.sh
+++ b/t/t5314-pack-cycle-detection.sh
@@ -63,13 +63,16 @@ TEST_PASSES_SANITIZE_LEAK=true
# 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 <list >pack &&
+ git index-pack --stdin --fix-thin <pack
}
test_expect_success 'setup' '
diff --git a/t/t5317-pack-objects-filter-objects.sh b/t/t5317-pack-objects-filter-objects.sh
index bb633c9b09..5b707d911b 100755
--- a/t/t5317-pack-objects-filter-objects.sh
+++ b/t/t5317-pack-objects-filter-objects.sh
@@ -24,8 +24,9 @@ parse_verify_pack_blob_oid () {
}
test_expect_success 'verify blob count in normal packfile' '
- git -C r1 ls-files -s file.1 file.2 file.3 file.4 file.5 |
- test_parse_ls_files_stage_oids |
+ git -C r1 ls-files -s file.1 file.2 file.3 file.4 file.5 \
+ >ls_files_result &&
+ test_parse_ls_files_stage_oids <ls_files_result |
sort >expected &&
git -C r1 pack-objects --revs --stdout >all.pack <<-EOF &&
@@ -123,8 +124,8 @@ test_expect_success 'setup r2' '
'
test_expect_success 'verify blob count in normal packfile' '
- git -C r2 ls-files -s large.1000 large.10000 |
- test_parse_ls_files_stage_oids |
+ git -C r2 ls-files -s large.1000 large.10000 >ls_files_result &&
+ test_parse_ls_files_stage_oids <ls_files_result |
sort >expected &&
git -C r2 pack-objects --revs --stdout >all.pack <<-EOF &&
@@ -161,8 +162,8 @@ test_expect_success 'verify blob:limit=1000' '
'
test_expect_success 'verify blob:limit=1001' '
- git -C r2 ls-files -s large.1000 |
- test_parse_ls_files_stage_oids |
+ git -C r2 ls-files -s large.1000 >ls_files_result &&
+ test_parse_ls_files_stage_oids <ls_files_result |
sort >expected &&
git -C r2 pack-objects --revs --stdout --filter=blob:limit=1001 >filter.pack <<-EOF &&
@@ -179,8 +180,8 @@ test_expect_success 'verify blob:limit=1001' '
'
test_expect_success 'verify blob:limit=10001' '
- git -C r2 ls-files -s large.1000 large.10000 |
- test_parse_ls_files_stage_oids |
+ git -C r2 ls-files -s large.1000 large.10000 >ls_files_result &&
+ test_parse_ls_files_stage_oids <ls_files_result |
sort >expected &&
git -C r2 pack-objects --revs --stdout --filter=blob:limit=10001 >filter.pack <<-EOF &&
@@ -197,8 +198,8 @@ test_expect_success 'verify blob:limit=10001' '
'
test_expect_success 'verify blob:limit=1k' '
- git -C r2 ls-files -s large.1000 |
- test_parse_ls_files_stage_oids |
+ git -C r2 ls-files -s large.1000 >ls_files_result &&
+ test_parse_ls_files_stage_oids <ls_files_result |
sort >expected &&
git -C r2 pack-objects --revs --stdout --filter=blob:limit=1k >filter.pack <<-EOF &&
@@ -215,8 +216,8 @@ test_expect_success 'verify blob:limit=1k' '
'
test_expect_success 'verify explicitly specifying oversized blob in input' '
- git -C r2 ls-files -s large.1000 large.10000 |
- test_parse_ls_files_stage_oids |
+ git -C r2 ls-files -s large.1000 large.10000 >ls_files_result &&
+ test_parse_ls_files_stage_oids <ls_files_result |
sort >expected &&
echo HEAD >objects &&
@@ -233,8 +234,8 @@ test_expect_success 'verify explicitly specifying oversized blob in input' '
'
test_expect_success 'verify blob:limit=1m' '
- git -C r2 ls-files -s large.1000 large.10000 |
- test_parse_ls_files_stage_oids |
+ git -C r2 ls-files -s large.1000 large.10000 >ls_files_result &&
+ test_parse_ls_files_stage_oids <ls_files_result |
sort >expected &&
git -C r2 pack-objects --revs --stdout --filter=blob:limit=1m >filter.pack <<-EOF &&
@@ -264,6 +265,44 @@ test_expect_success 'verify normal and blob:limit packfiles have same commits/tr
test_cmp expected observed
'
+test_expect_success 'verify small limit and big limit results in small limit' '
+ git -C r2 ls-files -s large.1000 >ls_files_result &&
+ test_parse_ls_files_stage_oids <ls_files_result |
+ sort >expected &&
+
+ git -C r2 pack-objects --revs --stdout --filter=blob:limit=1001 \
+ --filter=blob:limit=10001 >filter.pack <<-EOF &&
+ HEAD
+ EOF
+ git -C r2 index-pack ../filter.pack &&
+
+ git -C r2 verify-pack -v ../filter.pack >verify_result &&
+ grep blob verify_result |
+ parse_verify_pack_blob_oid |
+ sort >observed &&
+
+ test_cmp expected observed
+'
+
+test_expect_success 'verify big limit and small limit results in small limit' '
+ git -C r2 ls-files -s large.1000 >ls_files_result &&
+ test_parse_ls_files_stage_oids <ls_files_result |
+ sort >expected &&
+
+ git -C r2 pack-objects --revs --stdout --filter=blob:limit=10001 \
+ --filter=blob:limit=1001 >filter.pack <<-EOF &&
+ HEAD
+ EOF
+ git -C r2 index-pack ../filter.pack &&
+
+ git -C r2 verify-pack -v ../filter.pack >verify_result &&
+ grep blob verify_result |
+ parse_verify_pack_blob_oid |
+ sort >observed &&
+
+ test_cmp expected observed
+'
+
# Test sparse:path=<path> filter.
# !!!!
# NOTE: sparse:path filter support has been dropped for security reasons,
@@ -289,8 +328,9 @@ test_expect_success 'setup r3' '
'
test_expect_success 'verify blob count in normal packfile' '
- git -C r3 ls-files -s sparse1 sparse2 dir1/sparse1 dir1/sparse2 |
- test_parse_ls_files_stage_oids |
+ git -C r3 ls-files -s sparse1 sparse2 dir1/sparse1 dir1/sparse2 \
+ >ls_files_result &&
+ test_parse_ls_files_stage_oids <ls_files_result |
sort >expected &&
git -C r3 pack-objects --revs --stdout >all.pack <<-EOF &&
@@ -341,8 +381,9 @@ test_expect_success 'setup r4' '
'
test_expect_success 'verify blob count in normal packfile' '
- git -C r4 ls-files -s pattern sparse1 sparse2 dir1/sparse1 dir1/sparse2 |
- test_parse_ls_files_stage_oids |
+ git -C r4 ls-files -s pattern sparse1 sparse2 dir1/sparse1 dir1/sparse2 \
+ >ls_files_result &&
+ test_parse_ls_files_stage_oids <ls_files_result |
sort >expected &&
git -C r4 pack-objects --revs --stdout >all.pack <<-EOF &&
@@ -359,8 +400,8 @@ test_expect_success 'verify blob count in normal packfile' '
'
test_expect_success 'verify sparse:oid=OID' '
- git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 |
- test_parse_ls_files_stage_oids |
+ git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 >ls_files_result &&
+ test_parse_ls_files_stage_oids <ls_files_result |
sort >expected &&
git -C r4 ls-files -s pattern >staged &&
@@ -379,8 +420,8 @@ test_expect_success 'verify sparse:oid=OID' '
'
test_expect_success 'verify sparse:oid=oid-ish' '
- git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 |
- test_parse_ls_files_stage_oids |
+ git -C r4 ls-files -s dir1/sparse1 dir1/sparse2 >ls_files_result &&
+ test_parse_ls_files_stage_oids <ls_files_result |
sort >expected &&
git -C r4 pack-objects --revs --stdout --filter=sparse:oid=main:pattern >filter.pack <<-EOF &&
@@ -400,8 +441,9 @@ test_expect_success 'verify sparse:oid=oid-ish' '
# This models previously omitted objects that we did not receive.
test_expect_success 'setup r1 - delete loose blobs' '
- git -C r1 ls-files -s file.1 file.2 file.3 file.4 file.5 |
- test_parse_ls_files_stage_oids |
+ git -C r1 ls-files -s file.1 file.2 file.3 file.4 file.5 \
+ >ls_files_result &&
+ test_parse_ls_files_stage_oids <ls_files_result |
sort >expected &&
for id in `cat expected | sed "s|..|&/|"`
diff --git a/t/t5544-pack-objects-hook.sh b/t/t5544-pack-objects-hook.sh
index 54f54f8d2e..1a9e14bbcc 100755
--- a/t/t5544-pack-objects-hook.sh
+++ b/t/t5544-pack-objects-hook.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='test custom script in place of pack-objects'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'create some history to fetch' '
diff --git a/t/t5554-noop-fetch-negotiator.sh b/t/t5554-noop-fetch-negotiator.sh
index 2ac7b5859e..06991e8e8a 100755
--- a/t/t5554-noop-fetch-negotiator.sh
+++ b/t/t5554-noop-fetch-negotiator.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='test noop fetch negotiator'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'noop negotiator does not emit any "have"' '
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index b2524a24c2..1928ea1dd7 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -772,6 +772,65 @@ test_expect_success 'reject cloning shallow repository using HTTP' '
git clone --no-reject-shallow $HTTPD_URL/smart/repo.git repo
'
+test_expect_success 'auto-discover bundle URI from HTTP clone' '
+ test_when_finished rm -rf trace.txt repo2 "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" &&
+ git -C src bundle create "$HTTPD_DOCUMENT_ROOT_PATH/everything.bundle" --all &&
+ git clone --bare --no-local src "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" &&
+
+ git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \
+ uploadpack.advertiseBundleURIs true &&
+ git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \
+ bundle.version 1 &&
+ git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \
+ bundle.mode all &&
+ git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo2.git" config \
+ bundle.everything.uri "$HTTPD_URL/everything.bundle" &&
+
+ GIT_TRACE2_EVENT="$(pwd)/trace.txt" \
+ git -c protocol.version=2 \
+ -c transfer.bundleURI=true clone \
+ $HTTPD_URL/smart/repo2.git repo2 &&
+ cat >pattern <<-EOF &&
+ "event":"child_start".*"argv":\["git-remote-https","$HTTPD_URL/everything.bundle"\]
+ EOF
+ grep -f pattern trace.txt
+'
+
+test_expect_success 'auto-discover multiple bundles from HTTP clone' '
+ test_when_finished rm -rf trace.txt repo3 "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" &&
+
+ test_commit -C src new &&
+ git -C src bundle create "$HTTPD_DOCUMENT_ROOT_PATH/new.bundle" HEAD~1..HEAD &&
+ git clone --bare --no-local src "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" &&
+
+ git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
+ uploadpack.advertiseBundleURIs true &&
+ git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
+ bundle.version 1 &&
+ git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
+ bundle.mode all &&
+
+ git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
+ bundle.everything.uri "$HTTPD_URL/everything.bundle" &&
+ git -C "$HTTPD_DOCUMENT_ROOT_PATH/repo3.git" config \
+ bundle.new.uri "$HTTPD_URL/new.bundle" &&
+
+ GIT_TRACE2_EVENT="$(pwd)/trace.txt" \
+ git -c protocol.version=2 \
+ -c transfer.bundleURI=true clone \
+ $HTTPD_URL/smart/repo3.git repo3 &&
+
+ # We should fetch _both_ bundles
+ cat >pattern <<-EOF &&
+ "event":"child_start".*"argv":\["git-remote-https","$HTTPD_URL/everything.bundle"\]
+ EOF
+ grep -f pattern trace.txt &&
+ cat >pattern <<-EOF &&
+ "event":"child_start".*"argv":\["git-remote-https","$HTTPD_URL/new.bundle"\]
+ EOF
+ grep -f pattern trace.txt
+'
+
# DO NOT add non-httpd-specific tests here, because the last part of this
# test script is only executed when httpd is available and enabled.
diff --git a/t/t5610-clone-detached.sh b/t/t5610-clone-detached.sh
index a7ec21eda5..022ed3d87c 100755
--- a/t/t5610-clone-detached.sh
+++ b/t/t5610-clone-detached.sh
@@ -4,6 +4,7 @@ test_description='test cloning a repository with detached HEAD'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
head_is_detached() {
diff --git a/t/t5611-clone-config.sh b/t/t5611-clone-config.sh
index 4b3877216e..727caff443 100755
--- a/t/t5611-clone-config.sh
+++ b/t/t5611-clone-config.sh
@@ -4,6 +4,7 @@ test_description='tests for git clone -c key=value'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'clone -c sets config in cloned repo' '
diff --git a/t/t5614-clone-submodules-shallow.sh b/t/t5614-clone-submodules-shallow.sh
index 0c85ef834a..c2a2bb453e 100755
--- a/t/t5614-clone-submodules-shallow.sh
+++ b/t/t5614-clone-submodules-shallow.sh
@@ -2,6 +2,7 @@
test_description='Test shallow cloning of repos with submodules'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
pwd=$(pwd)
diff --git a/t/t5616-partial-clone.sh b/t/t5616-partial-clone.sh
index 037941b95d..f519d2a87a 100755
--- a/t/t5616-partial-clone.sh
+++ b/t/t5616-partial-clone.sh
@@ -644,6 +644,49 @@ test_expect_success 'repack does not loosen promisor objects' '
grep "loosen_unused_packed_objects/loosened:0" trace
'
+test_expect_success 'lazy-fetch in submodule succeeds' '
+ # setup
+ test_config_global protocol.file.allow always &&
+
+ test_when_finished "rm -rf src-sub" &&
+ git init src-sub &&
+ git -C src-sub config uploadpack.allowfilter 1 &&
+ git -C src-sub config uploadpack.allowanysha1inwant 1 &&
+
+ # This blob must be missing in the subsequent commit.
+ echo foo >src-sub/file &&
+ git -C src-sub add file &&
+ git -C src-sub commit -m "submodule one" &&
+ SUB_ONE=$(git -C src-sub rev-parse HEAD) &&
+
+ echo bar >src-sub/file &&
+ git -C src-sub add file &&
+ git -C src-sub commit -m "submodule two" &&
+ SUB_TWO=$(git -C src-sub rev-parse HEAD) &&
+
+ test_when_finished "rm -rf src-super" &&
+ git init src-super &&
+ git -C src-super config uploadpack.allowfilter 1 &&
+ git -C src-super config uploadpack.allowanysha1inwant 1 &&
+ git -C src-super submodule add ../src-sub src-sub &&
+
+ git -C src-super/src-sub checkout $SUB_ONE &&
+ git -C src-super add src-sub &&
+ git -C src-super commit -m "superproject one" &&
+
+ git -C src-super/src-sub checkout $SUB_TWO &&
+ git -C src-super add src-sub &&
+ git -C src-super commit -m "superproject two" &&
+
+ # the fetch
+ test_when_finished "rm -rf client" &&
+ git clone --filter=blob:none --also-filter-submodules \
+ --recurse-submodules "file://$(pwd)/src-super" client &&
+
+ # Trigger lazy-fetch from the superproject
+ git -C client restore --recurse-submodules --source=HEAD^ :/
+'
+
. "$TEST_DIRECTORY"/lib-httpd.sh
start_httpd
diff --git a/t/t5617-clone-submodules-remote.sh b/t/t5617-clone-submodules-remote.sh
index 6884338249..5a4d7936a7 100755
--- a/t/t5617-clone-submodules-remote.sh
+++ b/t/t5617-clone-submodules-remote.sh
@@ -5,6 +5,7 @@ test_description='Test cloning repos with submodules using remote-tracking branc
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
pwd=$(pwd)
diff --git a/t/t5618-alternate-refs.sh b/t/t5618-alternate-refs.sh
index 3353216f09..f905db0a3f 100755
--- a/t/t5618-alternate-refs.sh
+++ b/t/t5618-alternate-refs.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='test handling of --alternate-refs traversal'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Avoid test_commit because we want a specific and known set of refs:
diff --git a/t/t5701-git-serve.sh b/t/t5701-git-serve.sh
index 1896f671cb..f21e5e9d33 100755
--- a/t/t5701-git-serve.sh
+++ b/t/t5701-git-serve.sh
@@ -13,7 +13,7 @@ test_expect_success 'test capability advertisement' '
wrong_algo sha1:sha256
wrong_algo sha256:sha1
EOF
- cat >expect <<-EOF &&
+ cat >expect.base <<-EOF &&
version 2
agent=git/$(git version | cut -d" " -f3)
ls-refs=unborn
@@ -21,8 +21,11 @@ test_expect_success 'test capability advertisement' '
server-option
object-format=$(test_oid algo)
object-info
+ EOF
+ cat >expect.trailer <<-EOF &&
0000
EOF
+ cat expect.base expect.trailer >expect &&
GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \
--advertise-capabilities >out &&
@@ -342,4 +345,39 @@ test_expect_success 'basics of object-info' '
test_cmp expect actual
'
+test_expect_success 'test capability advertisement with uploadpack.advertiseBundleURIs' '
+ test_config uploadpack.advertiseBundleURIs true &&
+
+ cat >expect.extra <<-EOF &&
+ bundle-uri
+ EOF
+ cat expect.base \
+ expect.extra \
+ expect.trailer >expect &&
+
+ GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \
+ --advertise-capabilities >out &&
+ test-tool pkt-line unpack <out >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'basics of bundle-uri: dies if not enabled' '
+ test-tool pkt-line pack >in <<-EOF &&
+ command=bundle-uri
+ 0000
+ EOF
+
+ cat >err.expect <<-\EOF &&
+ fatal: invalid command '"'"'bundle-uri'"'"'
+ EOF
+
+ cat >expect <<-\EOF &&
+ ERR serve: invalid command '"'"'bundle-uri'"'"'
+ EOF
+
+ test_must_fail test-tool serve-v2 --stateless-rpc <in >out 2>err.actual &&
+ test_cmp err.expect err.actual &&
+ test_must_be_empty out
+'
+
test_done
diff --git a/t/t5730-protocol-v2-bundle-uri-file.sh b/t/t5730-protocol-v2-bundle-uri-file.sh
new file mode 100755
index 0000000000..37bdb725bc
--- /dev/null
+++ b/t/t5730-protocol-v2-bundle-uri-file.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+test_description="Test bundle-uri with protocol v2 and 'file://' transport"
+
+TEST_NO_CREATE_REPO=1
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+# Test protocol v2 with 'file://' transport
+#
+BUNDLE_URI_PROTOCOL=file
+. "$TEST_DIRECTORY"/lib-bundle-uri-protocol.sh
+
+test_done
diff --git a/t/t5731-protocol-v2-bundle-uri-git.sh b/t/t5731-protocol-v2-bundle-uri-git.sh
new file mode 100755
index 0000000000..8add1b37ab
--- /dev/null
+++ b/t/t5731-protocol-v2-bundle-uri-git.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+test_description="Test bundle-uri with protocol v2 and 'git://' transport"
+
+TEST_NO_CREATE_REPO=1
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+# Test protocol v2 with 'git://' transport
+#
+BUNDLE_URI_PROTOCOL=git
+. "$TEST_DIRECTORY"/lib-bundle-uri-protocol.sh
+
+test_done
diff --git a/t/t5732-protocol-v2-bundle-uri-http.sh b/t/t5732-protocol-v2-bundle-uri-http.sh
new file mode 100755
index 0000000000..129daa0226
--- /dev/null
+++ b/t/t5732-protocol-v2-bundle-uri-http.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+test_description="Test bundle-uri with protocol v2 and 'http://' transport"
+
+TEST_NO_CREATE_REPO=1
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+# Test protocol v2 with 'http://' transport
+#
+BUNDLE_URI_PROTOCOL=http
+. "$TEST_DIRECTORY"/lib-bundle-uri-protocol.sh
+
+test_done
diff --git a/t/t5750-bundle-uri-parse.sh b/t/t5750-bundle-uri-parse.sh
index c2fe3f9c5a..7b4f930e53 100755
--- a/t/t5750-bundle-uri-parse.sh
+++ b/t/t5750-bundle-uri-parse.sh
@@ -30,6 +30,58 @@ test_expect_success 'bundle_uri_parse_line() just URIs' '
test_cmp_config_output expect actual
'
+test_expect_success 'bundle_uri_parse_line(): relative URIs' '
+ cat >in <<-\EOF &&
+ bundle.one.uri=bundle.bdl
+ bundle.two.uri=../bundle.bdl
+ bundle.three.uri=sub/dir/bundle.bdl
+ EOF
+
+ cat >expect <<-\EOF &&
+ [bundle]
+ version = 1
+ mode = all
+ [bundle "one"]
+ uri = <uri>/bundle.bdl
+ [bundle "two"]
+ uri = bundle.bdl
+ [bundle "three"]
+ uri = <uri>/sub/dir/bundle.bdl
+ EOF
+
+ test-tool bundle-uri parse-key-values in >actual 2>err &&
+ test_must_be_empty err &&
+ test_cmp_config_output expect actual
+'
+
+test_expect_success 'bundle_uri_parse_line(): relative URIs and parent paths' '
+ cat >in <<-\EOF &&
+ bundle.one.uri=bundle.bdl
+ bundle.two.uri=../bundle.bdl
+ bundle.three.uri=../../bundle.bdl
+ EOF
+
+ cat >expect <<-\EOF &&
+ [bundle]
+ version = 1
+ mode = all
+ [bundle "one"]
+ uri = <uri>/bundle.bdl
+ [bundle "two"]
+ uri = bundle.bdl
+ [bundle "three"]
+ uri = <uri>/../bundle.bdl
+ EOF
+
+ # TODO: We would prefer if parsing a bundle list would not cause
+ # a die() and instead would give a warning and allow the rest of
+ # a Git command to continue. This test_must_fail is necessary for
+ # now until the interface for relative_url() allows for reporting
+ # an error instead of die()ing.
+ test_must_fail test-tool bundle-uri parse-key-values in >actual 2>err &&
+ grep "fatal: cannot strip one component off url" err
+'
+
test_expect_success 'bundle_uri_parse_line() parsing edge cases: empty key or value' '
cat >in <<-\EOF &&
=bogus-value
@@ -136,6 +188,36 @@ test_expect_success 'parse config format: just URIs' '
test_cmp_config_output expect actual
'
+test_expect_success 'parse config format: relative URIs' '
+ cat >in <<-\EOF &&
+ [bundle]
+ version = 1
+ mode = all
+ [bundle "one"]
+ uri = bundle.bdl
+ [bundle "two"]
+ uri = ../bundle.bdl
+ [bundle "three"]
+ uri = sub/dir/bundle.bdl
+ EOF
+
+ cat >expect <<-\EOF &&
+ [bundle]
+ version = 1
+ mode = all
+ [bundle "one"]
+ uri = <uri>/bundle.bdl
+ [bundle "two"]
+ uri = bundle.bdl
+ [bundle "three"]
+ uri = <uri>/sub/dir/bundle.bdl
+ EOF
+
+ test-tool bundle-uri parse-config in >actual 2>err &&
+ test_must_be_empty err &&
+ test_cmp_config_output expect actual
+'
+
test_expect_success 'parse config format edge cases: empty key or value' '
cat >in1 <<-\EOF &&
= bogus-value
diff --git a/t/t6003-rev-list-topo-order.sh b/t/t6003-rev-list-topo-order.sh
index 1f7d7dd20c..5cf2cee74d 100755
--- a/t/t6003-rev-list-topo-order.sh
+++ b/t/t6003-rev-list-topo-order.sh
@@ -326,19 +326,16 @@ a2
c3
EOF
-#
-# this test fails on --topo-order - a fix is required
-#
-#test_output_expect_success '--max-age=c3, --topo-order' "git rev-list --topo-order --max-age=$(commit_date c3) l5" <<EOF
-#l5
-#l4
-#l3
-#a4
-#c3
-#b4
-#a3
-#a2
-#EOF
+test_output_expect_success '--max-age=c3, --topo-order' "git rev-list --topo-order --max-age=$(commit_date c3) l5" <<EOF
+l5
+l4
+l3
+a4
+c3
+b4
+a3
+a2
+EOF
test_output_expect_success 'one specified head reachable from another a4, c3, --topo-order' "list_duplicates git rev-list --topo-order a4 c3" <<EOF
EOF
diff --git a/t/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh
index 833205125a..3a1cf30b1d 100755
--- a/t/t6020-bundle-misc.sh
+++ b/t/t6020-bundle-misc.sh
@@ -11,6 +11,13 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-bundle.sh
+for cmd in create verify list-heads unbundle
+do
+ test_expect_success "usage: git bundle $cmd needs an argument" '
+ test_expect_code 129 git bundle $cmd
+ '
+done
+
# Create a commit or tag and set the variable with the object ID.
test_commit_setvar () {
notick=
diff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh
index 6dbbe62eb2..3ba4fdf615 100755
--- a/t/t6030-bisect-porcelain.sh
+++ b/t/t6030-bisect-porcelain.sh
@@ -34,6 +34,36 @@ HASH2=
HASH3=
HASH4=
+test_bisect_usage () {
+ local code="$1" &&
+ shift &&
+ cat >expect &&
+ test_expect_code $code "$@" >out 2>actual &&
+ test_must_be_empty out &&
+ test_cmp expect actual
+}
+
+test_expect_success 'bisect usage' "
+ test_bisect_usage 1 git bisect reset extra1 extra2 <<-\EOF &&
+ error: 'git bisect reset' requires either no argument or a commit
+ EOF
+ test_bisect_usage 1 git bisect terms extra1 extra2 <<-\EOF &&
+ error: 'git bisect terms' requires 0 or 1 argument
+ EOF
+ test_bisect_usage 1 git bisect next extra1 <<-\EOF &&
+ error: 'git bisect next' requires 0 arguments
+ EOF
+ test_bisect_usage 1 git bisect log extra1 <<-\EOF &&
+ error: We are not bisecting.
+ EOF
+ test_bisect_usage 1 git bisect replay <<-\EOF &&
+ error: no logfile given
+ EOF
+ test_bisect_usage 1 git bisect run <<-\EOF
+ error: 'git bisect run' failed: no command provided.
+ EOF
+"
+
test_expect_success 'set up basic repo with 1 file (hello) and 4 commits' '
add_line_into_file "1: Hello World" hello &&
HASH1=$(git rev-parse --verify HEAD) &&
@@ -252,6 +282,124 @@ test_expect_success 'bisect skip: with commit both bad and skipped' '
grep $HASH4 my_bisect_log.txt
'
+test_bisect_run_args () {
+ test_when_finished "rm -f run.sh actual" &&
+ >actual &&
+ cat >expect.args &&
+ cat <&6 >expect.out &&
+ cat <&7 >expect.err &&
+ write_script run.sh <<-\EOF &&
+ while test $# != 0
+ do
+ echo "<$1>" &&
+ shift
+ done >actual.args
+ EOF
+
+ test_when_finished "git bisect reset" &&
+ git bisect start &&
+ git bisect good $HASH1 &&
+ git bisect bad $HASH4 &&
+ git bisect run ./run.sh $@ >actual.out.raw 2>actual.err &&
+ # Prune just the log output
+ sed -n \
+ -e '/^Author:/d' \
+ -e '/^Date:/d' \
+ -e '/^$/d' \
+ -e '/^commit /d' \
+ -e '/^ /d' \
+ -e 'p' \
+ <actual.out.raw >actual.out &&
+ test_cmp expect.out actual.out &&
+ test_cmp expect.err actual.err &&
+ test_cmp expect.args actual.args
+}
+
+test_expect_success 'git bisect run: args, stdout and stderr with no arguments' "
+ test_bisect_run_args <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
+ EOF_ARGS
+ running './run.sh'
+ $HASH4 is the first bad commit
+ bisect found first bad commit
+ EOF_OUT
+ EOF_ERR
+"
+
+test_expect_success 'git bisect run: args, stdout and stderr: "--" argument' "
+ test_bisect_run_args -- <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
+ <-->
+ EOF_ARGS
+ running './run.sh' '--'
+ $HASH4 is the first bad commit
+ bisect found first bad commit
+ EOF_OUT
+ EOF_ERR
+"
+
+test_expect_success 'git bisect run: args, stdout and stderr: "--log foo --no-log bar" arguments' "
+ test_bisect_run_args --log foo --no-log bar <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
+ <--log>
+ <foo>
+ <--no-log>
+ <bar>
+ EOF_ARGS
+ running './run.sh' '--log' 'foo' '--no-log' 'bar'
+ $HASH4 is the first bad commit
+ bisect found first bad commit
+ EOF_OUT
+ EOF_ERR
+"
+
+test_expect_success 'git bisect run: args, stdout and stderr: "--bisect-start" argument' "
+ test_bisect_run_args --bisect-start <<-'EOF_ARGS' 6<<-EOF_OUT 7<<-'EOF_ERR'
+ <--bisect-start>
+ EOF_ARGS
+ running './run.sh' '--bisect-start'
+ $HASH4 is the first bad commit
+ bisect found first bad commit
+ EOF_OUT
+ EOF_ERR
+"
+
+test_expect_success 'git bisect run: negative exit code' "
+ write_script fail.sh <<-'EOF' &&
+ exit 255
+ EOF
+ cat <<-'EOF' >expect &&
+ bisect run failed: exit code -1 from './fail.sh' is < 0 or >= 128
+ EOF
+ test_when_finished 'git bisect reset' &&
+ git bisect start &&
+ git bisect good $HASH1 &&
+ git bisect bad $HASH4 &&
+ ! git bisect run ./fail.sh 2>err &&
+ sed -En 's/.*(bisect.*code) (-?[0-9]+) (from.*)/\1 -1 \3/p' err >actual &&
+ test_cmp expect actual
+"
+
+test_expect_success 'git bisect run: unable to verify on good' "
+ write_script fail.sh <<-'EOF' &&
+ head=\$(git rev-parse --verify HEAD)
+ good=\$(git rev-parse --verify $HASH1)
+ if test "\$head" = "\$good"
+ then
+ exit 255
+ else
+ exit 127
+ fi
+ EOF
+ cat <<-'EOF' >expect &&
+ unable to verify './fail.sh' on good revision
+ EOF
+ test_when_finished 'git bisect reset' &&
+ git bisect start &&
+ git bisect good $HASH1 &&
+ git bisect bad $HASH4 &&
+ ! git bisect run ./fail.sh 2>err &&
+ sed -n 's/.*\(unable to verify.*\)/\1/p' err >actual &&
+ test_cmp expect actual
+"
+
# We want to automatically find the commit that
# added "Another" into hello.
test_expect_success '"git bisect run" simple case' '
@@ -910,6 +1058,16 @@ test_expect_success 'bisect start with one term1 and term2' '
git bisect reset
'
+test_expect_success 'bogus command does not start bisect' '
+ git bisect reset &&
+ test_must_fail git bisect --bisect-terms 1 2 2>out &&
+ ! grep "You need to start" out &&
+ test_must_fail git bisect --bisect-terms 2>out &&
+ ! grep "You need to start" out &&
+ grep "git bisect.*visualize" out &&
+ git bisect reset
+'
+
test_expect_success 'bisect replay with term1 and term2' '
git bisect replay log_to_replay.txt >bisect_result &&
grep "$HASH2 is the first term1 commit" bisect_result &&
@@ -1000,7 +1158,6 @@ test_expect_success 'git bisect reset cleans bisection state properly' '
test_path_is_missing ".git/BISECT_LOG" &&
test_path_is_missing ".git/BISECT_RUN" &&
test_path_is_missing ".git/BISECT_TERMS" &&
- test_path_is_missing ".git/head-name" &&
test_path_is_missing ".git/BISECT_HEAD" &&
test_path_is_missing ".git/BISECT_START"
'
@@ -1063,4 +1220,14 @@ test_expect_success 'bisect state output with bad commit' '
grep -F "waiting for good commit(s), bad commit known" output
'
+test_expect_success 'verify correct error message' '
+ git bisect reset &&
+ git bisect start $HASH4 $HASH1 &&
+ write_script test_script.sh <<-\EOF &&
+ rm .git/BISECT*
+ EOF
+ test_must_fail git bisect run ./test_script.sh 2>error &&
+ grep "git bisect good.*exited with error code" error
+'
+
test_done
diff --git a/t/t6060-merge-index.sh b/t/t6060-merge-index.sh
index ed449abe55..1a8b64cce1 100755
--- a/t/t6060-merge-index.sh
+++ b/t/t6060-merge-index.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='basic git merge-index / git-merge-one-file tests'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup diverging branches' '
diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh
index fa38b87441..2ae1fc721b 100755
--- a/t/t6300-for-each-ref.sh
+++ b/t/t6300-for-each-ref.sh
@@ -1242,6 +1242,24 @@ test_expect_success 'basic atom: rest must fail' '
test_must_fail git for-each-ref --format="%(rest)" refs/heads/main
'
+test_expect_success 'HEAD atom does not take arguments' '
+ test_must_fail git for-each-ref --format="%(HEAD:foo)" 2>err &&
+ echo "fatal: %(HEAD) does not take arguments" >expect &&
+ test_cmp expect err
+'
+
+test_expect_success 'subject atom rejects unknown arguments' '
+ test_must_fail git for-each-ref --format="%(subject:foo)" 2>err &&
+ echo "fatal: unrecognized %(subject) argument: foo" >expect &&
+ test_cmp expect err
+'
+
+test_expect_success 'refname atom rejects unknown arguments' '
+ test_must_fail git for-each-ref --format="%(refname:foo)" 2>err &&
+ echo "fatal: unrecognized %(refname) argument: foo" >expect &&
+ test_cmp expect err
+'
+
test_expect_success 'trailer parsing not fooled by --- line' '
git commit --allow-empty -F - <<-\EOF &&
this is the subject
diff --git a/t/t6301-for-each-ref-errors.sh b/t/t6301-for-each-ref-errors.sh
index 40edf9dab5..bfda1f46ad 100755
--- a/t/t6301-for-each-ref-errors.sh
+++ b/t/t6301-for-each-ref-errors.sh
@@ -2,6 +2,7 @@
test_description='for-each-ref errors for broken refs'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
ZEROS=$ZERO_OID
diff --git a/t/t6401-merge-criss-cross.sh b/t/t6401-merge-criss-cross.sh
index 9d5e992878..1962310408 100755
--- a/t/t6401-merge-criss-cross.sh
+++ b/t/t6401-merge-criss-cross.sh
@@ -8,6 +8,8 @@
test_description='Test criss-cross merge'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'prepare repository' '
diff --git a/t/t6406-merge-attr.sh b/t/t6406-merge-attr.sh
index 8650a88c40..5e4e4dd6d9 100755
--- a/t/t6406-merge-attr.sh
+++ b/t/t6406-merge-attr.sh
@@ -8,6 +8,7 @@ test_description='per path merge controlled by merge attribute'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t6407-merge-binary.sh b/t/t6407-merge-binary.sh
index e8a28717ce..0753fc95f4 100755
--- a/t/t6407-merge-binary.sh
+++ b/t/t6407-merge-binary.sh
@@ -5,6 +5,7 @@ test_description='ask merge-recursive to merge binary files'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t6415-merge-dir-to-symlink.sh b/t/t6415-merge-dir-to-symlink.sh
index 2655e295f5..ae00492c76 100755
--- a/t/t6415-merge-dir-to-symlink.sh
+++ b/t/t6415-merge-dir-to-symlink.sh
@@ -4,6 +4,7 @@ test_description='merging when a directory was replaced with a symlink'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'create a commit where dir a/b changed to symlink' '
diff --git a/t/t6421-merge-partial-clone.sh b/t/t6421-merge-partial-clone.sh
index 5413e5dd9d..711b709e75 100755
--- a/t/t6421-merge-partial-clone.sh
+++ b/t/t6421-merge-partial-clone.sh
@@ -155,7 +155,7 @@ test_setup_repo () {
# Commit A:
# (Rename leap->jump, rename basename/ -> basename/subdir/, rename dir/
# -> folder/, move e into newsubdir, add newfile.rs, remove f, modify
-# both both Makefiles and jumps)
+# both Makefiles and jumps)
# general/{jump1_A, jump2_A}
# basename/subdir/{numbers_A, sequence_A, values_A}
# folder/subdir/{a,b,c,d,Makefile_TOP_A}
@@ -343,7 +343,7 @@ test_expect_merge_algorithm failure success 'Objects downloaded when a directory
# Commit A:
# (Rename leap->jump, rename basename/ -> basename/subdir/, rename dir/
# -> folder/, move e into newsubdir, add newfile.rs, remove f, modify
-# both both Makefiles and jumps)
+# both Makefiles and jumps)
# general/{jump1_A, jump2_A}
# basename/subdir/{numbers_A, sequence_A, values_A}
# folder/subdir/{a,b,c,d,Makefile_TOP_A}
diff --git a/t/t6422-merge-rename-corner-cases.sh b/t/t6422-merge-rename-corner-cases.sh
index 346253c7c8..076b6a74d5 100755
--- a/t/t6422-merge-rename-corner-cases.sh
+++ b/t/t6422-merge-rename-corner-cases.sh
@@ -1159,7 +1159,6 @@ test_conflicts_with_adds_and_renames() {
# 4) There should not be any three~* files in the working
# tree
test_setup_collision_conflict () {
- #test_expect_success "setup simple $sideL/$sideR conflict" '
git init simple_${sideL}_${sideR} &&
(
cd simple_${sideL}_${sideR} &&
@@ -1236,7 +1235,6 @@ test_conflicts_with_adds_and_renames() {
fi &&
test_tick && git commit -m R
)
- #'
}
test_expect_success "check simple $sideL/$sideR conflict" '
diff --git a/t/t6426-merge-skip-unneeded-updates.sh b/t/t6426-merge-skip-unneeded-updates.sh
index 2bb8e7f09b..fd21c1a486 100755
--- a/t/t6426-merge-skip-unneeded-updates.sh
+++ b/t/t6426-merge-skip-unneeded-updates.sh
@@ -378,42 +378,30 @@ test_expect_success '2c: Modify b & add c VS rename b->c' '
test_i18ngrep "CONFLICT (.*/add):" out &&
test_must_be_empty err &&
- # Make sure c WAS updated
+ git ls-files -s >index_files &&
+ test_line_count = 2 index_files &&
+
+ # Ensure b was removed
+ test_path_is_missing b &&
+
+ # Make sure c WAS updated...
test-tool chmtime --get c >new-mtime &&
- test $(cat old-mtime) -lt $(cat new-mtime)
-
- # FIXME: rename/add conflicts are horribly broken right now;
- # when I get back to my patch series fixing it and
- # rename/rename(2to1) conflicts to bring them in line with
- # how add/add conflicts behave, then checks like the below
- # could be added. But that patch series is waiting until
- # the rename-directory-detection series lands, which this
- # is part of. And in the mean time, I do not want to further
- # enforce broken behavior. So for now, the main test is the
- # one above that err is an empty file.
-
- #git ls-files -s >index_files &&
- #test_line_count = 2 index_files &&
-
- #git rev-parse >actual :2:c :3:c &&
- #git rev-parse >expect A:b A:c &&
- #test_cmp expect actual &&
-
- #git cat-file -p A:b >>merged &&
- #git cat-file -p A:c >>merge-me &&
- #>empty &&
- #test_must_fail git merge-file \
- # -L "Temporary merge branch 1" \
- # -L "" \
- # -L "Temporary merge branch 2" \
- # merged empty merge-me &&
- #sed -e "s/^\([<=>]\)/\1\1\1/" merged >merged-internal &&
-
- #git hash-object c >actual &&
- #git hash-object merged-internal >expect &&
- #test_cmp expect actual &&
-
- #test_path_is_missing b
+ test $(cat old-mtime) -lt $(cat new-mtime) &&
+
+ # ...and has correct index entries and working tree contents
+ git rev-parse >actual :2:c :3:c &&
+ git rev-parse >expect A:c A:b &&
+ test_cmp expect actual &&
+
+ git cat-file -p A:b >>merge-me &&
+ git cat-file -p A:c >>merged &&
+ >empty &&
+ test_must_fail git merge-file \
+ -L "HEAD" \
+ -L "" \
+ -L "B^0" \
+ merged empty merge-me &&
+ test_cmp merged c
)
'
diff --git a/t/t6435-merge-sparse.sh b/t/t6435-merge-sparse.sh
index fde4aa3cd1..78628fb248 100755
--- a/t/t6435-merge-sparse.sh
+++ b/t/t6435-merge-sparse.sh
@@ -3,6 +3,7 @@
test_description='merge with sparse files'
TEST_CREATE_REPO_NO_TEMPLATE=1
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# test_file $filename $content
diff --git a/t/t7103-reset-bare.sh b/t/t7103-reset-bare.sh
index a60153f9f3..18bbd9975e 100755
--- a/t/t7103-reset-bare.sh
+++ b/t/t7103-reset-bare.sh
@@ -63,7 +63,7 @@ test_expect_success '"mixed" reset is not allowed in bare' '
test_must_fail git reset --mixed HEAD^
'
-test_expect_success !SANITIZE_LEAK '"soft" reset is allowed in bare' '
+test_expect_success '"soft" reset is allowed in bare' '
git reset --soft HEAD^ &&
git show --pretty=format:%s >out &&
echo one >expect &&
diff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh
index 2859695c6d..f778321857 100755
--- a/t/t7412-submodule-absorbgitdirs.sh
+++ b/t/t7412-submodule-absorbgitdirs.sh
@@ -10,6 +10,7 @@ TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup a real submodule' '
+ cwd="$(pwd)" &&
git init sub1 &&
test_commit -C sub1 first &&
git submodule add ./sub1 &&
@@ -18,13 +19,21 @@ test_expect_success 'setup a real submodule' '
'
test_expect_success 'absorb the git dir' '
+ >expect &&
+ >actual &&
>expect.1 &&
>expect.2 &&
>actual.1 &&
>actual.2 &&
git status >expect.1 &&
git -C sub1 rev-parse HEAD >expect.2 &&
- git submodule absorbgitdirs &&
+ cat >expect <<-EOF &&
+ Migrating git directory of '\''sub1'\'' from
+ '\''$cwd/sub1/.git'\'' to
+ '\''$cwd/.git/modules/sub1'\''
+ EOF
+ git submodule absorbgitdirs 2>actual &&
+ test_cmp expect actual &&
git fsck &&
test -f sub1/.git &&
test -d .git/modules/sub1 &&
@@ -37,7 +46,8 @@ test_expect_success 'absorb the git dir' '
test_expect_success 'absorbing does not fail for deinitialized submodules' '
test_when_finished "git submodule update --init" &&
git submodule deinit --all &&
- git submodule absorbgitdirs &&
+ git submodule absorbgitdirs 2>err &&
+ test_must_be_empty err &&
test -d .git/modules/sub1 &&
test -d sub1 &&
! test -e sub1/.git
@@ -56,7 +66,13 @@ test_expect_success 'setup nested submodule' '
test_expect_success 'absorb the git dir in a nested submodule' '
git status >expect.1 &&
git -C sub1/nested rev-parse HEAD >expect.2 &&
- git submodule absorbgitdirs &&
+ cat >expect <<-EOF &&
+ Migrating git directory of '\''sub1/nested'\'' from
+ '\''$cwd/sub1/nested/.git'\'' to
+ '\''$cwd/.git/modules/sub1/modules/nested'\''
+ EOF
+ git submodule absorbgitdirs 2>actual &&
+ test_cmp expect actual &&
test -f sub1/nested/.git &&
test -d .git/modules/sub1/modules/nested &&
git status >actual.1 &&
@@ -87,7 +103,13 @@ test_expect_success 're-setup nested submodule' '
test_expect_success 'absorb the git dir in a nested submodule' '
git status >expect.1 &&
git -C sub1/nested rev-parse HEAD >expect.2 &&
- git submodule absorbgitdirs &&
+ cat >expect <<-EOF &&
+ Migrating git directory of '\''sub1'\'' from
+ '\''$cwd/sub1/.git'\'' to
+ '\''$cwd/.git/modules/sub1'\''
+ EOF
+ git submodule absorbgitdirs 2>actual &&
+ test_cmp expect actual &&
test -f sub1/.git &&
test -f sub1/nested/.git &&
test -d .git/modules/sub1/modules/nested &&
@@ -97,6 +119,27 @@ test_expect_success 'absorb the git dir in a nested submodule' '
test_cmp expect.2 actual.2
'
+test_expect_success 'absorb the git dir outside of primary worktree' '
+ test_when_finished "rm -rf repo-bare.git" &&
+ git clone --bare . repo-bare.git &&
+ test_when_finished "rm -rf repo-wt" &&
+ git -C repo-bare.git worktree add ../repo-wt &&
+
+ test_when_finished "rm -f .gitconfig" &&
+ test_config_global protocol.file.allow always &&
+ git -C repo-wt submodule update --init &&
+ git init repo-wt/sub2 &&
+ test_commit -C repo-wt/sub2 A &&
+ git -C repo-wt submodule add ./sub2 sub2 &&
+ cat >expect <<-EOF &&
+ Migrating git directory of '\''sub2'\'' from
+ '\''$cwd/repo-wt/sub2/.git'\'' to
+ '\''$cwd/repo-bare.git/worktrees/repo-wt/modules/sub2'\''
+ EOF
+ git -C repo-wt submodule absorbgitdirs 2>actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'setup a gitlink with missing .gitmodules entry' '
git init sub2 &&
test_commit -C sub2 first &&
@@ -107,7 +150,11 @@ test_expect_success 'setup a gitlink with missing .gitmodules entry' '
test_expect_success 'absorbing the git dir fails for incomplete submodules' '
git status >expect.1 &&
git -C sub2 rev-parse HEAD >expect.2 &&
- test_must_fail git submodule absorbgitdirs &&
+ cat >expect <<-\EOF &&
+ fatal: could not lookup name for submodule '\''sub2'\''
+ EOF
+ test_must_fail git submodule absorbgitdirs 2>actual &&
+ test_cmp expect actual &&
git -C sub2 fsck &&
test -d sub2/.git &&
git status >actual &&
@@ -127,8 +174,11 @@ test_expect_success 'setup a submodule with multiple worktrees' '
'
test_expect_success 'absorbing fails for a submodule with multiple worktrees' '
- test_must_fail git submodule absorbgitdirs sub3 2>error &&
- test_i18ngrep "not supported" error
+ cat >expect <<-\EOF &&
+ fatal: could not lookup name for submodule '\''sub2'\''
+ EOF
+ test_must_fail git submodule absorbgitdirs 2>actual &&
+ test_cmp expect actual
'
test_done
diff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh
index a39de8c112..07ca46fb0d 100755
--- a/t/t7504-commit-msg-hook.sh
+++ b/t/t7504-commit-msg-hook.sh
@@ -5,6 +5,7 @@ test_description='commit-msg hook'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'with no hook' '
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index 2b7ef6c41a..aed07c5b62 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1676,4 +1676,74 @@ test_expect_success 'racy timestamps will be fixed for dirty worktree' '
! test_is_magic_mtime .git/index
'
+test_expect_success 'setup slow status advice' '
+ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main git init slowstatus &&
+ (
+ cd slowstatus &&
+ cat >.gitignore <<-\EOF &&
+ /actual
+ /expected
+ /out
+ EOF
+ git add .gitignore &&
+ git commit -m "Add .gitignore" &&
+ git config advice.statusuoption true
+ )
+'
+
+test_expect_success 'slow status advice when core.untrackedCache and fsmonitor are unset' '
+ (
+ cd slowstatus &&
+ git config core.untrackedCache false &&
+ git config core.fsmonitor false &&
+ GIT_TEST_UF_DELAY_WARNING=1 git status >actual &&
+ cat >expected <<-\EOF &&
+ On branch main
+
+ It took 3.25 seconds to enumerate untracked files.
+ See '\''git help status'\'' for information on how to improve this.
+
+ nothing to commit, working tree clean
+ EOF
+ test_cmp expected actual
+ )
+'
+
+test_expect_success 'slow status advice when core.untrackedCache true, but not fsmonitor' '
+ (
+ cd slowstatus &&
+ git config core.untrackedCache true &&
+ git config core.fsmonitor false &&
+ GIT_TEST_UF_DELAY_WARNING=1 git status >actual &&
+ cat >expected <<-\EOF &&
+ On branch main
+
+ It took 3.25 seconds to enumerate untracked files.
+ See '\''git help status'\'' for information on how to improve this.
+
+ nothing to commit, working tree clean
+ EOF
+ test_cmp expected actual
+ )
+'
+
+test_expect_success 'slow status advice when core.untrackedCache true, and fsmonitor' '
+ (
+ cd slowstatus &&
+ git config core.untrackedCache true &&
+ git config core.fsmonitor true &&
+ GIT_TEST_UF_DELAY_WARNING=1 git status >actual &&
+ cat >expected <<-\EOF &&
+ On branch main
+
+ It took 3.25 seconds to enumerate untracked files,
+ but the results were cached, and subsequent runs may be faster.
+ See '\''git help status'\'' for information on how to improve this.
+
+ nothing to commit, working tree clean
+ EOF
+ test_cmp expected actual
+ )
+'
+
test_done
diff --git a/t/t7517-per-repo-email.sh b/t/t7517-per-repo-email.sh
index 163ae80468..efc6496e2b 100755
--- a/t/t7517-per-repo-email.sh
+++ b/t/t7517-per-repo-email.sh
@@ -9,6 +9,7 @@ test_description='per-repo forced setting of email address'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup a likely user.useConfigOnly use case' '
diff --git a/t/t7520-ignored-hook-warning.sh b/t/t7520-ignored-hook-warning.sh
index dc57526e6f..184b258989 100755
--- a/t/t7520-ignored-hook-warning.sh
+++ b/t/t7520-ignored-hook-warning.sh
@@ -2,6 +2,7 @@
test_description='ignored hook warning'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh
index 4abc74db2b..4c0327b2bb 100755
--- a/t/t7527-builtin-fsmonitor.sh
+++ b/t/t7527-builtin-fsmonitor.sh
@@ -866,27 +866,9 @@ test_expect_success 'submodule always visited' '
# the submodule, and someone does a `git submodule absorbgitdirs`
# in the super, Git will recursively invoke `git submodule--helper`
# to do the work and this may try to read the index. This will
-# try to start the daemon in the submodule *and* pass (either
-# directly or via inheritance) the `--super-prefix` arg to the
-# `git fsmonitor--daemon start` command inside the submodule.
-# This causes a warning because fsmonitor--daemon does take that
-# global arg (see the table in git.c)
-#
-# This causes a warning when trying to start the daemon that is
-# somewhat confusing. It does not seem to hurt anything because
-# the fsmonitor code maps the query failure into a trivial response
-# and does the work anyway.
-#
-# It would be nice to silence the warning, however.
-
-have_t2_error_event () {
- log=$1
- msg="fsmonitor--daemon doesnQt support --super-prefix" &&
-
- tr '\047' Q <$1 | grep -e "$msg"
-}
+# try to start the daemon in the submodule.
-test_expect_success "stray submodule super-prefix warning" '
+test_expect_success "submodule absorbgitdirs implicitly starts daemon" '
test_when_finished "rm -rf super; \
rm -rf sub; \
rm super-sub.trace" &&
@@ -904,21 +886,31 @@ test_expect_success "stray submodule super-prefix warning" '
test_path_is_dir super/dir_1/dir_2/sub/.git &&
+ cwd="$(cd super && pwd)" &&
+ cat >expect <<-EOF &&
+ Migrating git directory of '\''dir_1/dir_2/sub'\'' from
+ '\''$cwd/dir_1/dir_2/sub/.git'\'' to
+ '\''$cwd/.git/modules/dir_1/dir_2/sub'\''
+ EOF
GIT_TRACE2_EVENT="$PWD/super-sub.trace" \
- git -C super submodule absorbgitdirs &&
+ git -C super submodule absorbgitdirs >out 2>actual &&
+ test_cmp expect actual &&
+ test_must_be_empty out &&
- ! have_t2_error_event super-sub.trace
+ # Confirm that the trace2 log contains a record of the
+ # daemon starting.
+ test_subcommand git fsmonitor--daemon start <super-sub.trace
'
# On a case-insensitive file system, confirm that the daemon
# notices when the .git directory is moved/renamed/deleted
-# regardless of how it is spelled in the the FS event.
+# regardless of how it is spelled in the FS event.
# That is, does the FS event receive the spelling of the
# operation or does it receive the spelling preserved with
# the file/directory.
#
test_expect_success CASE_INSENSITIVE_FS 'case insensitive+preserving' '
-# test_when_finished "stop_daemon_delete_repo test_insensitive" &&
+ test_when_finished "stop_daemon_delete_repo test_insensitive" &&
git init test_insensitive &&
@@ -930,8 +922,8 @@ test_expect_success CASE_INSENSITIVE_FS 'case insensitive+preserving' '
test_path_is_dir test_insensitive/.git &&
test_path_is_dir test_insensitive/.GIT &&
- # Rename .git using an alternate spelling to verify that that
- # daemon detects it and automatically shuts down.
+ # Rename .git using an alternate spelling to verify that
+ # the daemon detects it and automatically shuts down.
mv test_insensitive/.GIT test_insensitive/.FOO &&
# See [1] above.
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 7c3f6ed994..060e145957 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -105,7 +105,7 @@ verify_mergeheads () {
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 --git a/t/t7605-merge-resolve.sh b/t/t7605-merge-resolve.sh
index 5d56c38546..62d935d31c 100755
--- a/t/t7605-merge-resolve.sh
+++ b/t/t7605-merge-resolve.sh
@@ -4,6 +4,7 @@ test_description='git merge
Testing the resolve strategy.'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t7614-merge-signoff.sh b/t/t7614-merge-signoff.sh
index fee258d4f0..cf96a35e8e 100755
--- a/t/t7614-merge-signoff.sh
+++ b/t/t7614-merge-signoff.sh
@@ -8,6 +8,7 @@ This test runs git merge --signoff and makes sure that it works.
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Setup test files
diff --git a/t/t9003-help-autocorrect.sh b/t/t9003-help-autocorrect.sh
index f00deaf381..14a704d0a8 100755
--- a/t/t9003-help-autocorrect.sh
+++ b/t/t9003-help-autocorrect.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='help.autocorrect finding a match'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
@@ -60,4 +62,10 @@ test_expect_success 'autocorrect can be declined altogether' '
test_line_count = 1 actual
'
+test_expect_success 'autocorrect works in work tree created from bare repo' '
+ git clone --bare . bare.git &&
+ git -C bare.git worktree add ../worktree &&
+ git -C worktree -c help.autocorrect=immediate stauts
+'
+
test_done
diff --git a/t/t9115-git-svn-dcommit-funky-renames.sh b/t/t9115-git-svn-dcommit-funky-renames.sh
index 419f055721..743fbe1fe4 100755
--- a/t/t9115-git-svn-dcommit-funky-renames.sh
+++ b/t/t9115-git-svn-dcommit-funky-renames.sh
@@ -5,7 +5,6 @@
test_description='git svn dcommit can commit renames of files with ugly names'
-TEST_FAILS_SANITIZE_LEAK=true
. ./lib-git-svn.sh
test_expect_success 'load repository with strange names' '
diff --git a/t/t9119-git-svn-info.sh b/t/t9119-git-svn-info.sh
index 8201c3e808..088d1c57a8 100755
--- a/t/t9119-git-svn-info.sh
+++ b/t/t9119-git-svn-info.sh
@@ -28,7 +28,7 @@ test_cmp_info () {
rm -f tmp.expect tmp.actual
}
-quoted_svnrepo="$(echo $svnrepo | sed 's/ /%20/')"
+quoted_svnrepo="$(echo $svnrepo | test_uri_escape)"
test_expect_success 'setup repository and import' '
mkdir info &&
diff --git a/t/t9146-git-svn-empty-dirs.sh b/t/t9146-git-svn-empty-dirs.sh
index 79c26ed69c..09606f1b3c 100755
--- a/t/t9146-git-svn-empty-dirs.sh
+++ b/t/t9146-git-svn-empty-dirs.sh
@@ -4,7 +4,6 @@
test_description='git svn creates empty directories'
-TEST_FAILS_SANITIZE_LEAK=true
. ./lib-git-svn.sh
test_expect_success 'initialize repo' '
diff --git a/t/t9148-git-svn-propset.sh b/t/t9148-git-svn-propset.sh
index 6cc76a07b3..aebb28995e 100755
--- a/t/t9148-git-svn-propset.sh
+++ b/t/t9148-git-svn-propset.sh
@@ -5,7 +5,6 @@
test_description='git svn propset tests'
-TEST_FAILS_SANITIZE_LEAK=true
. ./lib-git-svn.sh
test_expect_success 'setup propset via import' '
diff --git a/t/t9160-git-svn-preserve-empty-dirs.sh b/t/t9160-git-svn-preserve-empty-dirs.sh
index 9cf7a1427a..36c6b1a12f 100755
--- a/t/t9160-git-svn-preserve-empty-dirs.sh
+++ b/t/t9160-git-svn-preserve-empty-dirs.sh
@@ -9,7 +9,6 @@ This test uses git to clone a Subversion repository that contains empty
directories, and checks that corresponding directories are created in the
local Git repository with placeholder files.'
-TEST_FAILS_SANITIZE_LEAK=true
. ./lib-git-svn.sh
GIT_REPO=git-svn-repo
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 43de868b80..d6c0478d98 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -2255,6 +2255,36 @@ test_expect_success 'checkout completes ref names' '
EOF
'
+test_expect_success 'checkout does not match ref names of a different case' '
+ test_completion "git checkout M" ""
+'
+
+test_expect_success 'checkout matches case insensitively with GIT_COMPLETION_IGNORE_CASE' '
+ (
+ GIT_COMPLETION_IGNORE_CASE=1 &&
+ test_completion "git checkout M" <<-\EOF
+ main Z
+ mybranch Z
+ mytag Z
+ EOF
+ )
+'
+
+test_expect_success 'checkout completes pseudo refs' '
+ test_completion "git checkout H" <<-\EOF
+ HEAD Z
+ EOF
+'
+
+test_expect_success 'checkout completes pseudo refs case insensitively with GIT_COMPLETION_IGNORE_CASE' '
+ (
+ GIT_COMPLETION_IGNORE_CASE=1 &&
+ test_completion "git checkout h" <<-\EOF
+ HEAD Z
+ EOF
+ )
+'
+
test_expect_success 'git -C <path> checkout uses the right repo' '
test_completion "git -C subdir -C subsubdir -C .. -C ../otherrepo checkout b" <<-\EOF
branch-in-other Z
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 796093a7b3..7992222703 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -1422,7 +1422,7 @@ test_bool_env () {
BUG "test_bool_env requires two parameters (variable name and default value)"
fi
- git env--helper --type=bool --default="$2" --exit-code "$1"
+ test-tool env-helper --type=bool --default="$2" --exit-code "$1"
ret=$?
case $ret in
0|1) # unset or valid bool value
@@ -1450,72 +1450,6 @@ test_skip_or_die () {
error "$2"
}
-# The following mingw_* functions obey POSIX shell syntax, but are actually
-# bash scripts, and are meant to be used only with bash on Windows.
-
-# A test_cmp function that treats LF and CRLF equal and avoids to fork
-# diff when possible.
-mingw_test_cmp () {
- # Read text into shell variables and compare them. If the results
- # are different, use regular diff to report the difference.
- local test_cmp_a= test_cmp_b=
-
- # When text came from stdin (one argument is '-') we must feed it
- # to diff.
- local stdin_for_diff=
-
- # Since it is difficult to detect the difference between an
- # empty input file and a failure to read the files, we go straight
- # to diff if one of the inputs is empty.
- if test -s "$1" && test -s "$2"
- then
- # regular case: both files non-empty
- mingw_read_file_strip_cr_ test_cmp_a <"$1"
- mingw_read_file_strip_cr_ test_cmp_b <"$2"
- elif test -s "$1" && test "$2" = -
- then
- # read 2nd file from stdin
- mingw_read_file_strip_cr_ test_cmp_a <"$1"
- mingw_read_file_strip_cr_ test_cmp_b
- stdin_for_diff='<<<"$test_cmp_b"'
- elif test "$1" = - && test -s "$2"
- then
- # read 1st file from stdin
- mingw_read_file_strip_cr_ test_cmp_a
- mingw_read_file_strip_cr_ test_cmp_b <"$2"
- stdin_for_diff='<<<"$test_cmp_a"'
- fi
- test -n "$test_cmp_a" &&
- test -n "$test_cmp_b" &&
- test "$test_cmp_a" = "$test_cmp_b" ||
- eval "diff -u \"\$@\" $stdin_for_diff"
-}
-
-# $1 is the name of the shell variable to fill in
-mingw_read_file_strip_cr_ () {
- # Read line-wise using LF as the line separator
- # and use IFS to strip CR.
- local line
- while :
- do
- if IFS=$'\r' read -r -d $'\n' line
- then
- # good
- line=$line$'\n'
- else
- # we get here at EOF, but also if the last line
- # was not terminated by LF; in the latter case,
- # some text was read
- if test -z "$line"
- then
- # EOF, really
- break
- fi
- fi
- eval "$1=\$$1\$line"
- done
-}
-
# Like "env FOO=BAR some-program", but run inside a subshell, which means
# it also works for shell functions (though those functions cannot impact
# the environment outside of the test_env invocation).
@@ -1682,7 +1616,7 @@ test_oid () {
then
BUG "undefined key '$1'"
fi &&
- eval "printf '%s' \"\${$var}\""
+ eval "printf '%s\n' \"\${$var}\""
}
# Insert a slash into an object ID so it can be used to reference a location
@@ -1751,6 +1685,13 @@ test_path_is_hidden () {
return 1
}
+# Poor man's URI escaping. Good enough for the test suite whose trash
+# directory has a space in it. See 93c3fcbe4d4 (git-svn: attempt to
+# mimic SVN 1.7 URL canonicalization, 2012-07-28) for prior art.
+test_uri_escape() {
+ sed 's/ /%20/g'
+}
+
# Check that the given command was invoked as part of the
# trace2-format trace on stdin.
#
@@ -1875,3 +1816,11 @@ test_cmp_config_output () {
sort config-actual >sorted-actual &&
test_cmp sorted-expect sorted-actual
}
+
+# Given a filename, extract its trailing hash as a hex string
+test_trailing_hash () {
+ local file="$1" &&
+ tail -c $(test_oid rawsz) "$file" |
+ test-tool hexdump |
+ sed "s/ //g"
+}
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 6db377f68b..01e88781dd 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -1542,8 +1542,8 @@ then
# Normalize with test_bool_env
passes_sanitize_leak=
- # We need to see TEST_PASSES_SANITIZE_LEAK in "git
- # env--helper" (via test_bool_env)
+ # We need to see TEST_PASSES_SANITIZE_LEAK in "test-tool
+ # env-helper" (via test_bool_env)
export TEST_PASSES_SANITIZE_LEAK
if test_bool_env TEST_PASSES_SANITIZE_LEAK false
then
@@ -1682,7 +1682,7 @@ yes () {
# The GIT_TEST_FAIL_PREREQS code hooks into test_set_prereq(), and
# thus needs to be set up really early, and set an internal variable
# for convenience so the hot test_set_prereq() codepath doesn't need
-# to call "git env--helper" (via test_bool_env). Only do that work
+# to call "test-tool env-helper" (via test_bool_env). Only do that work
# if needed by seeing if GIT_TEST_FAIL_PREREQS is set at all.
GIT_TEST_FAIL_PREREQS_INTERNAL=
if test -n "$GIT_TEST_FAIL_PREREQS"
@@ -1721,7 +1721,7 @@ case $uname_s in
test_set_prereq SED_STRIPS_CR
test_set_prereq GREP_STRIPS_CR
test_set_prereq WINDOWS
- GIT_TEST_CMP=mingw_test_cmp
+ GIT_TEST_CMP="GIT_DIR=/dev/null git diff --no-index --ignore-cr-at-eol --"
;;
*CYGWIN*)
test_set_prereq POSIXPERM
diff --git a/transport-helper.c b/transport-helper.c
index e95267a4ab..3ea7c2bb5a 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -1267,9 +1267,22 @@ static struct ref *get_refs_list_using_list(struct transport *transport,
return ret;
}
+static int get_bundle_uri(struct transport *transport)
+{
+ get_helper(transport);
+
+ if (process_connect(transport, 0)) {
+ do_take_over(transport);
+ return transport->vtable->get_bundle_uri(transport);
+ }
+
+ return -1;
+}
+
static struct transport_vtable vtable = {
.set_option = set_helper_option,
.get_refs_list = get_refs_list,
+ .get_bundle_uri = get_bundle_uri,
.fetch_refs = fetch_refs,
.push_refs = push_refs,
.connect = connect_helper,
diff --git a/transport-internal.h b/transport-internal.h
index c4ca0b733a..90ea749e5c 100644
--- a/transport-internal.h
+++ b/transport-internal.h
@@ -27,6 +27,13 @@ struct transport_vtable {
struct transport_ls_refs_options *transport_options);
/**
+ * Populates the remote side's bundle-uri under protocol v2,
+ * if the "bundle-uri" capability was advertised. Returns 0 if
+ * OK, negative values on error.
+ */
+ int (*get_bundle_uri)(struct transport *transport);
+
+ /**
* Fetch the objects for the given refs. Note that this gets
* an array, and should ignore the list structure.
*
diff --git a/transport.c b/transport.c
index e7b97194c1..77a61a9d7b 100644
--- a/transport.c
+++ b/transport.c
@@ -22,6 +22,7 @@
#include "protocol.h"
#include "object-store.h"
#include "color.h"
+#include "bundle-uri.h"
static int transport_use_color = -1;
static char transport_colors[][COLOR_MAXLEN] = {
@@ -197,7 +198,7 @@ struct git_transport_data {
struct git_transport_options options;
struct child_process *conn;
int fd[2];
- unsigned got_remote_heads : 1;
+ unsigned finished_handshake : 1;
enum protocol_version version;
struct oid_array extra_have;
struct oid_array shallow;
@@ -344,7 +345,7 @@ static struct ref *handshake(struct transport *transport, int for_push,
case protocol_unknown_version:
BUG("unknown protocol version");
}
- data->got_remote_heads = 1;
+ data->finished_handshake = 1;
transport->hash_algo = reader.hash_algo;
if (reader.line_peeked)
@@ -359,6 +360,39 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
return handshake(transport, for_push, options, 1);
}
+static int get_bundle_uri(struct transport *transport)
+{
+ struct git_transport_data *data = transport->data;
+ struct packet_reader reader;
+ int stateless_rpc = transport->stateless_rpc;
+
+ if (!transport->bundles) {
+ CALLOC_ARRAY(transport->bundles, 1);
+ init_bundle_list(transport->bundles);
+ }
+
+ if (!data->finished_handshake) {
+ struct ref *refs = handshake(transport, 0, NULL, 0);
+
+ if (refs)
+ free_refs(refs);
+ }
+
+ /*
+ * "Support" protocol v0 and v2 without bundle-uri support by
+ * silently degrading to a NOOP.
+ */
+ if (!server_supports_v2("bundle-uri"))
+ return 0;
+
+ packet_reader_init(&reader, data->fd[0], NULL, 0,
+ PACKET_READ_CHOMP_NEWLINE |
+ PACKET_READ_GENTLE_ON_EOF);
+
+ return get_remote_bundle_uri(data->fd[1], &reader,
+ transport->bundles, stateless_rpc);
+}
+
static int fetch_refs_via_pack(struct transport *transport,
int nr_heads, struct ref **to_fetch)
{
@@ -394,7 +428,7 @@ static int fetch_refs_via_pack(struct transport *transport,
args.negotiation_tips = data->options.negotiation_tips;
args.reject_shallow_remote = transport->smart_options->reject_shallow;
- if (!data->got_remote_heads) {
+ if (!data->finished_handshake) {
int i;
int must_list_refs = 0;
for (i = 0; i < nr_heads; i++) {
@@ -434,7 +468,7 @@ static int fetch_refs_via_pack(struct transport *transport,
to_fetch, nr_heads, &data->shallow,
&transport->pack_lockfiles, data->version);
- data->got_remote_heads = 0;
+ data->finished_handshake = 0;
data->options.self_contained_and_connected =
args.self_contained_and_connected;
data->options.connectivity_checked = args.connectivity_checked;
@@ -819,7 +853,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
if (transport_color_config() < 0)
return -1;
- if (!data->got_remote_heads)
+ if (!data->finished_handshake)
get_refs_via_connect(transport, 1, NULL);
memset(&args, 0, sizeof(args));
@@ -867,7 +901,7 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
else
ret = finish_connect(data->conn);
data->conn = NULL;
- data->got_remote_heads = 0;
+ data->finished_handshake = 0;
return ret;
}
@@ -887,7 +921,7 @@ static int disconnect_git(struct transport *transport)
{
struct git_transport_data *data = transport->data;
if (data->conn) {
- if (data->got_remote_heads && !transport->stateless_rpc)
+ if (data->finished_handshake && !transport->stateless_rpc)
packet_flush(data->fd[1]);
close(data->fd[0]);
if (data->fd[1] >= 0)
@@ -902,6 +936,7 @@ static int disconnect_git(struct transport *transport)
static struct transport_vtable taken_over_vtable = {
.get_refs_list = get_refs_via_connect,
+ .get_bundle_uri = get_bundle_uri,
.fetch_refs = fetch_refs_via_pack,
.push_refs = git_transport_push,
.disconnect = disconnect_git
@@ -921,7 +956,7 @@ void transport_take_over(struct transport *transport,
data->conn = child;
data->fd[0] = data->conn->out;
data->fd[1] = data->conn->in;
- data->got_remote_heads = 0;
+ data->finished_handshake = 0;
transport->data = data;
transport->vtable = &taken_over_vtable;
@@ -1054,6 +1089,7 @@ static struct transport_vtable bundle_vtable = {
static struct transport_vtable builtin_smart_vtable = {
.get_refs_list = get_refs_via_connect,
+ .get_bundle_uri = get_bundle_uri,
.fetch_refs = fetch_refs_via_pack,
.push_refs = git_transport_push,
.connect = connect_git,
@@ -1068,6 +1104,9 @@ struct transport *transport_get(struct remote *remote, const char *url)
ret->progress = isatty(2);
string_list_init_dup(&ret->pack_lockfiles);
+ CALLOC_ARRAY(ret->bundles, 1);
+ init_bundle_list(ret->bundles);
+
if (!remote)
BUG("No remote provided to transport_get()");
@@ -1118,7 +1157,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
ret->smart_options = &(data->options);
data->conn = NULL;
- data->got_remote_heads = 0;
+ data->finished_handshake = 0;
} else {
/* Unknown protocol in URL. Pass to external handler. */
int len = external_specification_len(url);
@@ -1482,6 +1521,34 @@ int transport_fetch_refs(struct transport *transport, struct ref *refs)
return rc;
}
+int transport_get_remote_bundle_uri(struct transport *transport)
+{
+ int value = 0;
+ const struct transport_vtable *vtable = transport->vtable;
+
+ /* Check config only once. */
+ if (transport->got_remote_bundle_uri)
+ return 0;
+ transport->got_remote_bundle_uri = 1;
+
+ /*
+ * Don't request bundle-uri from the server unless configured to
+ * do so by the transfer.bundleURI=true config option.
+ */
+ if (git_config_get_bool("transfer.bundleuri", &value) || !value)
+ return 0;
+
+ if (!transport->bundles->baseURI)
+ transport->bundles->baseURI = xstrdup(transport->url);
+
+ if (!vtable->get_bundle_uri)
+ return error(_("bundle-uri operation not supported by protocol"));
+
+ if (vtable->get_bundle_uri(transport) < 0)
+ return error(_("could not retrieve server-advertised bundle-uri list"));
+ return 0;
+}
+
void transport_unlock_pack(struct transport *transport, unsigned int flags)
{
int in_signal_handler = !!(flags & TRANSPORT_UNLOCK_PACK_IN_SIGNAL_HANDLER);
@@ -1512,6 +1579,8 @@ int transport_disconnect(struct transport *transport)
ret = transport->vtable->disconnect(transport);
if (transport->got_remote_refs)
free_refs((void *)transport->remote_refs);
+ clear_bundle_list(transport->bundles);
+ free(transport->bundles);
free(transport);
return ret;
}
diff --git a/transport.h b/transport.h
index b5bf7b3e70..85150f504f 100644
--- a/transport.h
+++ b/transport.h
@@ -62,6 +62,7 @@ enum transport_family {
TRANSPORT_FAMILY_IPV6
};
+struct bundle_list;
struct transport {
const struct transport_vtable *vtable;
@@ -76,6 +77,18 @@ struct transport {
*/
unsigned got_remote_refs : 1;
+ /**
+ * Indicates whether we already called get_bundle_uri_list(); set by
+ * transport.c::transport_get_remote_bundle_uri().
+ */
+ unsigned got_remote_bundle_uri : 1;
+
+ /*
+ * The results of "command=bundle-uri", if both sides support
+ * the "bundle-uri" capability.
+ */
+ struct bundle_list *bundles;
+
/*
* Transports that call take-over destroys the data specific to
* the transport type while doing so, and cannot be reused.
@@ -281,6 +294,12 @@ void transport_ls_refs_options_release(struct transport_ls_refs_options *opts);
const struct ref *transport_get_remote_refs(struct transport *transport,
struct transport_ls_refs_options *transport_options);
+/**
+ * Retrieve bundle URI(s) from a remote. Populates "struct
+ * transport"'s "bundle_uri" and "got_remote_bundle_uri".
+ */
+int transport_get_remote_bundle_uri(struct transport *transport);
+
/*
* Fetch the hash algorithm used by a remote.
*
diff --git a/unpack-trees.c b/unpack-trees.c
index 8a762aa077..d1d1b0f319 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -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
@@ -71,7 +70,7 @@ static const char *unpack_plumbing_errors[NB_UNPACK_TREES_WARNING_TYPES] = {
? ((o)->msgs[(type)]) \
: (unpack_plumbing_errors[(type)]) )
-static const char *super_prefixed(const char *path)
+static const char *super_prefixed(const char *path, const char *super_prefix)
{
/*
* It is necessary and sufficient to have two static buffers
@@ -83,7 +82,6 @@ static const char *super_prefixed(const char *path)
static unsigned idx = ARRAY_SIZE(buf) - 1;
if (super_prefix_len < 0) {
- const char *super_prefix = get_super_prefix();
if (!super_prefix) {
super_prefix_len = 0;
} else {
@@ -236,7 +234,8 @@ static int add_rejected_path(struct unpack_trees_options *o,
return -1;
if (!o->show_all_errors)
- return error(ERRORMSG(o, e), super_prefixed(path));
+ return error(ERRORMSG(o, e), super_prefixed(path,
+ o->super_prefix));
/*
* Otherwise, insert in a list for future display by
@@ -263,7 +262,8 @@ static void display_error_msgs(struct unpack_trees_options *o)
error_displayed = 1;
for (i = 0; i < rejects->nr; i++)
strbuf_addf(&path, "\t%s\n", rejects->items[i].string);
- error(ERRORMSG(o, e), super_prefixed(path.buf));
+ error(ERRORMSG(o, e), super_prefixed(path.buf,
+ o->super_prefix));
strbuf_release(&path);
}
string_list_clear(rejects, 0);
@@ -290,7 +290,8 @@ static void display_warning_msgs(struct unpack_trees_options *o)
warning_displayed = 1;
for (i = 0; i < rejects->nr; i++)
strbuf_addf(&path, "\t%s\n", rejects->items[i].string);
- warning(ERRORMSG(o, e), super_prefixed(path.buf));
+ warning(ERRORMSG(o, e), super_prefixed(path.buf,
+ o->super_prefix));
strbuf_release(&path);
}
string_list_clear(rejects, 0);
@@ -312,7 +313,8 @@ static int check_submodule_move_head(const struct cache_entry *ce,
if (o->reset)
flags |= SUBMODULE_MOVE_HEAD_FORCE;
- if (submodule_move_head(ce->name, old_id, new_id, flags))
+ if (submodule_move_head(ce->name, o->super_prefix, old_id, new_id,
+ flags))
return add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);
return 0;
}
@@ -415,6 +417,7 @@ static int check_updates(struct unpack_trees_options *o,
int i, pc_workers, pc_threshold;
trace_performance_enter();
+ state.super_prefix = o->super_prefix;
state.force = 1;
state.quiet = 1;
state.refresh_cache = 1;
@@ -445,7 +448,7 @@ static int check_updates(struct unpack_trees_options *o,
if (ce->ce_flags & CE_WT_REMOVE) {
display_progress(progress, ++cnt);
- unlink_entry(ce);
+ unlink_entry(ce, o->super_prefix);
}
}
@@ -1877,7 +1880,8 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
prepare_repo_settings(repo);
if (repo->settings.command_requires_full_index) {
ensure_full_index(o->src_index);
- ensure_full_index(o->dst_index);
+ if (o->dst_index)
+ ensure_full_index(o->dst_index);
}
if (o->reset == UNPACK_RESET_OVERWRITE_UNTRACKED &&
@@ -1901,7 +1905,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
populate_from_existing_patterns(o, &pl);
}
- memset(&o->result, 0, sizeof(o->result));
+ index_state_init(&o->result);
o->result.initialized = 1;
o->result.timestamp.sec = o->src_index->timestamp.sec;
o->result.timestamp.nsec = o->src_index->timestamp.nsec;
@@ -2959,8 +2963,8 @@ int bind_merge(const struct cache_entry * const *src,
if (a && old)
return o->quiet ? -1 :
error(ERRORMSG(o, ERROR_BIND_OVERLAP),
- super_prefixed(a->name),
- super_prefixed(old->name));
+ super_prefixed(a->name, o->super_prefix),
+ super_prefixed(old->name, o->super_prefix));
if (!a)
return keep_entry(old, o);
else
@@ -3021,7 +3025,7 @@ int stash_worktree_untracked_merge(const struct cache_entry * const *src,
if (worktree && untracked)
return error(_("worktree and untracked commit have duplicate entries: %s"),
- super_prefixed(worktree->name));
+ super_prefixed(worktree->name, o->super_prefix));
return merged_entry(worktree ? worktree : untracked, NULL, o);
}
diff --git a/unpack-trees.h b/unpack-trees.h
index 6ab0d74c84..3a7b3e5f00 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -75,6 +75,7 @@ struct unpack_trees_options {
skip_cache_tree_update;
enum unpack_trees_reset_type reset;
const char *prefix;
+ const char *super_prefix;
int cache_bottom;
struct pathspec *pathspec;
merge_fn_t fn;
diff --git a/urlmatch.c b/urlmatch.c
index b615adc923..620a648efc 100644
--- a/urlmatch.c
+++ b/urlmatch.c
@@ -209,7 +209,7 @@ static char *url_normalize_1(const char *url, struct url_info *out_info, char al
*/
if (!url_len || strchr(":/?#", *url)) {
/* Missing host invalid for all URL schemes except file */
- if (strncmp(norm.buf, "file:", 5)) {
+ if (!starts_with(norm.buf, "file:")) {
if (out_info) {
out_info->url = NULL;
out_info->err = _("missing host and scheme is not 'file:'");
@@ -268,11 +268,11 @@ static char *url_normalize_1(const char *url, struct url_info *out_info, char al
if (url == slash_ptr) {
/* Skip ":" port with no number, it's same as default */
} else if (slash_ptr - url == 2 &&
- !strncmp(norm.buf, "http:", 5) &&
+ starts_with(norm.buf, "http:") &&
!strncmp(url, "80", 2)) {
/* Skip http :80 as it's the default */
} else if (slash_ptr - url == 3 &&
- !strncmp(norm.buf, "https:", 6) &&
+ starts_with(norm.buf, "https:") &&
!strncmp(url, "443", 3)) {
/* Skip https :443 as it's the default */
} else {
diff --git a/userdiff.c b/userdiff.c
index 151d9a5278..d71b82feb7 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -315,7 +315,8 @@ struct find_by_namelen_data {
};
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;
@@ -412,7 +413,7 @@ struct userdiff_driver *userdiff_find_by_path(struct index_state *istate,
check = attr_check_initl("diff", NULL);
if (!path)
return NULL;
- git_check_attr(istate, path, check);
+ git_check_attr(istate, NULL, path, check);
if (ATTR_TRUE(check->items[0].value))
return &driver_true;
diff --git a/utf8.c b/utf8.c
index de4ce5c0e6..6a0dd25b0f 100644
--- a/utf8.c
+++ b/utf8.c
@@ -206,26 +206,34 @@ int utf8_width(const char **start, size_t *remainder_p)
* string, assuming that the string is utf8. Returns strlen() instead
* if the string does not look like a valid utf8 string.
*/
-int utf8_strnwidth(const char *string, int len, int skip_ansi)
+int utf8_strnwidth(const char *string, size_t len, int skip_ansi)
{
- int width = 0;
const char *orig = string;
+ size_t width = 0;
- if (len == -1)
- len = strlen(string);
while (string && string < orig + len) {
- int skip;
+ int glyph_width;
+ size_t skip;
+
while (skip_ansi &&
(skip = display_mode_esc_sequence_len(string)) != 0)
string += skip;
- width += utf8_width(&string, NULL);
+
+ glyph_width = utf8_width(&string, NULL);
+ if (glyph_width > 0)
+ width += glyph_width;
}
- return string ? width : len;
+
+ /*
+ * TODO: fix the interface of this function and `utf8_strwidth()` to
+ * return `size_t` instead of `int`.
+ */
+ return cast_size_t_to_int(string ? width : len);
}
int utf8_strwidth(const char *string)
{
- return utf8_strnwidth(string, -1, 0);
+ return utf8_strnwidth(string, strlen(string), 0);
}
int is_utf8(const char *text)
@@ -357,51 +365,52 @@ void strbuf_add_wrapped_bytes(struct strbuf *buf, const char *data, int len,
void strbuf_utf8_replace(struct strbuf *sb_src, int pos, int width,
const char *subst)
{
- struct strbuf sb_dst = STRBUF_INIT;
- char *src = sb_src->buf;
- char *end = src + sb_src->len;
- char *dst;
- int w = 0, subst_len = 0;
+ const char *src = sb_src->buf, *end = sb_src->buf + sb_src->len;
+ struct strbuf dst;
+ int w = 0;
- if (subst)
- subst_len = strlen(subst);
- strbuf_grow(&sb_dst, sb_src->len + subst_len);
- dst = sb_dst.buf;
+ strbuf_init(&dst, sb_src->len);
while (src < end) {
- char *old;
+ const char *old;
+ int glyph_width;
size_t n;
while ((n = display_mode_esc_sequence_len(src))) {
- memcpy(dst, src, n);
+ strbuf_add(&dst, src, n);
src += n;
- dst += n;
}
if (src >= end)
break;
old = src;
- n = utf8_width((const char**)&src, NULL);
- if (!src) /* broken utf-8, do nothing */
+ glyph_width = utf8_width((const char**)&src, NULL);
+ if (!src) /* broken utf-8, do nothing */
goto out;
- if (n && w >= pos && w < pos + width) {
+
+ /*
+ * In case we see a control character we copy it into the
+ * buffer, but don't add it to the width.
+ */
+ if (glyph_width < 0)
+ glyph_width = 0;
+
+ if (glyph_width && w >= pos && w < pos + width) {
if (subst) {
- memcpy(dst, subst, subst_len);
- dst += subst_len;
+ strbuf_addstr(&dst, subst);
subst = NULL;
}
- w += n;
- continue;
+ } else {
+ strbuf_add(&dst, old, src - old);
}
- memcpy(dst, old, src - old);
- dst += src - old;
- w += n;
+
+ w += glyph_width;
}
- strbuf_setlen(&sb_dst, dst - sb_dst.buf);
- strbuf_swap(sb_src, &sb_dst);
+
+ strbuf_swap(sb_src, &dst);
out:
- strbuf_release(&sb_dst);
+ strbuf_release(&dst);
}
/*
@@ -796,7 +805,7 @@ int skip_utf8_bom(char **text, size_t len)
void strbuf_utf8_align(struct strbuf *buf, align_type position, unsigned int width,
const char *s)
{
- int slen = strlen(s);
+ size_t slen = strlen(s);
int display_len = utf8_strnwidth(s, slen, 0);
int utf8_compensation = slen - display_len;
diff --git a/utf8.h b/utf8.h
index 9a16c8679d..b68efef6f4 100644
--- a/utf8.h
+++ b/utf8.h
@@ -7,7 +7,7 @@ typedef unsigned int ucs_char_t; /* assuming 32bit int */
size_t display_mode_esc_sequence_len(const char *s);
int utf8_width(const char **start, size_t *remainder_p);
-int utf8_strnwidth(const char *string, int len, int skip_ansi);
+int utf8_strnwidth(const char *string, size_t len, int skip_ansi);
int utf8_strwidth(const char *string);
int is_utf8(const char *text);
int is_encoding_utf8(const char *name);
diff --git a/ws.c b/ws.c
index 6e69877f25..da3d0e28cb 100644
--- a/ws.c
+++ b/ws.c
@@ -29,6 +29,7 @@ unsigned parse_whitespace_rule(const char *string)
int i;
size_t len;
const char *ep;
+ const char *arg;
int negated = 0;
string = string + strspn(string, ", \t\n\r");
@@ -52,15 +53,15 @@ unsigned parse_whitespace_rule(const char *string)
rule |= whitespace_rule_names[i].rule_bits;
break;
}
- if (strncmp(string, "tabwidth=", 9) == 0) {
- unsigned tabwidth = atoi(string + 9);
+ if (skip_prefix(string, "tabwidth=", &arg)) {
+ unsigned tabwidth = atoi(arg);
if (0 < tabwidth && tabwidth < 0100) {
rule &= ~WS_TAB_WIDTH_MASK;
rule |= tabwidth;
}
else
warning("tabwidth %.*s out of range",
- (int)(len - 9), string + 9);
+ (int)(ep - arg), arg);
}
string = ep;
}
@@ -78,7 +79,7 @@ unsigned whitespace_rule(struct index_state *istate, const char *pathname)
if (!attr_whitespace_rule)
attr_whitespace_rule = attr_check_initl("whitespace", NULL);
- git_check_attr(istate, pathname, attr_whitespace_rule);
+ git_check_attr(istate, NULL, pathname, attr_whitespace_rule);
value = attr_whitespace_rule->items[0].value;
if (ATTR_TRUE(value)) {
/* true (whitespace) */
@@ -252,7 +253,7 @@ unsigned ws_check(const char *line, int len, unsigned ws_rule)
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 --git a/wt-status.c b/wt-status.c
index 5813174896..3162241a57 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -18,8 +18,10 @@
#include "worktree.h"
#include "lockfile.h"
#include "sequencer.h"
+#include "fsmonitor-settings.h"
#define AB_DELAY_WARNING_IN_MS (2 * 1000)
+#define UF_DELAY_WARNING_IN_MS (2 * 1000)
static const char cut_line[] =
"------------------------ >8 ------------------------\n";
@@ -438,7 +440,7 @@ static char short_submodule_status(struct wt_status_change_data *d)
}
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 +527,7 @@ static int unmerged_mask(struct index_state *istate, const char *path)
}
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;
@@ -1205,6 +1207,13 @@ static void wt_longstatus_print_tracking(struct wt_status *s)
strbuf_release(&sb);
}
+static int uf_was_slow(struct wt_status *s)
+{
+ if (getenv("GIT_TEST_UF_DELAY_WARNING"))
+ s->untracked_in_ms = 3250;
+ return UF_DELAY_WARNING_IN_MS < s->untracked_in_ms;
+}
+
static void show_merge_in_progress(struct wt_status *s,
const char *color)
{
@@ -1814,6 +1823,7 @@ static void wt_longstatus_print(struct wt_status *s)
{
const char *branch_color = color(WT_STATUS_ONBRANCH, s);
const char *branch_status_color = color(WT_STATUS_HEADER, s);
+ enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(s->repo);
if (s->branch) {
const char *on_what = _("On branch ");
@@ -1870,13 +1880,21 @@ static void wt_longstatus_print(struct wt_status *s)
wt_longstatus_print_other(s, &s->untracked, _("Untracked files"), "add");
if (s->show_ignored_mode)
wt_longstatus_print_other(s, &s->ignored, _("Ignored files"), "add -f");
- if (advice_enabled(ADVICE_STATUS_U_OPTION) && 2000 < s->untracked_in_ms) {
+ if (advice_enabled(ADVICE_STATUS_U_OPTION) && uf_was_slow(s)) {
status_printf_ln(s, GIT_COLOR_NORMAL, "%s", "");
+ if (fsm_mode > FSMONITOR_MODE_DISABLED) {
+ status_printf_ln(s, GIT_COLOR_NORMAL,
+ _("It took %.2f seconds to enumerate untracked files,\n"
+ "but the results were cached, and subsequent runs may be faster."),
+ s->untracked_in_ms / 1000.0);
+ } else {
+ status_printf_ln(s, GIT_COLOR_NORMAL,
+ _("It took %.2f seconds to enumerate untracked files."),
+ s->untracked_in_ms / 1000.0);
+ }
status_printf_ln(s, GIT_COLOR_NORMAL,
- _("It took %.2f seconds to enumerate untracked files. 'status -uno'\n"
- "may speed it up, but you have to be careful not to forget to add\n"
- "new files yourself (see 'git help status')."),
- s->untracked_in_ms / 1000.0);
+ _("See 'git help status' for information on how to improve this."));
+ status_printf_ln(s, GIT_COLOR_NORMAL, "%s", "");
}
} else if (s->committable)
status_printf_ln(s, GIT_COLOR_NORMAL, _("Untracked files not listed%s"),
diff --git a/xdiff/xdiffi.c b/xdiff/xdiffi.c
index 32652ded2d..344c2dfc3e 100644
--- a/xdiff/xdiffi.c
+++ b/xdiff/xdiffi.c
@@ -973,7 +973,7 @@ void xdl_free_script(xdchange_t *xscr) {
}
}
-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 --git a/xdiff/xemit.c b/xdiff/xemit.c
index c4ccd68d47..75f0fe4986 100644
--- a/xdiff/xemit.c
+++ b/xdiff/xemit.c
@@ -95,7 +95,7 @@ xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg)
}
-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 @@ static long match_func_rec(xdfile_t *xdf, xdemitconf_t const *xecfg, long ri,
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);
}