aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.clang-format5
-rw-r--r--.github/workflows/main.yml14
-rw-r--r--Documentation/Makefile1
-rw-r--r--Documentation/RelNotes/2.46.1.txt37
-rw-r--r--Documentation/RelNotes/2.47.0.txt51
-rw-r--r--Documentation/fsck-msgids.txt6
-rw-r--r--Documentation/git-diff-tree.txt2
-rw-r--r--Documentation/git-multi-pack-index.txt11
-rw-r--r--Documentation/git-refs.txt13
-rw-r--r--Documentation/git-submodule.txt10
-rw-r--r--Documentation/git-svn.txt14
-rw-r--r--Documentation/gittutorial.txt2
-rw-r--r--Documentation/howto/maintain-git.txt4
-rw-r--r--Documentation/technical/multi-pack-index.txt103
-rw-r--r--Documentation/technical/platform-support.txt190
-rw-r--r--Makefile3
-rw-r--r--add-patch.c3
-rw-r--r--bisect.c3
-rw-r--r--builtin/am.c9
-rw-r--r--builtin/bisect.c4
-rw-r--r--builtin/branch.c7
-rw-r--r--builtin/bugreport.c2
-rw-r--r--builtin/bundle.c5
-rw-r--r--builtin/checkout.c4
-rw-r--r--builtin/clone.c12
-rw-r--r--builtin/commit.c7
-rw-r--r--builtin/config.c16
-rw-r--r--builtin/count-objects.c2
-rw-r--r--builtin/describe.c2
-rw-r--r--builtin/diff-tree.c13
-rw-r--r--builtin/diff.c6
-rw-r--r--builtin/fast-export.c19
-rw-r--r--builtin/fast-import.c12
-rw-r--r--builtin/fetch.c3
-rw-r--r--builtin/fsck.c23
-rw-r--r--builtin/gc.c9
-rw-r--r--builtin/hook.c2
-rw-r--r--builtin/log.c14
-rw-r--r--builtin/merge.c2
-rw-r--r--builtin/mktag.c3
-rw-r--r--builtin/multi-pack-index.c2
-rw-r--r--builtin/name-rev.c2
-rw-r--r--builtin/notes.c11
-rw-r--r--builtin/pack-objects.c5
-rw-r--r--builtin/rebase.c3
-rw-r--r--builtin/receive-pack.c12
-rw-r--r--builtin/refs.c34
-rw-r--r--builtin/remote.c8
-rw-r--r--builtin/repack.c9
-rw-r--r--builtin/replace.c1
-rw-r--r--builtin/rev-parse.c4
-rw-r--r--builtin/show-branch.c8
-rw-r--r--builtin/show-ref.c3
-rw-r--r--builtin/submodule--helper.c49
-rw-r--r--builtin/update-index.c4
-rw-r--r--builtin/worktree.c7
-rw-r--r--bulk-checkin.c2
-rw-r--r--bundle.c7
-rwxr-xr-xci/run-build-and-tests.sh2
-rw-r--r--commit-graph.c1
-rw-r--r--commit.c2
-rw-r--r--compat/fsmonitor/fsm-ipc-darwin.c2
-rw-r--r--compat/precompose_utf8.c1
-rw-r--r--config.c228
-rw-r--r--config.h285
-rw-r--r--connect.c2
-rw-r--r--credential.c2
-rw-r--r--csum-file.c2
-rw-r--r--csum-file.h10
-rw-r--r--daemon.c2
-rw-r--r--delta-islands.c2
-rw-r--r--diff.c16
-rw-r--r--editor.c15
-rw-r--r--editor.h5
-rw-r--r--environment.c1
-rw-r--r--environment.h1
-rw-r--r--fetch-pack.c2
-rw-r--r--fsck.c125
-rw-r--r--fsck.h76
-rw-r--r--fsmonitor.c2
-rwxr-xr-xgit-submodule.sh82
-rwxr-xr-xgit-svn.perl51
-rw-r--r--git.c13
-rw-r--r--gpg-interface.c2
-rw-r--r--graph.c2
-rw-r--r--help.c2
-rw-r--r--hook.c21
-rw-r--r--hook.h13
-rw-r--r--http-backend.c4
-rw-r--r--imap-send.c2
-rw-r--r--log-tree.c2
-rw-r--r--ls-refs.c4
-rw-r--r--mailinfo.c2
-rw-r--r--merge-ll.c2
-rw-r--r--merge-ort.c3
-rw-r--r--midx-write.c326
-rw-r--r--midx.c399
-rw-r--r--midx.h26
-rw-r--r--negotiator/default.c2
-rw-r--r--negotiator/skipping.c2
-rw-r--r--notes.c2
-rw-r--r--object-file.c10
-rw-r--r--object-name.c102
-rw-r--r--object.c9
-rw-r--r--packfile.c21
-rw-r--r--packfile.h4
-rw-r--r--parallel-checkout.c2
-rw-r--r--path.c97
-rw-r--r--path.h170
-rw-r--r--perl/Git/SVN.pm2
-rw-r--r--protocol.c2
-rw-r--r--pseudo-merge.c1
-rw-r--r--range-diff.c6
-rw-r--r--reachable.c2
-rw-r--r--read-cache.c136
-rw-r--r--ref-filter.c17
-rw-r--r--reflog.c1
-rw-r--r--refs.c25
-rw-r--r--refs.h10
-rw-r--r--refs/debug.c11
-rw-r--r--refs/files-backend.c132
-rw-r--r--refs/iterator.c4
-rw-r--r--refs/packed-backend.c10
-rw-r--r--refs/ref-cache.c5
-rw-r--r--refs/ref-cache.h2
-rw-r--r--refs/refs-internal.h7
-rw-r--r--refs/reftable-backend.c19
-rw-r--r--reftable/reftable-tests.h1
-rw-r--r--reftable/stack.c231
-rw-r--r--reftable/stack_test.c142
-rw-r--r--remote.c6
-rw-r--r--replace-object.c1
-rw-r--r--rerere.c6
-rw-r--r--reset.c2
-rw-r--r--revision.c4
-rw-r--r--sequencer.c73
-rw-r--r--server-info.c2
-rw-r--r--setup.c58
-rw-r--r--shallow.c2
-rw-r--r--sideband.c2
-rw-r--r--submodule-config.c18
-rw-r--r--submodule.c22
-rw-r--r--t/README6
-rw-r--r--t/helper/test-advise.c2
-rw-r--r--t/helper/test-config.c2
-rw-r--r--t/helper/test-example-tap.c35
-rw-r--r--t/helper/test-hashmap.c98
-rw-r--r--t/helper/test-read-midx.c24
-rw-r--r--t/helper/test-ref-store.c2
-rw-r--r--t/helper/test-reftable.c1
-rw-r--r--t/helper/test-userdiff.c2
-rw-r--r--t/lib-bitmap.sh6
-rw-r--r--t/lib-midx.sh28
-rwxr-xr-xt/t0011-hashmap.sh260
-rwxr-xr-xt/t0033-safe-directory.sh178
-rwxr-xr-xt/t0080-unit-test-output.sh60
-rwxr-xr-xt/t0210-trace2-normal.sh2
-rwxr-xr-xt/t0410-partial-clone.sh2
-rwxr-xr-xt/t0602-reffiles-fsck.sh92
-rwxr-xr-xt/t0610-reftable-basics.sh21
-rwxr-xr-xt/t1001-read-tree-m-2way.sh2
-rwxr-xr-xt/t1006-cat-file.sh1
-rwxr-xr-xt/t1050-large.sh1
-rwxr-xr-xt/t1450-fsck.sh1
-rwxr-xr-xt/t1601-index-bogus.sh2
-rwxr-xr-xt/t3206-range-diff.sh52
-rwxr-xr-xt/t3310-notes-merge-manual-resolve.sh1
-rwxr-xr-xt/t3311-notes-merge-fanout.sh1
-rwxr-xr-xt/t3404-rebase-interactive.sh1
-rwxr-xr-xt/t3435-rebase-gpg-sign.sh1
-rwxr-xr-xt/t3507-cherry-pick-conflict.sh1
-rwxr-xr-xt/t3510-cherry-pick-sequence.sh1
-rwxr-xr-xt/t3705-add-sparse-checkout.sh1
-rwxr-xr-xt/t4013-diff-various.sh1
-rwxr-xr-xt/t4014-format-patch.sh1
-rwxr-xr-xt/t4018-diff-funcname.sh1
-rwxr-xr-xt/t4030-diff-textconv.sh2
-rwxr-xr-xt/t4042-diff-textconv-caching.sh2
-rwxr-xr-xt/t4048-diff-combined-binary.sh1
-rwxr-xr-xt/t4064-diff-oidfind.sh2
-rwxr-xr-xt/t4065-diff-anchored.sh1
-rwxr-xr-xt/t4068-diff-symmetric-merge-base.sh1
-rwxr-xr-xt/t4069-remerge-diff.sh36
-rwxr-xr-xt/t4108-apply-threeway.sh1
-rwxr-xr-xt/t4129-apply-samemode.sh2
-rwxr-xr-xt/t4209-log-pickaxe.sh2
-rwxr-xr-xt/t5310-pack-bitmaps.sh4
-rwxr-xr-xt/t5313-pack-bounds-checks.sh8
-rwxr-xr-xt/t5319-multi-pack-index.sh30
-rwxr-xr-xt/t5326-multi-pack-bitmaps.sh4
-rwxr-xr-xt/t5327-multi-pack-bitmaps-rev.sh6
-rwxr-xr-xt/t5332-multi-pack-reuse.sh2
-rwxr-xr-xt/t5334-incremental-multi-pack-index.sh46
-rwxr-xr-xt/t5509-fetch-push-namespaces.sh1
-rwxr-xr-xt/t5523-push-upstream.sh4
-rwxr-xr-xt/t5572-pull-submodule.sh1
-rwxr-xr-xt/t5802-connect-helper.sh2
-rwxr-xr-xt/t5814-proto-disable-ext.sh2
-rwxr-xr-xt/t5815-submodule-protos.sh2
-rwxr-xr-xt/t6020-bundle-misc.sh32
-rwxr-xr-xt/t6421-merge-partial-clone.sh1
-rwxr-xr-xt/t6428-merge-conflicts-sparse.sh1
-rwxr-xr-xt/t7004-tag.sh1144
-rwxr-xr-xt/t7008-filter-branch-null-sha1.sh1
-rwxr-xr-xt/t7030-verify-tag.sh1
-rwxr-xr-xt/t7418-submodule-sparse-gitmodules.sh1
-rwxr-xr-xt/t7424-submodule-mixed-ref-formats.sh144
-rwxr-xr-xt/t7700-repack.sh48
-rwxr-xr-xt/t7817-grep-sparse-checkout.sh1
-rwxr-xr-xt/t9300-fast-import.sh1
-rwxr-xr-xt/t9304-fast-import-marks.sh2
-rwxr-xr-xt/t9351-fast-export-anonymize.sh1
-rw-r--r--t/unit-tests/t-ctype.c4
-rw-r--r--t/unit-tests/t-example-decorate.c24
-rw-r--r--t/unit-tests/t-hashmap.c361
-rw-r--r--t/unit-tests/t-reftable-basics.c228
-rw-r--r--t/unit-tests/t-reftable-readwrite.c (renamed from reftable/readwrite_test.c)441
-rw-r--r--t/unit-tests/t-strvec.c416
-rw-r--r--t/unit-tests/test-lib.c36
-rw-r--r--t/unit-tests/test-lib.h20
-rw-r--r--trailer.c2
-rw-r--r--transport.c2
-rw-r--r--unpack-trees.c2
-rw-r--r--upload-pack.c8
-rw-r--r--userdiff.c38
-rw-r--r--userdiff.h4
-rw-r--r--versioncmp.c2
-rw-r--r--walker.c1
-rw-r--r--worktree.c4
-rw-r--r--wt-status.c14
230 files changed, 5238 insertions, 2741 deletions
diff --git a/.clang-format b/.clang-format
index 0b82f3c776..41969eca4b 100644
--- a/.clang-format
+++ b/.clang-format
@@ -196,6 +196,11 @@ ForEachMacros:
- 'strmap_for_each_entry'
- 'strset_for_each_entry'
+# A list of macros that should be interpreted as conditionals instead of as
+# function calls.
+IfMacros:
+ - 'if_test'
+
# The maximum number of consecutive empty lines to keep.
MaxEmptyLinesToKeep: 1
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 13cc0fe807..1ee0433acc 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -181,16 +181,12 @@ jobs:
repository: 'microsoft/vcpkg'
path: 'compat/vcbuild/vcpkg'
- name: download vcpkg artifacts
- shell: powershell
- run: |
- $urlbase = "https://dev.azure.com/git/git/_apis/build/builds"
- $id = ((Invoke-WebRequest -UseBasicParsing "${urlbase}?definitions=9&statusFilter=completed&resultFilter=succeeded&`$top=1").content | ConvertFrom-JSON).value[0].id
- $downloadUrl = ((Invoke-WebRequest -UseBasicParsing "${urlbase}/$id/artifacts").content | ConvertFrom-JSON).value[0].resource.downloadUrl
- (New-Object Net.WebClient).DownloadFile($downloadUrl, "compat.zip")
- Expand-Archive compat.zip -DestinationPath . -Force
- Remove-Item compat.zip
+ uses: git-for-windows/get-azure-pipelines-artifact@v0
+ with:
+ repository: git/git
+ definitionId: 9
- name: add msbuild to PATH
- uses: microsoft/setup-msbuild@v1
+ uses: microsoft/setup-msbuild@v2
- name: copy dlls to root
shell: cmd
run: compat\vcbuild\vcpkg_copy_dlls.bat release
diff --git a/Documentation/Makefile b/Documentation/Makefile
index 1bd23fbeef..0f55baa252 100644
--- a/Documentation/Makefile
+++ b/Documentation/Makefile
@@ -118,6 +118,7 @@ TECH_DOCS += technical/multi-pack-index
TECH_DOCS += technical/pack-heuristics
TECH_DOCS += technical/parallel-checkout
TECH_DOCS += technical/partial-clone
+TECH_DOCS += technical/platform-support
TECH_DOCS += technical/racy-git
TECH_DOCS += technical/reftable
TECH_DOCS += technical/scalar
diff --git a/Documentation/RelNotes/2.46.1.txt b/Documentation/RelNotes/2.46.1.txt
new file mode 100644
index 0000000000..52afb3556a
--- /dev/null
+++ b/Documentation/RelNotes/2.46.1.txt
@@ -0,0 +1,37 @@
+Git 2.46.1 Release Notes
+========================
+
+This release is primarily to merge fixes accumulated on the 'master'
+front to prepare for 2.47 release that are still relevant to 2.46.x
+maintenance track.
+
+Fixes since Git 2.46
+--------------------
+
+ * "git checkout --ours" (no other arguments) complained that the
+ option is incompatible with branch switching, which is technically
+ correct, but found confusing by some users. It now says that the
+ user needs to give pathspec to specify what paths to checkout.
+
+ * It has been documented that we avoid "VAR=VAL shell_func" and why.
+
+ * "git add -p" by users with diff.suppressBlankEmpty set to true
+ failed to parse the patch that represents an unmodified empty line
+ with an empty line (not a line with a single space on it), which
+ has been corrected.
+
+ * "git rebase --help" referred to "offset" (the difference between
+ the location a change was taken from and the change gets replaced)
+ incorrectly and called it "fuzz", which has been corrected.
+
+ * "git notes add -m '' --allow-empty" and friends that take prepared
+ data to create notes should not invoke an editor, but it started
+ doing so since Git 2.42, which has been corrected.
+
+ * An expensive operation to prepare tracing was done in re-encoding
+ code path even when the tracing was not requested, which has been
+ corrected.
+
+ * Perforce tests have been updated.
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.47.0.txt b/Documentation/RelNotes/2.47.0.txt
index b948fa4db4..24dd430403 100644
--- a/Documentation/RelNotes/2.47.0.txt
+++ b/Documentation/RelNotes/2.47.0.txt
@@ -21,6 +21,15 @@ UI, Workflows & Features
discard it when we taught proxy auth code path to use the
credential helpers, which has been corrected.
+ * The code paths to compact multiple reftable files have been updated
+ to correctly deal with multiple compaction triggering at the same
+ time.
+
+ * Support to specify ref backend for submodules has been enhanced.
+
+ * "git svn" has been taught about svn:global-ignores property
+ recent versions of Subversion has.
+
Performance, Internal Implementation, Development Support etc.
--------------------------------------------------------------
@@ -51,6 +60,22 @@ Performance, Internal Implementation, Development Support etc.
less likely to cause trouble by lengthening the expiry value it
uses.
+ * An existing test of hashmap API has been rewritten with the
+ unit-test framework.
+
+ * A policy document that describes platform support levels and
+ expectation on platform stakeholders has been introduced.
+
+ * The refs API has been taught to give symref target information to
+ the users of ref iterators, allowing for-each-ref and friends to
+ avoid an extra ref_resolve_* API call per a symbolic ref.
+
+ * Unit-test framework has learned a simple control structure to allow
+ embedding test statements in-line instead of having to create a new
+ function to contain them.
+
+ * Incremental updates of multi-pack index files is getting worked on.
+
Fixes since v2.46
-----------------
@@ -59,31 +84,25 @@ Fixes since v2.46
failed to parse the patch that represents an unmodified empty line
with an empty line (not a line with a single space on it), which
has been corrected.
- (merge 60cf761ed1 pw/add-patch-with-suppress-blank-empty later to maint).
* "git checkout --ours" (no other arguments) complained that the
option is incompatible with branch switching, which is technically
correct, but found confusing by some users. It now says that the
user needs to give pathspec to specify what paths to checkout.
- (merge d1e6c61272 jc/checkout-no-op-switch-errors later to maint).
* It has been documented that we avoid "VAR=VAL shell_func" and why.
- (merge 728a1962cd jc/doc-one-shot-export-with-shell-func later to maint).
* "git rebase --help" referred to "offset" (the difference between
the location a change was taken from and the change gets replaced)
incorrectly and called it "fuzz", which has been corrected.
- (merge 70058db385 jc/doc-rebase-fuzz-vs-offset-fix later to maint).
* "git notes add -m '' --allow-empty" and friends that take prepared
data to create notes should not invoke an editor, but it started
doing so since Git 2.42, which has been corrected.
- (merge 8b426c84f3 dd/notes-empty-no-edit-by-default later to maint).
* An expensive operation to prepare tracing was done in re-encoding
code path even when the tracing was not requested, which has been
corrected.
- (merge 63ad8dbf16 dh/encoding-trace-optim later to maint).
* More leakfixes.
(merge f30bfafcd4 ps/leakfixes-part-3 later to maint).
@@ -118,12 +137,20 @@ Fixes since v2.46
fixed.
(merge ec60bb9fc4 kl/test-fixes later to maint).
+ * Follow-up on 2.45.1 regression fix.
+ (merge ee0be850b0 jc/safe-directory later to maint).
+
+ * "git rev-list ... | git diff-tree -p --remerge-diff --stdin" should
+ behave more or less like "git log -p --remerge-diff" but instead it
+ crashed, forgetting to prepare a temporary object store needed.
+ (merge a77554ea09 xx/diff-tree-remerge-diff-fix later to maint).
+
+ * "git bundle unbundle" outside a repository triggered a BUG()
+ unnecessarily, which has been corrected.
+ (merge 96a9a3e42e ps/bundle-outside-repo-fix later to maint).
+
* Other code cleanup, docfix, build fix, etc.
- (merge 8db8786fc2 jt/doc-post-receive-hook-update later to maint).
- (merge 1c473dd6af tn/doc-commit-fix later to maint).
(merge bb0498b1bb jc/how-to-maintain-updates later to maint).
- (merge 6e71d6ac7c ks/unit-test-comment-typofix later to maint).
- (merge 63ee933383 ps/p4-tests-updates later to maint).
(merge 7c7516b8db jc/jl-git-no-advice-fix later to maint).
(merge c3d034df16 jc/leakfix-hashfile later to maint).
(merge d98d9c77e5 jc/leakfix-mailmap later to maint).
@@ -131,3 +158,7 @@ Fixes since v2.46
(merge e2e373ba82 ss/packed-ref-store-leakfix later to maint).
(merge 0c4d5aa22d rs/use-decimal-width later to maint).
(merge 67be8c4de5 jc/document-use-of-local later to maint).
+ (merge 098be29f5b rs/t-example-simplify later to maint).
+ (merge 0d66f601a9 jc/tests-no-useless-tee later to maint).
+ (merge 170cdfc5a4 jc/grammo-fixes later to maint).
+ (merge 983555a1f2 jc/how-to-maintain-updates later to maint).
diff --git a/Documentation/fsck-msgids.txt b/Documentation/fsck-msgids.txt
index f643585a34..68a2801f15 100644
--- a/Documentation/fsck-msgids.txt
+++ b/Documentation/fsck-msgids.txt
@@ -19,6 +19,12 @@
`badParentSha1`::
(ERROR) A commit object has a bad parent sha1.
+`badRefFiletype`::
+ (ERROR) A ref has a bad file type.
+
+`badRefName`::
+ (ERROR) A ref has an invalid format.
+
`badTagName`::
(INFO) A tag has an invalid format.
diff --git a/Documentation/git-diff-tree.txt b/Documentation/git-diff-tree.txt
index 143318c411..09286a85eb 100644
--- a/Documentation/git-diff-tree.txt
+++ b/Documentation/git-diff-tree.txt
@@ -88,7 +88,7 @@ include::pretty-options.txt[]
--no-commit-id::
'git diff-tree' outputs a line with the commit ID when
- applicable. This flag suppressed the commit ID output.
+ applicable. This flag suppresses the commit ID output.
-c::
This flag changes the way a merge commit is displayed
diff --git a/Documentation/git-multi-pack-index.txt b/Documentation/git-multi-pack-index.txt
index 3696506eb3..631d5c7d15 100644
--- a/Documentation/git-multi-pack-index.txt
+++ b/Documentation/git-multi-pack-index.txt
@@ -64,6 +64,12 @@ The file given at `<path>` is expected to be readable, and can contain
duplicates. (If a given OID is given more than once, it is marked as
preferred if at least one instance of it begins with the special `+`
marker).
+
+ --incremental::
+ Write an incremental MIDX file containing only objects
+ and packs not present in an existing MIDX layer.
+ Migrates non-incremental MIDXs to incremental ones when
+ necessary. Incompatible with `--bitmap`.
--
verify::
@@ -74,6 +80,8 @@ expire::
have no objects referenced by the MIDX (with the exception of
`.keep` packs and cruft packs). Rewrite the MIDX file afterward
to remove all references to these pack-files.
++
+NOTE: this mode is incompatible with incremental MIDX files.
repack::
Create a new pack-file containing objects in small pack-files
@@ -95,7 +103,8 @@ repack::
+
If `repack.packKeptObjects` is `false`, then any pack-files with an
associated `.keep` file will not be selected for the batch to repack.
-
++
+NOTE: this mode is incompatible with incremental MIDX files.
EXAMPLES
--------
diff --git a/Documentation/git-refs.txt b/Documentation/git-refs.txt
index 5b99e04385..ce31f93061 100644
--- a/Documentation/git-refs.txt
+++ b/Documentation/git-refs.txt
@@ -10,6 +10,7 @@ SYNOPSIS
--------
[verse]
'git refs migrate' --ref-format=<format> [--dry-run]
+'git refs verify' [--strict] [--verbose]
DESCRIPTION
-----------
@@ -22,6 +23,9 @@ COMMANDS
migrate::
Migrate ref store between different formats.
+verify::
+ Verify reference database consistency.
+
OPTIONS
-------
@@ -39,6 +43,15 @@ include::ref-storage-format.txt[]
can be used to double check that the migration works as expected before
performing the actual migration.
+The following options are specific to 'git refs verify':
+
+--strict::
+ Enable stricter error checking. This will cause warnings to be
+ reported as errors. See linkgit:git-fsck[1].
+
+--verbose::
+ When verifying the reference database consistency, be chatty.
+
KNOWN LIMITATIONS
-----------------
diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt
index ca0347a37b..87d8e0f0c5 100644
--- a/Documentation/git-submodule.txt
+++ b/Documentation/git-submodule.txt
@@ -34,7 +34,7 @@ COMMANDS
With no arguments, shows the status of existing submodules. Several
subcommands are available to perform operations on the submodules.
-add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--depth <depth>] [--] <repository> [<path>]::
+add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--ref-format <format>] [--depth <depth>] [--] <repository> [<path>]::
Add the given repository as a submodule at the given path
to the changeset to be committed next to the current
project: the current project is termed the "superproject".
@@ -71,6 +71,9 @@ submodule repositories will be kept together in the same relative
location, and only the superproject's URL needs to be provided.
git-submodule will correctly locate the submodule using the relative
URL in `.gitmodules`.
++
+If `--ref-format <format>` is specified, the ref storage format of newly
+cloned submodules will be set accordingly.
status [--cached] [--recursive] [--] [<path>...]::
Show the status of the submodules. This will print the SHA-1 of the
@@ -136,7 +139,7 @@ If you really want to remove a submodule from the repository and commit
that use linkgit:git-rm[1] instead. See linkgit:gitsubmodules[7] for removal
options.
-update [--init] [--remote] [-N|--no-fetch] [--[no-]recommend-shallow] [-f|--force] [--checkout|--rebase|--merge] [--reference <repository>] [--depth <depth>] [--recursive] [--jobs <n>] [--[no-]single-branch] [--filter <filter-spec>] [--] [<path>...]::
+update [--init] [--remote] [-N|--no-fetch] [--[no-]recommend-shallow] [-f|--force] [--checkout|--rebase|--merge] [--reference <repository>] [--ref-format <format>] [--depth <depth>] [--recursive] [--jobs <n>] [--[no-]single-branch] [--filter <filter-spec>] [--] [<path>...]::
+
--
Update the registered submodules to match what the superproject
@@ -185,6 +188,9 @@ submodule with the `--init` option.
If `--recursive` is specified, this command will recurse into the
registered submodules, and update any nested submodules within.
+If `--ref-format <format>` is specified, the ref storage format of newly
+cloned submodules will be set accordingly.
+
If `--filter <filter-spec>` is specified, the given partial clone filter will be
applied to the submodule. See linkgit:git-rev-list[1] for details on filter
specifications.
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index 43c68c2ec4..bcf7d84a87 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -431,14 +431,14 @@ Any other arguments are passed directly to 'git log'
independently of 'git svn' functions.
'create-ignore'::
- Recursively finds the svn:ignore property on directories and
- creates matching .gitignore files. The resulting files are staged to
- be committed, but are not committed. Use -r/--revision to refer to a
- specific revision.
+ Recursively finds the svn:ignore and svn:global-ignores properties
+ on directories and creates matching .gitignore files. The resulting
+ files are staged to be committed, but are not committed. Use
+ -r/--revision to refer to a specific revision.
'show-ignore'::
- Recursively finds and lists the svn:ignore property on
- directories. The output is suitable for appending to
+ Recursively finds and lists the svn:ignore and svn:global-ignores
+ properties on directories. The output is suitable for appending to
the $GIT_DIR/info/exclude file.
'mkdirs'::
@@ -871,7 +871,7 @@ Tracking and contributing to the trunk of a Subversion-managed project
# Now commit your changes (that were committed previously using Git) to SVN,
# as well as automatically updating your working HEAD:
git svn dcommit
-# Append svn:ignore settings to the default Git exclude file:
+# Append svn:ignore and svn:global-ignores settings to the default Git exclude file:
git svn show-ignore >> .git/info/exclude
------------------------------------------------------------------------
diff --git a/Documentation/gittutorial.txt b/Documentation/gittutorial.txt
index 4759408788..f89ad30cf6 100644
--- a/Documentation/gittutorial.txt
+++ b/Documentation/gittutorial.txt
@@ -360,7 +360,7 @@ $ gitk HEAD...FETCH_HEAD
This means "show everything that is reachable from either one, but
exclude anything that is reachable from both of them".
-Please note that these range notation can be used with both `gitk`
+Please note that these range notations can be used with both `gitk`
and `git log`.
After inspecting what Bob did, if there is nothing urgent, Alice may
diff --git a/Documentation/howto/maintain-git.txt b/Documentation/howto/maintain-git.txt
index 41f54050f8..da31332f11 100644
--- a/Documentation/howto/maintain-git.txt
+++ b/Documentation/howto/maintain-git.txt
@@ -181,6 +181,10 @@ by doing the following:
$ git diff ORIG_HEAD.. ;# final review
$ make test ;# final review
+ If the tip of 'master' is updated, also generate the preformatted
+ documentation and push the out result to git-htmldocs and
+ git-manpages repositories.
+
- Handle the remaining patches:
- Anything unobvious that is applicable to 'master' (in other
diff --git a/Documentation/technical/multi-pack-index.txt b/Documentation/technical/multi-pack-index.txt
index f2221d2b44..cc063b30be 100644
--- a/Documentation/technical/multi-pack-index.txt
+++ b/Documentation/technical/multi-pack-index.txt
@@ -61,6 +61,109 @@ Design Details
- The MIDX file format uses a chunk-based approach (similar to the
commit-graph file) that allows optional data to be added.
+Incremental multi-pack indexes
+------------------------------
+
+As repositories grow in size, it becomes more expensive to write a
+multi-pack index (MIDX) that includes all packfiles. To accommodate
+this, the "incremental multi-pack indexes" feature allows for combining
+a "chain" of multi-pack indexes.
+
+Each individual component of the chain need only contain a small number
+of packfiles. Appending to the chain does not invalidate earlier parts
+of the chain, so repositories can control how much time is spent
+updating the MIDX chain by determining the number of packs in each layer
+of the MIDX chain.
+
+=== Design state
+
+At present, the incremental multi-pack indexes feature is missing two
+important components:
+
+ - The ability to rewrite earlier portions of the MIDX chain (i.e., to
+ "compact" some collection of adjacent MIDX layers into a single
+ MIDX). At present the only supported way of shrinking a MIDX chain
+ is to rewrite the entire chain from scratch without the `--split`
+ flag.
++
+There are no fundamental limitations that stand in the way of being able
+to implement this feature. It is omitted from the initial implementation
+in order to reduce the complexity, but will be added later.
+
+ - Support for reachability bitmaps. The classic single MIDX
+ implementation does support reachability bitmaps (see the section
+ titled "multi-pack-index reverse indexes" in
+ linkgit:gitformat-pack[5] for more details).
++
+As above, there are no fundamental limitations that stand in the way of
+extending the incremental MIDX format to support reachability bitmaps.
+The design below specifically takes this into account, and support for
+reachability bitmaps will be added in a future patch series. It is
+omitted from the current implementation for the same reason as above.
++
+In brief, to support reachability bitmaps with the incremental MIDX
+feature, the concept of the pseudo-pack order is extended across each
+layer of the incremental MIDX chain to form a concatenated pseudo-pack
+order. This concatenation takes place in the same order as the chain
+itself (in other words, the concatenated pseudo-pack order for a chain
+`{$H1, $H2, $H3}` would be the pseudo-pack order for `$H1`, followed by
+the pseudo-pack order for `$H2`, followed by the pseudo-pack order for
+`$H3`).
++
+The layout will then be extended so that each layer of the incremental
+MIDX chain can write a `*.bitmap`. The objects in each layer's bitmap
+are offset by the number of objects in the previous layers of the chain.
+
+=== File layout
+
+Instead of storing a single `multi-pack-index` file (with an optional
+`.rev` and `.bitmap` extension) in `$GIT_DIR/objects/pack`, incremental
+MIDXs are stored in the following layout:
+
+----
+$GIT_DIR/objects/pack/multi-pack-index.d/
+$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-chain
+$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-$H1.midx
+$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-$H2.midx
+$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-$H3.midx
+----
+
+The `multi-pack-index-chain` file contains a list of the incremental
+MIDX files in the chain, in order. The above example shows a chain whose
+`multi-pack-index-chain` file would contain the following lines:
+
+----
+$H1
+$H2
+$H3
+----
+
+The `multi-pack-index-$H1.midx` file contains the first layer of the
+multi-pack-index chain. The `multi-pack-index-$H2.midx` file contains
+the second layer of the chain, and so on.
+
+When both an incremental- and non-incremental MIDX are present, the
+non-incremental MIDX is always read first.
+
+=== Object positions for incremental MIDXs
+
+In the original multi-pack-index design, we refer to objects via their
+lexicographic position (by object IDs) within the repository's singular
+multi-pack-index. In the incremental multi-pack-index design, we refer
+to objects via their index into a concatenated lexicographic ordering
+among each component in the MIDX chain.
+
+If `objects_nr()` is a function that returns the number of objects in a
+given MIDX layer, then the index of an object at lexicographic position
+`i` within, say, $H3 is defined as:
+
+----
+objects_nr($H2) + objects_nr($H1) + i
+----
+
+(in the C implementation, this is often computed as `i +
+m->num_objects_in_base`).
+
Future Work
-----------
diff --git a/Documentation/technical/platform-support.txt b/Documentation/technical/platform-support.txt
new file mode 100644
index 0000000000..a227c363d7
--- /dev/null
+++ b/Documentation/technical/platform-support.txt
@@ -0,0 +1,190 @@
+Platform Support Policy
+=======================
+
+Git has a history of providing broad "support" for exotic platforms and older
+platforms, without an explicit commitment. Stakeholders of these platforms may
+want a more predictable support commitment. This is only possible when platform
+stakeholders supply Git developers with adequate tooling, so we can test for
+compatibility or develop workarounds for platform-specific quirks on our own.
+Various levels of platform-specific tooling will allow us to make more solid
+commitments around Git's compatibility with that platform.
+
+Note that this document is about maintaining existing support for a platform
+that has generally worked in the past; for adding support to a platform which
+doesn't generally work with Git, the stakeholders for that platform are expected
+to do the bulk of that work themselves. We will consider such patches if they
+don't make life harder for other supported platforms or for Git contributors.
+Some contributors may volunteer to help with the initial or continued support,
+but that's not a given. Support work which is too intrusive or difficult for the
+project to maintain may still not be accepted.
+
+Minimum Requirements
+--------------------
+
+The rest of this doc describes best practices for platforms to make themselves
+easy to support. However, before considering support at all, platforms need to
+meet the following minimum requirements:
+
+* Has C99 or C11
+
+* Uses versions of dependencies which are generally accepted as stable and
+ supportable, e.g., in line with the version used by other long-term-support
+ distributions
+
+* Has active security support (taking security releases of dependencies, etc)
+
+These requirements are a starting point, and not sufficient on their own for the
+Git community to be enthusiastic about supporting your platform. Maintainers of
+platforms which do meet these requirements can follow the steps below to make it
+more likely that Git updates will respect the platform's needs.
+
+Compatible by next release
+--------------------------
+
+To increase probability that compatibility issues introduced in a release
+will be fixed in a later release:
+
+* You should send a bug report as soon as you notice the breakage on your
+ platform. The sooner you notice, the better; watching `seen` means you can
+ notice problems before they are considered "done with review"; whereas
+ watching `master` means the stable branch could break for your platform, but
+ you have a decent chance of avoiding a tagged release breaking you. See "The
+ Policy" in link:../howto/maintain-git.txt["How to maintain Git"] for an
+ overview of which branches are used in the Git project, and how.
+
+* The bug report should include information about what platform you are using.
+
+* You should also use linkgit:git-bisect[1] and determine which commit
+ introduced the breakage.
+
+* Please include any information you have about the nature of the breakage: is
+ it a memory alignment issue? Is an underlying library missing or broken for
+ your platform? Is there some quirk about your platform which means typical
+ practices (like malloc) behave strangely?
+
+* If possible, build Git from the exact same source both for your platform and
+ for a mainstream platform, to see if the problem you noticed appears only
+ on your platform. If the problem appears in both, then it's not a
+ compatibility issue, but we of course appreciate hearing about it in a bug
+ report anyway, to benefit users of every platform. If it appears only on your
+ platform, mention clearly that it is a compatibility issue in your report.
+
+* Once we begin to fix the issue, please work closely with the contributor
+ working on it to test the proposed fix against your platform.
+
+Example: NonStop
+https://lore.kernel.org/git/01bd01da681a$b8d70a70$2a851f50$@nexbridge.com/[reports
+problems] when they're noticed.
+
+Compatible on `master` and releases
+-----------------------------------
+
+To make sure all stable builds and regular releases work for your platform the
+first time, help us avoid breaking `master` for your platform:
+
+* You should run regular tests against the `next` branch and
+ publish breakage reports to the mailing list immediately when they happen.
+
+** Ideally, these tests should run daily. They must run more often than
+ weekly, as topics generally spend at least 7 days in `next` before graduating
+ to `master`, and it takes time to put the brakes on a patch once it lands in
+ `next`.
+
+** You may want to ask to join the mailto:git-security@googlegroups.com[security
+ mailing list] in order to run tests against the fixes proposed there, too.
+
+* It may make sense to automate these; if you do, make sure they are not noisy
+ (you don't need to send a report when everything works, only when something
+ breaks; you don't need to send repeated reports for the same breakage night
+ after night).
+
+* Breakage reports should be actionable - include clear error messages that can
+ help developers who may not have access to test directly on your platform.
+
+* You should use git-bisect and determine which commit introduced the breakage;
+ if you can't do this with automation, you should do this yourself manually as
+ soon as you notice a breakage report was sent.
+
+* You should either:
+
+** Provide on-demand access to your platform to a trusted developer working to
+ fix the issue, so they can test their fix, OR
+
+** Work closely with the developer fixing the issue; the turnaround to check
+ that their proposed fix works for your platform should be fast enough that it
+ doesn't hinder the developer working on that fix. Slow testing turnarounds
+ may cause the fix to miss the next release, or the developer may lose
+ interest in working on the fix at all.
+
+Example:
+https://lore.kernel.org/git/CAHd-oW6X4cwD_yLNFONPnXXUAFPxgDoccv2SOdpeLrqmHCJB4Q@mail.gmail.com/[AIX]
+provides a build farm and runs tests against release candidates.
+
+Compatible on `next`
+--------------------
+
+To avoid reactive debugging and fixing when changes hit a release or stable, you
+can aim to ensure `next` always works for your platform. (See "The Policy" in
+link:../howto/maintain-git.txt["How to maintain Git"] for an overview of how
+`next` is used in the Git project.) To do that:
+
+* You should add a runner for your platform to the GitHub Actions or GitLab CI
+ suite. This suite is run when any Git developer proposes a new patch, and
+ having a runner for your platform/configuration means every developer will
+ know if they break you, immediately.
+
+** If adding it to an existing CI suite is infeasible (due to architecture
+ constraints or for performance reasons), any other method which runs as
+ automatically and quickly as possible works, too. For example, a service
+ which snoops on the mailing list and automatically runs tests on new [PATCH]
+ emails, replying to the author with the results, would also be within the
+ spirit of this requirement.
+
+* If you rely on Git avoiding a specific pattern that doesn't work well with
+ your platform (like a certain malloc pattern), raise it on the mailing list.
+ We'll work case-by-case to look for a solution that doesn't unnecessarily
+ constrain other platforms to keep compatibility with yours.
+
+* If you rely on some configuration or behavior, add a test for it. Untested
+ behavior is subject to breakage at any time.
+
+** Clearly label these tests as necessary for platform compatibility. Add them
+ to an isolated compatibility-related test suite, like a new t* file or unit
+ test suite, so that they're easy to remove when compatibility is no longer
+ required. If the specific compatibility need is gated behind an issue with
+ another project, link to documentation of that issue (like a bug or email
+ thread) to make it easier to tell when that compatibility need goes away.
+
+** Include a comment with an expiration date for these tests no more than 1 year
+ from now. You can update the expiration date if your platform still needs
+ that assurance down the road, but we need to know you still care about that
+ compatibility case and are working to make it unnecessary.
+
+Example: We run our
+https://git.kernel.org/pub/scm/git/git.git/tree/.github/workflows/main.yml[CI
+suite] on Windows, Ubuntu, Mac, and others.
+
+Getting help writing platform support patches
+---------------------------------------------
+
+In general, when sending patches to fix platform support problems, follow
+these guidelines to make sure the patch is reviewed with the appropriate level
+of urgency:
+
+* Clearly state in the commit message that you are fixing a platform breakage,
+ and for which platform.
+
+* Use the CI and test suite to ensure that the fix for your platform doesn't
+ break other platforms.
+
+* If possible, add a test ensuring this regression doesn't happen again. If
+ it's not possible to add a test, explain why in the commit message.
+
+Platform Maintainers
+--------------------
+
+If you maintain a platform, or Git for that platform, and intend to work with
+the Git project to ensure compatibility, please send a patch to add yourself to
+this list.
+
+NonStop: Randall S. Becker <rsbecker@nexbridge.com>
diff --git a/Makefile b/Makefile
index 13890710f8..e298c8b55e 100644
--- a/Makefile
+++ b/Makefile
@@ -1335,6 +1335,7 @@ THIRD_PARTY_SOURCES += sha1dc/%
UNIT_TEST_PROGRAMS += t-ctype
UNIT_TEST_PROGRAMS += t-example-decorate
UNIT_TEST_PROGRAMS += t-hash
+UNIT_TEST_PROGRAMS += t-hashmap
UNIT_TEST_PROGRAMS += t-mem-pool
UNIT_TEST_PROGRAMS += t-oidmap
UNIT_TEST_PROGRAMS += t-oidtree
@@ -1342,6 +1343,7 @@ UNIT_TEST_PROGRAMS += t-prio-queue
UNIT_TEST_PROGRAMS += t-reftable-basics
UNIT_TEST_PROGRAMS += t-reftable-merged
UNIT_TEST_PROGRAMS += t-reftable-pq
+UNIT_TEST_PROGRAMS += t-reftable-readwrite
UNIT_TEST_PROGRAMS += t-reftable-record
UNIT_TEST_PROGRAMS += t-reftable-tree
UNIT_TEST_PROGRAMS += t-strbuf
@@ -2683,7 +2685,6 @@ REFTABLE_OBJS += reftable/writer.o
REFTABLE_TEST_OBJS += reftable/block_test.o
REFTABLE_TEST_OBJS += reftable/dump.o
-REFTABLE_TEST_OBJS += reftable/readwrite_test.o
REFTABLE_TEST_OBJS += reftable/stack_test.o
REFTABLE_TEST_OBJS += reftable/test_framework.o
diff --git a/add-patch.c b/add-patch.c
index 1cec4ab67b..557903310d 100644
--- a/add-patch.c
+++ b/add-patch.c
@@ -1142,7 +1142,8 @@ static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
"removed, then the edit is\n"
"aborted and the hunk is left unchanged.\n"));
- if (strbuf_edit_interactively(&s->buf, "addp-hunk-edit.diff", NULL) < 0)
+ if (strbuf_edit_interactively(the_repository, &s->buf,
+ "addp-hunk-edit.diff", NULL) < 0)
return -1;
/* strip out commented lines */
diff --git a/bisect.c b/bisect.c
index 135f94ba09..4406fc44cf 100644
--- a/bisect.c
+++ b/bisect.c
@@ -448,7 +448,7 @@ void find_bisection(struct commit_list **commit_list, int *reaches,
clear_commit_weight(&commit_weight);
}
-static int register_ref(const char *refname, const struct object_id *oid,
+static int register_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flags UNUSED, void *cb_data UNUSED)
{
struct strbuf good_prefix = STRBUF_INIT;
@@ -1170,6 +1170,7 @@ int estimate_bisect_steps(int all)
}
static int mark_for_removal(const char *refname,
+ const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flag UNUSED, void *cb_data)
{
diff --git a/builtin/am.c b/builtin/am.c
index a12be088f7..d8875ad402 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -490,7 +490,8 @@ static int run_applypatch_msg_hook(struct am_state *state)
assert(state->msg);
if (!state->no_verify)
- ret = run_hooks_l("applypatch-msg", am_path(state, "final-commit"), NULL);
+ ret = run_hooks_l(the_repository, "applypatch-msg",
+ am_path(state, "final-commit"), NULL);
if (!ret) {
FREE_AND_NULL(state->msg);
@@ -512,7 +513,7 @@ static int run_post_rewrite_hook(const struct am_state *state)
strvec_push(&opt.args, "rebase");
opt.path_to_stdin = am_path(state, "rewritten");
- return run_hooks_opt("post-rewrite", &opt);
+ return run_hooks_opt(the_repository, "post-rewrite", &opt);
}
/**
@@ -1663,7 +1664,7 @@ static void do_commit(const struct am_state *state)
const char *reflog_msg, *author, *committer = NULL;
struct strbuf sb = STRBUF_INIT;
- if (!state->no_verify && run_hooks("pre-applypatch"))
+ if (!state->no_verify && run_hooks(the_repository, "pre-applypatch"))
exit(1);
if (write_index_as_tree(&tree, the_repository->index, get_index_file(), 0, NULL))
@@ -1716,7 +1717,7 @@ static void do_commit(const struct am_state *state)
fclose(fp);
}
- run_hooks("post-applypatch");
+ run_hooks(the_repository, "post-applypatch");
free_commit_list(parents);
strbuf_release(&sb);
diff --git a/builtin/bisect.c b/builtin/bisect.c
index dabce9b542..453a6cccd7 100644
--- a/builtin/bisect.c
+++ b/builtin/bisect.c
@@ -356,6 +356,7 @@ static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)
}
static int inc_nr(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flag UNUSED, void *cb_data)
{
@@ -545,7 +546,7 @@ finish:
return res;
}
-static int add_bisect_ref(const char *refname, const struct object_id *oid,
+static int add_bisect_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flags UNUSED, void *cb)
{
struct add_bisect_ref_data *data = cb;
@@ -1162,6 +1163,7 @@ static int bisect_visualize(struct bisect_terms *terms, int argc,
}
static int get_first_good(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flag UNUSED, void *cb_data)
{
diff --git a/builtin/branch.c b/builtin/branch.c
index 48cac74f97..3f870741bf 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -210,7 +210,7 @@ static void delete_branch_config(const char *branchname)
{
struct strbuf buf = STRBUF_INIT;
strbuf_addf(&buf, "branch.%s", branchname);
- if (git_config_rename_section(buf.buf, NULL) < 0)
+ if (repo_config_rename_section(the_repository, buf.buf, NULL) < 0)
warning(_("update of config-file failed"));
strbuf_release(&buf);
}
@@ -659,9 +659,10 @@ static void copy_or_rename_branch(const char *oldname, const char *newname, int
strbuf_addf(&oldsection, "branch.%s", interpreted_oldname);
strbuf_addf(&newsection, "branch.%s", interpreted_newname);
- if (!copy && git_config_rename_section(oldsection.buf, newsection.buf) < 0)
+ if (!copy && repo_config_rename_section(the_repository, oldsection.buf, newsection.buf) < 0)
die(_("branch is renamed, but update of config-file failed"));
- if (copy && strcmp(interpreted_oldname, interpreted_newname) && git_config_copy_section(oldsection.buf, newsection.buf) < 0)
+ if (copy && strcmp(interpreted_oldname, interpreted_newname) &&
+ repo_config_copy_section(the_repository, oldsection.buf, newsection.buf) < 0)
die(_("branch is copied, but update of config-file failed"));
strbuf_release(&oldref);
strbuf_release(&newref);
diff --git a/builtin/bugreport.c b/builtin/bugreport.c
index b3cc77af53..bdfed3d8f1 100644
--- a/builtin/bugreport.c
+++ b/builtin/bugreport.c
@@ -58,7 +58,7 @@ static void get_populated_hooks(struct strbuf *hook_info, int nongit)
for (p = hook_name_list; *p; p++) {
const char *hook = *p;
- if (hook_exists(hook))
+ if (hook_exists(the_repository, hook))
strbuf_addf(hook_info, "%s\n", hook);
}
}
diff --git a/builtin/bundle.c b/builtin/bundle.c
index d5d41a8f67..86d0ed7049 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -207,12 +207,13 @@ static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix)
builtin_bundle_unbundle_usage, options, &bundle_file);
/* bundle internals use argv[1] as further parameters */
+ if (!startup_info->have_repository)
+ die(_("Need a repository to unbundle."));
+
if ((bundle_fd = open_bundle(bundle_file, &header, NULL)) < 0) {
ret = 1;
goto cleanup;
}
- if (!startup_info->have_repository)
- die(_("Need a repository to unbundle."));
if (progress)
strvec_pushl(&extra_index_pack_args, "-v", "--progress-title",
_("Unbundling objects"), NULL);
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 0f21ddd2c6..4cfe6fab50 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -125,7 +125,7 @@ static void branch_info_release(struct branch_info *info)
static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,
int changed)
{
- return run_hooks_l("post-checkout",
+ return run_hooks_l(the_repository, "post-checkout",
oid_to_hex(old_commit ? &old_commit->object.oid : null_oid()),
oid_to_hex(new_commit ? &new_commit->object.oid : null_oid()),
changed ? "1" : "0", NULL);
@@ -1045,7 +1045,7 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
report_tracking(new_branch_info);
}
-static int add_pending_uninteresting_ref(const char *refname,
+static int add_pending_uninteresting_ref(const char *refname, const char *referent UNUSED,
const struct object_id *oid,
int flags UNUSED, void *cb_data)
{
diff --git a/builtin/clone.c b/builtin/clone.c
index af6017d41a..269b6e18a4 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -729,7 +729,8 @@ static int git_sparse_checkout_init(const char *repo)
return result;
}
-static int checkout(int submodule_progress, int filter_submodules)
+static int checkout(int submodule_progress, int filter_submodules,
+ enum ref_storage_format ref_storage_format)
{
struct object_id oid;
char *head;
@@ -788,7 +789,7 @@ static int checkout(int submodule_progress, int filter_submodules)
if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
- err |= run_hooks_l("post-checkout", oid_to_hex(null_oid()),
+ err |= run_hooks_l(the_repository, "post-checkout", oid_to_hex(null_oid()),
oid_to_hex(&oid), "1", NULL);
if (!err && (option_recurse_submodules.nr > 0)) {
@@ -813,6 +814,10 @@ static int checkout(int submodule_progress, int filter_submodules)
strvec_push(&cmd.args, "--no-fetch");
}
+ if (ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
+ strvec_pushf(&cmd.args, "--ref-format=%s",
+ ref_storage_format_to_name(ref_storage_format));
+
if (filter_submodules && filter_options.choice)
strvec_pushf(&cmd.args, "--filter=%s",
expand_list_objects_filter_spec(&filter_options));
@@ -1536,7 +1541,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
return 1;
junk_mode = JUNK_LEAVE_REPO;
- err = checkout(submodule_progress, filter_submodules);
+ err = checkout(submodule_progress, filter_submodules,
+ ref_storage_format);
free(remote_name);
strbuf_release(&reflog_msg);
diff --git a/builtin/commit.c b/builtin/commit.c
index 66427ba82d..b2033c4887 100644
--- a/builtin/commit.c
+++ b/builtin/commit.c
@@ -684,7 +684,9 @@ static void adjust_comment_line_char(const struct strbuf *sb)
const char *p;
if (!memchr(sb->buf, candidates[0], sb->len)) {
- comment_line_str = xstrfmt("%c", candidates[0]);
+ free(comment_line_str_to_free);
+ comment_line_str = comment_line_str_to_free =
+ xstrfmt("%c", candidates[0]);
return;
}
@@ -705,7 +707,8 @@ static void adjust_comment_line_char(const struct strbuf *sb)
if (!*p)
die(_("unable to select a comment character that is not used\n"
"in the current commit message"));
- comment_line_str = xstrfmt("%c", *p);
+ free(comment_line_str_to_free);
+ comment_line_str = comment_line_str_to_free = xstrfmt("%c", *p);
}
static void prepare_amend_commit(struct commit *commit, struct strbuf *sb,
diff --git a/builtin/config.c b/builtin/config.c
index 20a0b64090..e00d983596 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -1026,8 +1026,8 @@ static int cmd_config_rename_section(int argc, const char **argv, const char *pr
location_options_init(&location_opts, prefix);
check_write(&location_opts.source);
- ret = git_config_rename_section_in_file(location_opts.source.file,
- argv[0], argv[1]);
+ ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file,
+ argv[0], argv[1]);
if (ret < 0)
goto out;
else if (!ret)
@@ -1055,8 +1055,8 @@ static int cmd_config_remove_section(int argc, const char **argv, const char *pr
location_options_init(&location_opts, prefix);
check_write(&location_opts.source);
- ret = git_config_rename_section_in_file(location_opts.source.file,
- argv[0], NULL);
+ ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file,
+ argv[0], NULL);
if (ret < 0)
goto out;
else if (!ret)
@@ -1353,8 +1353,8 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
else if (actions == ACTION_RENAME_SECTION) {
check_write(&location_opts.source);
check_argc(argc, 2, 2);
- ret = git_config_rename_section_in_file(location_opts.source.file,
- argv[0], argv[1]);
+ ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file,
+ argv[0], argv[1]);
if (ret < 0)
goto out;
else if (!ret)
@@ -1365,8 +1365,8 @@ static int cmd_config_actions(int argc, const char **argv, const char *prefix)
else if (actions == ACTION_REMOVE_SECTION) {
check_write(&location_opts.source);
check_argc(argc, 1, 1);
- ret = git_config_rename_section_in_file(location_opts.source.file,
- argv[0], NULL);
+ ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file,
+ argv[0], NULL);
if (ret < 0)
goto out;
else if (!ret)
diff --git a/builtin/count-objects.c b/builtin/count-objects.c
index 2d4bb5e8d0..ec6098a149 100644
--- a/builtin/count-objects.c
+++ b/builtin/count-objects.c
@@ -113,7 +113,7 @@ int cmd_count_objects(int argc, const char **argv, const char *prefix)
usage_with_options(count_objects_usage, opts);
if (verbose) {
report_garbage = real_report_garbage;
- report_linked_checkout_garbage();
+ report_linked_checkout_garbage(the_repository);
}
for_each_loose_file_in_objdir(get_object_directory(),
diff --git a/builtin/describe.c b/builtin/describe.c
index 954929c514..b43093c099 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -149,7 +149,7 @@ static void add_to_known_names(const char *path,
}
}
-static int get_name(const char *path, const struct object_id *oid,
+static int get_name(const char *path, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data UNUSED)
{
int is_tag = 0;
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
index 0d3c611aac..b8df1d4b79 100644
--- a/builtin/diff-tree.c
+++ b/builtin/diff-tree.c
@@ -8,6 +8,7 @@
#include "read-cache-ll.h"
#include "repository.h"
#include "revision.h"
+#include "tmp-objdir.h"
#include "tree.h"
static struct rev_info log_tree_opt;
@@ -166,6 +167,13 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
opt->diffopt.rotate_to_strict = 1;
+ if (opt->remerge_diff) {
+ opt->remerge_objdir = tmp_objdir_create("remerge-diff");
+ if (!opt->remerge_objdir)
+ die(_("unable to create temporary object directory"));
+ tmp_objdir_replace_primary_odb(opt->remerge_objdir, 1);
+ }
+
/*
* NOTE! We expect "a..b" to expand to "^a b" but it is
* perfectly valid for revision range parser to yield "b ^a",
@@ -230,5 +238,10 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
diff_free(&opt->diffopt);
}
+ if (opt->remerge_diff) {
+ tmp_objdir_destroy(opt->remerge_objdir);
+ opt->remerge_objdir = NULL;
+ }
+
return diff_result_code(&opt->diffopt);
}
diff --git a/builtin/diff.c b/builtin/diff.c
index 9b6cdabe15..6eac445579 100644
--- a/builtin/diff.c
+++ b/builtin/diff.c
@@ -388,6 +388,11 @@ static void symdiff_prepare(struct rev_info *rev, struct symdiff *sym)
sym->skip = map;
}
+static void symdiff_release(struct symdiff *sdiff)
+{
+ bitmap_free(sdiff->skip);
+}
+
int cmd_diff(int argc, const char **argv, const char *prefix)
{
int i;
@@ -619,6 +624,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
refresh_index_quietly();
release_revisions(&rev);
object_array_clear(&ent);
+ symdiff_release(&sdiff);
UNLEAK(blob);
return result;
}
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 4b6e8c6832..f253b79322 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -42,8 +42,8 @@ static int full_tree;
static int reference_excluded_commits;
static int show_original_ids;
static int mark_tags;
-static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
-static struct string_list tag_refs = STRING_LIST_INIT_NODUP;
+static struct string_list extra_refs = STRING_LIST_INIT_DUP;
+static struct string_list tag_refs = STRING_LIST_INIT_DUP;
static struct refspec refspecs = REFSPEC_INIT_FETCH;
static int anonymize;
static struct hashmap anonymized_seeds;
@@ -901,7 +901,7 @@ static void handle_tag(const char *name, struct tag *tag)
free(buf);
}
-static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name)
+static struct commit *get_commit(struct rev_cmdline_entry *e, const char *full_name)
{
switch (e->item->type) {
case OBJ_COMMIT:
@@ -932,14 +932,16 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
struct rev_cmdline_entry *e = info->rev + i;
struct object_id oid;
struct commit *commit;
- char *full_name;
+ char *full_name = NULL;
if (e->flags & UNINTERESTING)
continue;
if (repo_dwim_ref(the_repository, e->name, strlen(e->name),
- &oid, &full_name, 0) != 1)
+ &oid, &full_name, 0) != 1) {
+ free(full_name);
continue;
+ }
if (refspecs.nr) {
char *private;
@@ -955,6 +957,7 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
warning("%s: Unexpected object of type %s, skipping.",
e->name,
type_name(e->item->type));
+ free(full_name);
continue;
}
@@ -963,10 +966,12 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
break;
case OBJ_BLOB:
export_blob(&commit->object.oid);
+ free(full_name);
continue;
default: /* OBJ_TAG (nested tags) is already handled */
warning("Tag points to object of unexpected type %s, skipping.",
type_name(commit->object.type));
+ free(full_name);
continue;
}
@@ -979,6 +984,8 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
if (!*revision_sources_at(&revision_sources, commit))
*revision_sources_at(&revision_sources, commit) = full_name;
+ else
+ free(full_name);
}
string_list_sort(&extra_refs);
@@ -1278,9 +1285,11 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
revs.diffopt.format_callback = show_filemodify;
revs.diffopt.format_callback_data = &paths_of_changed_objects;
revs.diffopt.flags.recursive = 1;
+
revs.diffopt.no_free = 1;
while ((commit = get_revision(&revs)))
handle_commit(commit, &revs, &paths_of_changed_objects);
+ revs.diffopt.no_free = 0;
handle_tags_and_duplicates(&extra_refs);
handle_tags_and_duplicates(&tag_refs);
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index d21c4053a7..2214c105f1 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -206,8 +206,8 @@ static unsigned int object_entry_alloc = 5000;
static struct object_entry_pool *blocks;
static struct hashmap object_table;
static struct mark_set *marks;
-static const char *export_marks_file;
-static const char *import_marks_file;
+static char *export_marks_file;
+static char *import_marks_file;
static int import_marks_file_from_stream;
static int import_marks_file_ignore_missing;
static int import_marks_file_done;
@@ -3274,6 +3274,7 @@ static void option_import_marks(const char *marks,
read_marks();
}
+ free(import_marks_file);
import_marks_file = make_fast_import_path(marks);
import_marks_file_from_stream = from_stream;
import_marks_file_ignore_missing = ignore_missing;
@@ -3316,6 +3317,7 @@ static void option_active_branches(const char *branches)
static void option_export_marks(const char *marks)
{
+ free(export_marks_file);
export_marks_file = make_fast_import_path(marks);
}
@@ -3357,6 +3359,8 @@ static void option_rewrite_submodules(const char *arg, struct string_list *list)
free(f);
string_list_insert(list, s)->util = ms;
+
+ free(s);
}
static int parse_one_option(const char *option)
@@ -3481,8 +3485,8 @@ static void git_pack_config(void)
if (!git_config_get_int("pack.indexversion", &indexversion_value)) {
pack_idx_opts.version = indexversion_value;
if (pack_idx_opts.version > 2)
- git_die_config("pack.indexversion",
- "bad pack.indexVersion=%"PRIu32, pack_idx_opts.version);
+ git_die_config(the_repository, "pack.indexversion",
+ "bad pack.indexVersion=%"PRIu32, pack_idx_opts.version);
}
if (!git_config_get_ulong("pack.packsizelimit", &packsizelimit_value))
max_packsize = packsizelimit_value;
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 693f02b958..c297569a47 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -286,7 +286,7 @@ static struct refname_hash_entry *refname_hash_add(struct hashmap *map,
return ent;
}
-static int add_one_refname(const char *refname,
+static int add_one_refname(const char *refname, const char *referent UNUSED,
const struct object_id *oid,
int flag UNUSED, void *cbdata)
{
@@ -1464,6 +1464,7 @@ static void set_option(struct transport *transport, const char *name, const char
static int add_oid(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flags UNUSED, void *cb_data)
{
diff --git a/builtin/fsck.c b/builtin/fsck.c
index d13a226c2e..60f4e6fad9 100644
--- a/builtin/fsck.c
+++ b/builtin/fsck.c
@@ -89,13 +89,16 @@ static int objerror(struct object *obj, const char *err)
return -1;
}
-static int fsck_error_func(struct fsck_options *o UNUSED,
- const struct object_id *oid,
- enum object_type object_type,
- enum fsck_msg_type msg_type,
- enum fsck_msg_id msg_id UNUSED,
- const char *message)
+static int fsck_objects_error_func(struct fsck_options *o UNUSED,
+ void *fsck_report,
+ enum fsck_msg_type msg_type,
+ enum fsck_msg_id msg_id UNUSED,
+ const char *message)
{
+ struct fsck_object_report *report = fsck_report;
+ const struct object_id *oid = report->oid;
+ enum object_type object_type = report->object_type;
+
switch (msg_type) {
case FSCK_WARN:
/* TRANSLATORS: e.g. warning in tree 01bfda: <more explanation> */
@@ -521,7 +524,7 @@ static int fsck_handle_reflog(const char *logname, void *cb_data)
return 0;
}
-static int fsck_handle_ref(const char *refname, const struct object_id *oid,
+static int fsck_handle_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data UNUSED)
{
struct object *obj;
@@ -576,7 +579,7 @@ static void get_default_heads(void)
strbuf_worktree_ref(wt, &ref, "HEAD");
fsck_head_link(ref.buf, &head_points_at, &head_oid);
if (head_points_at && !is_null_oid(&head_oid))
- fsck_handle_ref(ref.buf, &head_oid, 0, NULL);
+ fsck_handle_ref(ref.buf, NULL, &head_oid, 0, NULL);
strbuf_release(&ref);
if (include_reflogs)
@@ -938,7 +941,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
fsck_walk_options.walk = mark_object;
fsck_obj_options.walk = mark_used;
- fsck_obj_options.error_func = fsck_error_func;
+ fsck_obj_options.error_func = fsck_objects_error_func;
if (check_strict)
fsck_obj_options.strict = 1;
@@ -1050,7 +1053,7 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
* and may get overwritten by other calls
* while we're examining the index.
*/
- path = xstrdup(worktree_git_path(wt, "index"));
+ path = xstrdup(worktree_git_path(the_repository, wt, "index"));
read_index_from(&istate, path, get_worktree_git_dir(wt));
fsck_index(&istate, path, wt->is_current);
discard_index(&istate);
diff --git a/builtin/gc.c b/builtin/gc.c
index 72bac2554f..45f14fb09b 100644
--- a/builtin/gc.c
+++ b/builtin/gc.c
@@ -167,9 +167,9 @@ static void gc_config(void)
git_config_get_bool("gc.autodetach", &detach_auto);
git_config_get_bool("gc.cruftpacks", &cruft_packs);
git_config_get_ulong("gc.maxcruftsize", &max_cruft_size);
- git_config_get_expiry("gc.pruneexpire", &prune_expire);
- git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire);
- git_config_get_expiry("gc.logexpiry", &gc_log_expire);
+ repo_config_get_expiry(the_repository, "gc.pruneexpire", &prune_expire);
+ repo_config_get_expiry(the_repository, "gc.worktreepruneexpire", &prune_worktrees_expire);
+ repo_config_get_expiry(the_repository, "gc.logexpiry", &gc_log_expire);
git_config_get_ulong("gc.bigpackthreshold", &big_pack_threshold);
git_config_get_ulong("pack.deltacachesize", &max_delta_cache_size);
@@ -463,7 +463,7 @@ static int need_to_gc(void)
else
return 0;
- if (run_hooks("pre-auto-gc"))
+ if (run_hooks(the_repository, "pre-auto-gc"))
return 0;
return 1;
}
@@ -836,6 +836,7 @@ struct cg_auto_data {
};
static int dfs_on_ref(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flags UNUSED,
void *cb_data)
diff --git a/builtin/hook.c b/builtin/hook.c
index 5234693a94..cc37438fde 100644
--- a/builtin/hook.c
+++ b/builtin/hook.c
@@ -58,7 +58,7 @@ static int run(int argc, const char **argv, const char *prefix)
hook_name = argv[0];
if (!ignore_missing)
opt.error_if_missing = 1;
- ret = run_hooks_opt(hook_name, &opt);
+ ret = run_hooks_opt(the_repository, hook_name, &opt);
if (ret < 0) /* error() return */
ret = 1;
return ret;
diff --git a/builtin/log.c b/builtin/log.c
index a73a767606..36769bab3b 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -707,6 +707,7 @@ static int show_blob_object(const struct object_id *oid, struct rev_info *rev, c
write_or_die(1, buf, size);
object_context_release(&obj_context);
+ free(buf);
return 0;
}
@@ -1827,12 +1828,14 @@ static struct commit *get_base_commit(const struct format_config *cfg,
if (die_on_failure) {
die(_("failed to find exact merge base"));
} else {
+ free_commit_list(merge_base);
free(rev);
return NULL;
}
}
rev[i] = merge_base->item;
+ free_commit_list(merge_base);
}
if (rev_nr % 2)
@@ -2023,6 +2026,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
const char *rfc = NULL;
int creation_factor = -1;
const char *signature = git_version_string;
+ char *signature_to_free = NULL;
char *signature_file_arg = NULL;
struct keep_callback_data keep_callback_data = {
.cfg = &cfg,
@@ -2443,7 +2447,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
if (strbuf_read_file(&buf, signature_file, 128) < 0)
die_errno(_("unable to read signature file '%s'"), signature_file);
- signature = strbuf_detach(&buf, NULL);
+ signature = signature_to_free = strbuf_detach(&buf, NULL);
} else if (cfg.signature) {
signature = cfg.signature;
}
@@ -2548,12 +2552,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
else
print_signature(signature, rev.diffopt.file);
}
- if (output_directory)
+ if (output_directory) {
fclose(rev.diffopt.file);
+ rev.diffopt.file = NULL;
+ }
}
stop_progress(&progress);
free(list);
- free(branch_name);
if (ignore_if_in_upstream)
free_patch_ids(&ids);
@@ -2565,11 +2570,14 @@ done:
strbuf_release(&rdiff_title);
free(description_file);
free(signature_file_arg);
+ free(signature_to_free);
+ free(branch_name);
free(to_free);
free(rev.message_id);
if (rev.ref_message_ids)
string_list_clear(rev.ref_message_ids, 0);
free(rev.ref_message_ids);
+ rev.diffopt.no_free = 0;
release_revisions(&rev);
format_config_release(&cfg);
return 0;
diff --git a/builtin/merge.c b/builtin/merge.c
index c896b18d1a..662a49a0e8 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -478,7 +478,7 @@ static void finish(struct commit *head_commit,
}
/* Run a post-merge hook */
- run_hooks_l("post-merge", squash ? "1" : "0", NULL);
+ run_hooks_l(the_repository, "post-merge", squash ? "1" : "0", NULL);
if (new_head)
apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
diff --git a/builtin/mktag.c b/builtin/mktag.c
index 4767f1a97e..c6b644219f 100644
--- a/builtin/mktag.c
+++ b/builtin/mktag.c
@@ -18,8 +18,7 @@ static int option_strict = 1;
static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
static int mktag_fsck_error_func(struct fsck_options *o UNUSED,
- const struct object_id *oid UNUSED,
- enum object_type object_type UNUSED,
+ void *fsck_report UNUSED,
enum fsck_msg_type msg_type,
enum fsck_msg_id msg_id UNUSED,
const char *message)
diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c
index 9cf1a32d65..8805cbbeb3 100644
--- a/builtin/multi-pack-index.c
+++ b/builtin/multi-pack-index.c
@@ -129,6 +129,8 @@ static int cmd_multi_pack_index_write(int argc, const char **argv,
MIDX_WRITE_BITMAP | MIDX_WRITE_REV_INDEX),
OPT_BIT(0, "progress", &opts.flags,
N_("force progress reporting"), MIDX_PROGRESS),
+ OPT_BIT(0, "incremental", &opts.flags,
+ N_("write a new incremental MIDX"), MIDX_WRITE_INCREMENTAL),
OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
N_("write multi-pack index containing only given indexes")),
OPT_FILENAME(0, "refs-snapshot", &opts.refs_snapshot,
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index f62c0a36cb..a468ef84c3 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -337,7 +337,7 @@ static int cmp_by_tag_and_age(const void *a_, const void *b_)
return a->taggerdate != b->taggerdate;
}
-static int name_ref(const char *path, const struct object_id *oid,
+static int name_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
int flags UNUSED, void *cb_data)
{
struct object *o = parse_object(the_repository, oid);
diff --git a/builtin/notes.c b/builtin/notes.c
index 4cc5bfedc3..04f9dfb7fb 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -805,7 +805,7 @@ static int merge_commit(struct notes_merge_options *o)
{
struct strbuf msg = STRBUF_INIT;
struct object_id oid, parent_oid;
- struct notes_tree *t;
+ struct notes_tree t = {0};
struct commit *partial;
struct pretty_print_context pretty_ctx;
void *local_ref_to_free;
@@ -828,8 +828,7 @@ static int merge_commit(struct notes_merge_options *o)
else
oidclr(&parent_oid, the_repository->hash_algo);
- CALLOC_ARRAY(t, 1);
- init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
+ init_notes(&t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
o->local_ref = local_ref_to_free =
refs_resolve_refdup(get_main_ref_store(the_repository),
@@ -837,7 +836,7 @@ static int merge_commit(struct notes_merge_options *o)
if (!o->local_ref)
die(_("failed to resolve NOTES_MERGE_REF"));
- if (notes_merge_commit(o, t, partial, &oid))
+ if (notes_merge_commit(o, &t, partial, &oid))
die(_("failed to finalize notes merge"));
/* Reuse existing commit message in reflog message */
@@ -851,7 +850,7 @@ static int merge_commit(struct notes_merge_options *o)
is_null_oid(&parent_oid) ? NULL : &parent_oid,
0, UPDATE_REFS_DIE_ON_ERR);
- free_notes(t);
+ free_notes(&t);
strbuf_release(&msg);
ret = merge_abort(o);
free(local_ref_to_free);
@@ -866,7 +865,7 @@ static int git_config_get_notes_strategy(const char *key,
if (git_config_get_string(key, &value))
return 1;
if (parse_notes_merge_strategy(value, strategy))
- git_die_config(key, _("unknown notes merge strategy %s"), value);
+ git_die_config(the_repository, key, _("unknown notes merge strategy %s"), value);
free(value);
return 0;
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index f395488971..c481feadbf 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -771,7 +771,7 @@ static enum write_one_status write_one(struct hashfile *f,
return WRITE_ONE_WRITTEN;
}
-static int mark_tagged(const char *path UNUSED, const struct object_id *oid,
+static int mark_tagged(const char *path UNUSED, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data UNUSED)
{
struct object_id peeled;
@@ -3129,7 +3129,7 @@ static void add_tag_chain(const struct object_id *oid)
}
}
-static int add_ref_tag(const char *tag UNUSED, const struct object_id *oid,
+static int add_ref_tag(const char *tag UNUSED, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data UNUSED)
{
struct object_id peeled;
@@ -4076,6 +4076,7 @@ static void record_recent_commit(struct commit *commit, void *data UNUSED)
}
static int mark_bitmap_preferred_tip(const char *refname,
+ const char *referent UNUSED,
const struct object_id *oid,
int flags UNUSED,
void *data UNUSED)
diff --git a/builtin/rebase.c b/builtin/rebase.c
index e3a8e74cfc..a2c96c080e 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -186,6 +186,7 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
replay.committer_date_is_author_date =
opts->committer_date_is_author_date;
replay.ignore_date = opts->ignore_date;
+ free(replay.gpg_sign);
replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
replay.reflog_action = xstrdup(opts->reflog_action);
if (opts->strategy)
@@ -1774,7 +1775,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
/* If a hook exists, give it a chance to interrupt*/
if (!ok_to_skip_pre_rebase &&
- run_hooks_l("pre-rebase", options.upstream_arg,
+ run_hooks_l(the_repository, "pre-rebase", options.upstream_arg,
argc ? argv[0] : NULL, NULL))
die(_("The pre-rebase hook refused to rebase."));
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 339524ae2a..3f35140e48 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -300,7 +300,7 @@ static void show_ref(const char *path, const struct object_id *oid)
}
}
-static int show_ref_cb(const char *path_full, const struct object_id *oid,
+static int show_ref_cb(const char *path_full, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *data)
{
struct oidset *seen = data;
@@ -792,7 +792,7 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed,
struct child_process proc = CHILD_PROCESS_INIT;
struct async muxer;
int code;
- const char *hook_path = find_hook(hook_name);
+ const char *hook_path = find_hook(the_repository, hook_name);
if (!hook_path)
return 0;
@@ -922,7 +922,7 @@ static int run_update_hook(struct command *cmd)
{
struct child_process proc = CHILD_PROCESS_INIT;
int code;
- const char *hook_path = find_hook("update");
+ const char *hook_path = find_hook(the_repository, "update");
if (!hook_path)
return 0;
@@ -1098,7 +1098,7 @@ static int run_proc_receive_hook(struct command *commands,
int hook_use_push_options = 0;
int version = 0;
int code;
- const char *hook_path = find_hook("proc-receive");
+ const char *hook_path = find_hook(the_repository, "proc-receive");
if (!hook_path) {
rp_error("cannot find hook 'proc-receive'");
@@ -1409,7 +1409,7 @@ static const char *push_to_checkout(unsigned char *hash,
strvec_pushf(env, "GIT_WORK_TREE=%s", absolute_path(work_tree));
strvec_pushv(&opt.env, env->v);
strvec_push(&opt.args, hash_to_hex(hash));
- if (run_hooks_opt(push_to_checkout_hook, &opt))
+ if (run_hooks_opt(the_repository, push_to_checkout_hook, &opt))
return "push-to-checkout hook declined";
else
return NULL;
@@ -1618,7 +1618,7 @@ static void run_update_post_hook(struct command *commands)
struct child_process proc = CHILD_PROCESS_INIT;
const char *hook;
- hook = find_hook("post-update");
+ hook = find_hook(the_repository, "post-update");
if (!hook)
return;
diff --git a/builtin/refs.c b/builtin/refs.c
index 46dcd150d4..131f98be98 100644
--- a/builtin/refs.c
+++ b/builtin/refs.c
@@ -1,4 +1,6 @@
#include "builtin.h"
+#include "config.h"
+#include "fsck.h"
#include "parse-options.h"
#include "refs.h"
#include "repository.h"
@@ -7,6 +9,9 @@
#define REFS_MIGRATE_USAGE \
N_("git refs migrate --ref-format=<format> [--dry-run]")
+#define REFS_VERIFY_USAGE \
+ N_("git refs verify [--strict] [--verbose]")
+
static int cmd_refs_migrate(int argc, const char **argv, const char *prefix)
{
const char * const migrate_usage[] = {
@@ -58,15 +63,44 @@ out:
return err;
}
+static int cmd_refs_verify(int argc, const char **argv, const char *prefix)
+{
+ struct fsck_options fsck_refs_options = FSCK_REFS_OPTIONS_DEFAULT;
+ const char * const verify_usage[] = {
+ REFS_VERIFY_USAGE,
+ NULL,
+ };
+ struct option options[] = {
+ OPT_BOOL(0, "verbose", &fsck_refs_options.verbose, N_("be verbose")),
+ OPT_BOOL(0, "strict", &fsck_refs_options.strict, N_("enable strict checking")),
+ OPT_END(),
+ };
+ int ret;
+
+ argc = parse_options(argc, argv, prefix, options, verify_usage, 0);
+ if (argc)
+ usage(_("'git refs verify' takes no arguments"));
+
+ git_config(git_fsck_config, &fsck_refs_options);
+ prepare_repo_settings(the_repository);
+
+ ret = refs_fsck(get_main_ref_store(the_repository), &fsck_refs_options);
+
+ fsck_options_clear(&fsck_refs_options);
+ return ret;
+}
+
int cmd_refs(int argc, const char **argv, const char *prefix)
{
const char * const refs_usage[] = {
REFS_MIGRATE_USAGE,
+ REFS_VERIFY_USAGE,
NULL,
};
parse_opt_subcommand_fn *fn = NULL;
struct option opts[] = {
OPT_SUBCOMMAND("migrate", &fn, cmd_refs_migrate),
+ OPT_SUBCOMMAND("verify", &fn, cmd_refs_verify),
OPT_END(),
};
diff --git a/builtin/remote.c b/builtin/remote.c
index 9d54fddf8c..d1f9292ed2 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -544,6 +544,7 @@ struct branches_for_remote {
};
static int add_branch_for_removal(const char *refname,
+ const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flags UNUSED, void *cb_data)
{
@@ -589,7 +590,7 @@ struct rename_info {
uint32_t symrefs_nr;
};
-static int read_remote_branches(const char *refname,
+static int read_remote_branches(const char *refname, const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flags UNUSED, void *cb_data)
{
@@ -746,7 +747,7 @@ static int mv(int argc, const char **argv, const char *prefix)
strbuf_addf(&buf, "remote.%s", rename.old_name);
strbuf_addf(&buf2, "remote.%s", rename.new_name);
- if (git_config_rename_section(buf.buf, buf2.buf) < 1)
+ if (repo_config_rename_section(the_repository, buf.buf, buf2.buf) < 1)
return error(_("Could not rename config section '%s' to '%s'"),
buf.buf, buf2.buf);
@@ -959,7 +960,7 @@ static int rm(int argc, const char **argv, const char *prefix)
if (!result) {
strbuf_addf(&buf, "remote.%s", remote->name);
- if (git_config_rename_section(buf.buf, NULL) < 1) {
+ if (repo_config_rename_section(the_repository, buf.buf, NULL) < 1) {
result = error(_("Could not remove config section '%s'"), buf.buf);
goto out;
}
@@ -995,6 +996,7 @@ static void free_remote_ref_states(struct ref_states *states)
}
static int append_ref_to_tracked_list(const char *refname,
+ const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flags, void *cb_data)
{
diff --git a/builtin/repack.c b/builtin/repack.c
index f0317fa94a..62cfa50c50 100644
--- a/builtin/repack.c
+++ b/builtin/repack.c
@@ -667,6 +667,7 @@ struct midx_snapshot_ref_data {
};
static int midx_snapshot_ref_one(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flag UNUSED, void *_data)
{
@@ -1217,10 +1218,6 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (!write_midx &&
(!(pack_everything & ALL_INTO_ONE) || !is_bare_repository()))
write_bitmaps = 0;
- } else if (write_bitmaps &&
- git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0) &&
- git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP, 0)) {
- write_bitmaps = 0;
}
if (pack_kept_objects < 0)
pack_kept_objects = write_bitmaps > 0 && !write_midx;
@@ -1520,8 +1517,8 @@ int cmd_repack(int argc, const char **argv, const char *prefix)
if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0)) {
unsigned flags = 0;
- if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP, 0))
- flags |= MIDX_WRITE_BITMAP | MIDX_WRITE_REV_INDEX;
+ if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL, 0))
+ flags |= MIDX_WRITE_INCREMENTAL;
write_midx_file(get_object_directory(), NULL, NULL, flags);
}
diff --git a/builtin/replace.c b/builtin/replace.c
index 1ef833c07f..34cc4672bc 100644
--- a/builtin/replace.c
+++ b/builtin/replace.c
@@ -49,6 +49,7 @@ struct show_data {
};
static int show_reference(const char *refname,
+ const char *referent UNUSED,
const struct object_id *oid,
int flag UNUSED, void *cb_data)
{
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 5845d3f59b..4285dc34a7 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -211,7 +211,7 @@ static int show_default(void)
return 0;
}
-static int show_reference(const char *refname, const struct object_id *oid,
+static int show_reference(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data UNUSED)
{
if (ref_excluded(&ref_excludes, refname))
@@ -220,7 +220,7 @@ static int show_reference(const char *refname, const struct object_id *oid,
return 0;
}
-static int anti_reference(const char *refname, const struct object_id *oid,
+static int anti_reference(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data UNUSED)
{
show_rev(REVERSED, oid, refname);
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
index 7d797a880c..29237f653d 100644
--- a/builtin/show-branch.c
+++ b/builtin/show-branch.c
@@ -410,7 +410,7 @@ static int append_ref(const char *refname, const struct object_id *oid,
return 0;
}
-static int append_head_ref(const char *refname, const struct object_id *oid,
+static int append_head_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data UNUSED)
{
struct object_id tmp;
@@ -425,7 +425,7 @@ static int append_head_ref(const char *refname, const struct object_id *oid,
return append_ref(refname + ofs, oid, 0);
}
-static int append_remote_ref(const char *refname, const struct object_id *oid,
+static int append_remote_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data UNUSED)
{
struct object_id tmp;
@@ -451,7 +451,7 @@ static int append_tag_ref(const char *refname, const struct object_id *oid,
static const char *match_ref_pattern = NULL;
static int match_ref_slash = 0;
-static int append_matching_ref(const char *refname, const struct object_id *oid,
+static int append_matching_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag, void *cb_data)
{
/* we want to allow pattern hold/<asterisk> to show all
@@ -468,7 +468,7 @@ static int append_matching_ref(const char *refname, const struct object_id *oid,
if (wildmatch(match_ref_pattern, tail, 0))
return 0;
if (starts_with(refname, "refs/heads/"))
- return append_head_ref(refname, oid, flag, cb_data);
+ return append_head_ref(refname, NULL, oid, flag, cb_data);
if (starts_with(refname, "refs/tags/"))
return append_tag_ref(refname, oid, flag, cb_data);
return append_ref(refname, oid, 0);
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
index 85700caae9..f5899ce9ff 100644
--- a/builtin/show-ref.c
+++ b/builtin/show-ref.c
@@ -63,7 +63,7 @@ struct show_ref_data {
int show_head;
};
-static int show_ref(const char *refname, const struct object_id *oid,
+static int show_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cbdata)
{
struct show_ref_data *data = cbdata;
@@ -97,6 +97,7 @@ match:
}
static int add_existing(const char *refname,
+ const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flag UNUSED, void *cbdata)
{
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 673810d2c0..85fb23dee8 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -608,6 +608,7 @@ static void print_status(unsigned int flags, char state, const char *path,
}
static int handle_submodule_head_ref(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flags UNUSED,
void *cb_data)
@@ -1455,7 +1456,7 @@ static void deinit_submodule(const char *path, const char *prefix,
* remove the whole section so we have a clean state when
* the user later decides to init this submodule again
*/
- git_config_rename_section_in_file(NULL, sub_key, NULL);
+ repo_config_rename_section_in_file(the_repository, NULL, sub_key, NULL);
if (!(flags & OPT_QUIET))
printf(_("Submodule '%s' (%s) unregistered for path '%s'\n"),
sub->name, sub->url, displaypath);
@@ -1532,6 +1533,7 @@ struct module_clone_data {
const char *url;
int depth;
struct list_objects_filter_options *filter_options;
+ enum ref_storage_format ref_storage_format;
unsigned int quiet: 1;
unsigned int progress: 1;
unsigned int dissociate: 1;
@@ -1540,6 +1542,7 @@ struct module_clone_data {
};
#define MODULE_CLONE_DATA_INIT { \
.single_branch = -1, \
+ .ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN, \
}
struct submodule_alternate_setup {
@@ -1738,6 +1741,9 @@ static int clone_submodule(const struct module_clone_data *clone_data,
strvec_pushl(&cp.args, "--reference",
item->string, NULL);
}
+ if (clone_data->ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
+ strvec_pushf(&cp.args, "--ref-format=%s",
+ ref_storage_format_to_name(clone_data->ref_storage_format));
if (clone_data->dissociate)
strvec_push(&cp.args, "--dissociate");
if (sm_gitdir && *sm_gitdir)
@@ -1832,6 +1838,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
struct string_list reference = STRING_LIST_INIT_NODUP;
struct list_objects_filter_options filter_options =
LIST_OBJECTS_FILTER_INIT;
+ const char *ref_storage_format = NULL;
struct option module_clone_options[] = {
OPT_STRING(0, "prefix", &clone_data.prefix,
@@ -1849,6 +1856,8 @@ static int module_clone(int argc, const char **argv, const char *prefix)
OPT_STRING_LIST(0, "reference", &reference,
N_("repo"),
N_("reference repository")),
+ OPT_STRING(0, "ref-format", &ref_storage_format, N_("format"),
+ N_("specify the reference format to use")),
OPT_BOOL(0, "dissociate", &dissociate,
N_("use --reference only while cloning")),
OPT_INTEGER(0, "depth", &clone_data.depth,
@@ -1874,6 +1883,11 @@ static int module_clone(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, module_clone_options,
git_submodule_helper_usage, 0);
+ if (ref_storage_format) {
+ clone_data.ref_storage_format = ref_storage_format_by_name(ref_storage_format);
+ if (clone_data.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+ die(_("unknown ref storage format '%s'"), ref_storage_format);
+ }
clone_data.dissociate = !!dissociate;
clone_data.quiet = !!quiet;
clone_data.progress = !!progress;
@@ -1973,6 +1987,7 @@ struct update_data {
struct submodule_update_strategy update_strategy;
struct list_objects_filter_options *filter_options;
struct module_list list;
+ enum ref_storage_format ref_storage_format;
int depth;
int max_jobs;
int single_branch;
@@ -1996,6 +2011,7 @@ struct update_data {
#define UPDATE_DATA_INIT { \
.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
.list = MODULE_LIST_INIT, \
+ .ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN, \
.recommend_shallow = -1, \
.references = STRING_LIST_INIT_DUP, \
.single_branch = -1, \
@@ -2131,6 +2147,9 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
expand_list_objects_filter_spec(suc->update_data->filter_options));
if (suc->update_data->require_init)
strvec_push(&child->args, "--require-init");
+ if (suc->update_data->ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
+ strvec_pushf(&child->args, "--ref-format=%s",
+ ref_storage_format_to_name(suc->update_data->ref_storage_format));
strvec_pushl(&child->args, "--path", sub->path, NULL);
strvec_pushl(&child->args, "--name", sub->name, NULL);
strvec_pushl(&child->args, "--url", url, NULL);
@@ -2565,6 +2584,9 @@ static void update_data_to_args(const struct update_data *update_data,
for_each_string_list_item(item, &update_data->references)
strvec_pushl(args, "--reference", item->string, NULL);
}
+ if (update_data->ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
+ strvec_pushf(args, "--ref-format=%s",
+ ref_storage_format_to_name(update_data->ref_storage_format));
if (update_data->filter_options && update_data->filter_options->choice)
strvec_pushf(args, "--filter=%s",
expand_list_objects_filter_spec(
@@ -2740,6 +2762,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
struct update_data opt = UPDATE_DATA_INIT;
struct list_objects_filter_options filter_options =
LIST_OBJECTS_FILTER_INIT;
+ const char *ref_storage_format = NULL;
int ret;
struct option module_update_options[] = {
OPT__SUPER_PREFIX(&opt.super_prefix),
@@ -2763,6 +2786,8 @@ static int module_update(int argc, const char **argv, const char *prefix)
SM_UPDATE_REBASE),
OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"),
N_("reference repository")),
+ OPT_STRING(0, "ref-format", &ref_storage_format, N_("format"),
+ N_("specify the reference format to use")),
OPT_BOOL(0, "dissociate", &opt.dissociate,
N_("use --reference only while cloning")),
OPT_INTEGER(0, "depth", &opt.depth,
@@ -2806,6 +2831,12 @@ static int module_update(int argc, const char **argv, const char *prefix)
module_update_options);
}
+ if (ref_storage_format) {
+ opt.ref_storage_format = ref_storage_format_by_name(ref_storage_format);
+ if (opt.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+ die(_("unknown ref storage format '%s'"), ref_storage_format);
+ }
+
opt.filter_options = &filter_options;
opt.prefix = prefix;
@@ -3101,13 +3132,17 @@ struct add_data {
const char *sm_name;
const char *repo;
const char *realrepo;
+ enum ref_storage_format ref_storage_format;
int depth;
unsigned int force: 1;
unsigned int quiet: 1;
unsigned int progress: 1;
unsigned int dissociate: 1;
};
-#define ADD_DATA_INIT { .depth = -1 }
+#define ADD_DATA_INIT { \
+ .depth = -1, \
+ .ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN, \
+}
static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path)
{
@@ -3201,6 +3236,7 @@ static int add_submodule(const struct add_data *add_data)
string_list_append(&reference, p)->util = p;
}
+ clone_data.ref_storage_format = add_data->ref_storage_format;
clone_data.dissociate = add_data->dissociate;
if (add_data->depth >= 0)
clone_data.depth = add_data->depth;
@@ -3366,6 +3402,7 @@ static int module_add(int argc, const char **argv, const char *prefix)
{
int force = 0, quiet = 0, progress = 0, dissociate = 0;
struct add_data add_data = ADD_DATA_INIT;
+ const char *ref_storage_format = NULL;
char *to_free = NULL;
struct option options[] = {
OPT_STRING('b', "branch", &add_data.branch, N_("branch"),
@@ -3376,6 +3413,8 @@ static int module_add(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "progress", &progress, N_("force cloning progress")),
OPT_STRING(0, "reference", &add_data.reference_path, N_("repository"),
N_("reference repository")),
+ OPT_STRING(0, "ref-format", &ref_storage_format, N_("format"),
+ N_("specify the reference format to use")),
OPT_BOOL(0, "dissociate", &dissociate, N_("borrow the objects from reference repositories")),
OPT_STRING(0, "name", &add_data.sm_name, N_("name"),
N_("sets the submodule's name to the given string "
@@ -3402,6 +3441,12 @@ static int module_add(int argc, const char **argv, const char *prefix)
if (argc == 0 || argc > 2)
usage_with_options(usage, options);
+ if (ref_storage_format) {
+ add_data.ref_storage_format = ref_storage_format_by_name(ref_storage_format);
+ if (add_data.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+ die(_("unknown ref storage format '%s'"), ref_storage_format);
+ }
+
add_data.repo = argv[0];
if (argc == 1)
add_data.sm_path = git_url_basename(add_data.repo, 0, 0);
diff --git a/builtin/update-index.c b/builtin/update-index.c
index d343416ae2..35a1f957ad 100644
--- a/builtin/update-index.c
+++ b/builtin/update-index.c
@@ -1156,7 +1156,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
end_odb_transaction();
if (split_index > 0) {
- if (git_config_get_split_index() == 0)
+ if (repo_config_get_split_index(the_repository) == 0)
warning(_("core.splitIndex is set to false; "
"remove or change it, if you really want to "
"enable split index"));
@@ -1165,7 +1165,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
else
add_split_index(the_repository->index);
} else if (!split_index) {
- if (git_config_get_split_index() == 1)
+ if (repo_config_get_split_index(the_repository) == 1)
warning(_("core.splitIndex is set to true; "
"remove or change it, if you really want to "
"disable split index"));
diff --git a/builtin/worktree.c b/builtin/worktree.c
index cec3ada6b0..41e7f6a327 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -573,7 +573,7 @@ done:
NULL);
opt.dir = path;
- ret = run_hooks_opt("post-checkout", &opt);
+ ret = run_hooks_opt(the_repository, "post-checkout", &opt);
}
strvec_clear(&child_env);
@@ -626,6 +626,7 @@ static void print_preparing_worktree_line(int detach,
* Returns 0 on failure and non-zero on success.
*/
static int first_valid_ref(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flags UNUSED,
void *cb_data UNUSED)
@@ -1147,14 +1148,14 @@ static void validate_no_submodules(const struct worktree *wt)
struct strbuf path = STRBUF_INIT;
int i, found_submodules = 0;
- if (is_directory(worktree_git_path(wt, "modules"))) {
+ if (is_directory(worktree_git_path(the_repository, wt, "modules"))) {
/*
* There could be false positives, e.g. the "modules"
* directory exists but is empty. But it's a rare case and
* this simpler check is probably good enough for now.
*/
found_submodules = 1;
- } else if (read_index_from(&istate, worktree_git_path(wt, "index"),
+ } else if (read_index_from(&istate, worktree_git_path(the_repository, wt, "index"),
get_worktree_git_dir(wt)) > 0) {
for (i = 0; i < istate.cache_nr; i++) {
struct cache_entry *ce = istate.cache[i];
diff --git a/bulk-checkin.c b/bulk-checkin.c
index da8673199b..9089c214fa 100644
--- a/bulk-checkin.c
+++ b/bulk-checkin.c
@@ -61,6 +61,7 @@ static void flush_bulk_checkin_packfile(struct bulk_checkin_packfile *state)
if (state->nr_written == 0) {
close(state->f->fd);
+ free_hashfile(state->f);
unlink(state->pack_tmp_name);
goto clear_exit;
} else if (state->nr_written == 1) {
@@ -83,6 +84,7 @@ static void flush_bulk_checkin_packfile(struct bulk_checkin_packfile *state)
free(state->written[i]);
clear_exit:
+ free(state->pack_tmp_name);
free(state->written);
memset(state, 0, sizeof(*state));
diff --git a/bundle.c b/bundle.c
index ce164c37bc..b0a8a925cb 100644
--- a/bundle.c
+++ b/bundle.c
@@ -89,7 +89,12 @@ int read_bundle_header_fd(int fd, struct bundle_header *header,
goto abort;
}
- header->hash_algo = the_hash_algo;
+ /*
+ * The default hash format for bundles is SHA1, unless told otherwise
+ * by an "object-format=" capability, which is being handled in
+ * `parse_capability()`.
+ */
+ header->hash_algo = &hash_algos[GIT_HASH_SHA1];
/* The bundle header ends with an empty line */
while (!strbuf_getwholeline_fd(&buf, fd, '\n') &&
diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh
index 98dda42045..2e28d02b20 100755
--- a/ci/run-build-and-tests.sh
+++ b/ci/run-build-and-tests.sh
@@ -25,7 +25,7 @@ linux-TEST-vars)
export GIT_TEST_COMMIT_GRAPH=1
export GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=1
export GIT_TEST_MULTI_PACK_INDEX=1
- export GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=1
+ export GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=1
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
export GIT_TEST_NO_WRITE_REV_INDEX=1
export GIT_TEST_CHECKOUT_WORKERS=2
diff --git a/commit-graph.c b/commit-graph.c
index 79b0e72cc4..aa6e08eb39 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1847,6 +1847,7 @@ struct refs_cb_data {
};
static int add_ref_to_set(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flags UNUSED, void *cb_data)
{
diff --git a/commit.c b/commit.c
index 087cb19f4f..24ab5c1b50 100644
--- a/commit.c
+++ b/commit.c
@@ -1960,5 +1960,5 @@ int run_commit_hook(int editor_is_used, const char *index_file,
va_end(args);
opt.invoked_hook = invoked_hook;
- return run_hooks_opt(name, &opt);
+ return run_hooks_opt(the_repository, name, &opt);
}
diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
index 52f4f29720..fe149a1b37 100644
--- a/compat/fsmonitor/fsm-ipc-darwin.c
+++ b/compat/fsmonitor/fsm-ipc-darwin.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "gettext.h"
diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c
index 0bd5c24250..f7cc7b3be5 100644
--- a/compat/precompose_utf8.c
+++ b/compat/precompose_utf8.c
@@ -4,6 +4,7 @@
*/
#define PRECOMPOSE_UNICODE_C
+#define USE_THE_REPOSITORY_VARIABLE
#include "git-compat-util.h"
#include "config.h"
diff --git a/config.c b/config.c
index 05f369ec0d..9850897524 100644
--- a/config.c
+++ b/config.c
@@ -6,8 +6,6 @@
*
*/
-#define USE_THE_REPOSITORY_VARIABLE
-
#include "git-compat-util.h"
#include "abspath.h"
#include "advice.h"
@@ -300,13 +298,14 @@ done:
return ret;
}
-static int include_by_branch(const char *cond, size_t cond_len)
+static int include_by_branch(struct config_include_data *data,
+ const char *cond, size_t cond_len)
{
int flags;
int ret;
struct strbuf pattern = STRBUF_INIT;
- const char *refname = !the_repository->gitdir ?
- NULL : refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ const char *refname = (!data->repo || !data->repo->gitdir) ?
+ NULL : refs_resolve_ref_unsafe(get_main_ref_store(data->repo),
"HEAD", 0, NULL, &flags);
const char *shortname;
@@ -406,7 +405,7 @@ static int include_condition_is_true(const struct key_value_info *kvi,
else if (skip_prefix_mem(cond, cond_len, "gitdir/i:", &cond, &cond_len))
return include_by_gitdir(kvi, opts, cond, cond_len, 1);
else if (skip_prefix_mem(cond, cond_len, "onbranch:", &cond, &cond_len))
- return include_by_branch(cond, cond_len);
+ return include_by_branch(inc, cond, cond_len);
else if (skip_prefix_mem(cond, cond_len, "hasconfig:remote.*.url:", &cond,
&cond_len))
return include_by_remote_url(inc, cond, cond_len);
@@ -1596,7 +1595,8 @@ static int git_default_core_config(const char *var, const char *value,
else if (value[0]) {
if (strchr(value, '\n'))
return error(_("%s cannot contain newline"), var);
- comment_line_str = xstrdup(value);
+ comment_line_str = value;
+ FREE_AND_NULL(comment_line_str_to_free);
auto_comment_line_char = 0;
} else
return error(_("%s must have at least one character"), var);
@@ -2564,7 +2564,7 @@ static void git_config_check_init(struct repository *repo)
repo_read_config(repo);
}
-static void repo_config_clear(struct repository *repo)
+void repo_config_clear(struct repository *repo)
{
if (!repo->config || !repo->config->hash_initialized)
return;
@@ -2611,7 +2611,7 @@ int repo_config_get_string(struct repository *repo,
git_config_check_init(repo);
ret = git_configset_get_string(repo->config, key, dest);
if (ret < 0)
- git_die_config(key, NULL);
+ git_die_config(repo, key, NULL);
return ret;
}
@@ -2622,7 +2622,7 @@ int repo_config_get_string_tmp(struct repository *repo,
git_config_check_init(repo);
ret = git_configset_get_string_tmp(repo->config, key, dest);
if (ret < 0)
- git_die_config(key, NULL);
+ git_die_config(repo, key, NULL);
return ret;
}
@@ -2668,7 +2668,7 @@ int repo_config_get_pathname(struct repository *repo,
git_config_check_init(repo);
ret = git_configset_get_pathname(repo->config, key, dest);
if (ret < 0)
- git_die_config(key, NULL);
+ git_die_config(repo, key, NULL);
return ret;
}
@@ -2694,98 +2694,27 @@ void git_protected_config(config_fn_t fn, void *data)
configset_iter(&protected_config, fn, data);
}
-/* Functions used historically to read configuration from 'the_repository' */
-void git_config(config_fn_t fn, void *data)
-{
- repo_config(the_repository, fn, data);
-}
-
-void git_config_clear(void)
-{
- repo_config_clear(the_repository);
-}
-
-int git_config_get(const char *key)
-{
- return repo_config_get(the_repository, key);
-}
-
-int git_config_get_value(const char *key, const char **value)
-{
- return repo_config_get_value(the_repository, key, value);
-}
-
-int git_config_get_value_multi(const char *key, const struct string_list **dest)
-{
- return repo_config_get_value_multi(the_repository, key, dest);
-}
-
-int git_config_get_string_multi(const char *key,
- const struct string_list **dest)
-{
- return repo_config_get_string_multi(the_repository, key, dest);
-}
-
-int git_config_get_string(const char *key, char **dest)
-{
- return repo_config_get_string(the_repository, key, dest);
-}
-
-int git_config_get_string_tmp(const char *key, const char **dest)
-{
- return repo_config_get_string_tmp(the_repository, key, dest);
-}
-
-int git_config_get_int(const char *key, int *dest)
-{
- return repo_config_get_int(the_repository, key, dest);
-}
-
-int git_config_get_ulong(const char *key, unsigned long *dest)
-{
- return repo_config_get_ulong(the_repository, key, dest);
-}
-
-int git_config_get_bool(const char *key, int *dest)
-{
- return repo_config_get_bool(the_repository, key, dest);
-}
-
-int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)
-{
- return repo_config_get_bool_or_int(the_repository, key, is_bool, dest);
-}
-
-int git_config_get_maybe_bool(const char *key, int *dest)
+int repo_config_get_expiry(struct repository *r, const char *key, const char **output)
{
- return repo_config_get_maybe_bool(the_repository, key, dest);
-}
-
-int git_config_get_pathname(const char *key, char **dest)
-{
- return repo_config_get_pathname(the_repository, key, dest);
-}
-
-int git_config_get_expiry(const char *key, const char **output)
-{
- int ret = git_config_get_string(key, (char **)output);
+ int ret = repo_config_get_string(r, key, (char **)output);
if (ret)
return ret;
if (strcmp(*output, "now")) {
timestamp_t now = approxidate("now");
if (approxidate(*output) >= now)
- git_die_config(key, _("Invalid %s: '%s'"), key, *output);
+ git_die_config(r, key, _("Invalid %s: '%s'"), key, *output);
}
return ret;
}
-int git_config_get_expiry_in_days(const char *key, timestamp_t *expiry, timestamp_t now)
+int repo_config_get_expiry_in_days(struct repository *r, const char *key,
+ timestamp_t *expiry, timestamp_t now)
{
const char *expiry_string;
intmax_t days;
timestamp_t when;
- if (git_config_get_string_tmp(key, &expiry_string))
+ if (repo_config_get_string_tmp(r, key, &expiry_string))
return 1; /* no such thing */
if (git_parse_signed(expiry_string, &days, maximum_signed_value_of_type(int))) {
@@ -2801,21 +2730,21 @@ int git_config_get_expiry_in_days(const char *key, timestamp_t *expiry, timestam
return -1; /* thing exists but cannot be parsed */
}
-int git_config_get_split_index(void)
+int repo_config_get_split_index(struct repository *r)
{
int val;
- if (!git_config_get_maybe_bool("core.splitindex", &val))
+ if (!repo_config_get_maybe_bool(r, "core.splitindex", &val))
return val;
return -1; /* default value */
}
-int git_config_get_max_percent_split_change(void)
+int repo_config_get_max_percent_split_change(struct repository *r)
{
int val = -1;
- if (!git_config_get_int("splitindex.maxpercentchange", &val)) {
+ if (!repo_config_get_int(r, "splitindex.maxpercentchange", &val)) {
if (0 <= val && val <= 100)
return val;
@@ -2826,7 +2755,7 @@ int git_config_get_max_percent_split_change(void)
return -1; /* default value */
}
-int git_config_get_index_threads(int *dest)
+int repo_config_get_index_threads(struct repository *r, int *dest)
{
int is_bool, val;
@@ -2836,7 +2765,7 @@ int git_config_get_index_threads(int *dest)
return 0;
}
- if (!git_config_get_bool_or_int("index.threads", &is_bool, &val)) {
+ if (!repo_config_get_bool_or_int(r, "index.threads", &is_bool, &val)) {
if (is_bool)
*dest = val ? 0 : 1;
else
@@ -2857,7 +2786,7 @@ void git_die_config_linenr(const char *key, const char *filename, int linenr)
key, filename, linenr);
}
-void git_die_config(const char *key, const char *err, ...)
+void git_die_config(struct repository *r, const char *key, const char *err, ...)
{
const struct string_list *values;
struct key_value_info *kv_info;
@@ -2869,7 +2798,7 @@ void git_die_config(const char *key, const char *err, ...)
error_fn(err, params);
va_end(params);
}
- if (git_config_get_value_multi(key, &values))
+ if (repo_config_get_value_multi(r, key, &values))
BUG("for key '%s' we must have a value to report on", key);
kv_info = values->items[values->nr - 1].util;
git_die_config_linenr(key, kv_info->filename, kv_info->linenr);
@@ -3178,21 +3107,21 @@ static void maybe_remove_section(struct config_store_data *store,
*end_offset = store->parsed[store->parsed_nr - 1].end;
}
-int git_config_set_in_file_gently(const char *config_filename,
- const char *key, const char *comment, const char *value)
+int repo_config_set_in_file_gently(struct repository *r, const char *config_filename,
+ const char *key, const char *comment, const char *value)
{
- return git_config_set_multivar_in_file_gently(config_filename, key, value, NULL, comment, 0);
+ return repo_config_set_multivar_in_file_gently(r, config_filename, key, value, NULL, comment, 0);
}
-void git_config_set_in_file(const char *config_filename,
- const char *key, const char *value)
+void repo_config_set_in_file(struct repository *r, const char *config_filename,
+ const char *key, const char *value)
{
- git_config_set_multivar_in_file(config_filename, key, value, NULL, 0);
+ repo_config_set_multivar_in_file(r, config_filename, key, value, NULL, 0);
}
-int git_config_set_gently(const char *key, const char *value)
+int repo_config_set_gently(struct repository *r, const char *key, const char *value)
{
- return git_config_set_multivar_gently(key, value, NULL, 0);
+ return repo_config_set_multivar_gently(r, key, value, NULL, 0);
}
int repo_config_set_worktree_gently(struct repository *r,
@@ -3201,17 +3130,17 @@ int repo_config_set_worktree_gently(struct repository *r,
/* Only use worktree-specific config if it is already enabled. */
if (r->repository_format_worktree_config) {
char *file = repo_git_path(r, "config.worktree");
- int ret = git_config_set_multivar_in_file_gently(
- file, key, value, NULL, NULL, 0);
+ int ret = repo_config_set_multivar_in_file_gently(
+ r, file, key, value, NULL, NULL, 0);
free(file);
return ret;
}
return repo_config_set_multivar_gently(r, key, value, NULL, 0);
}
-void git_config_set(const char *key, const char *value)
+void repo_config_set(struct repository *r, const char *key, const char *value)
{
- git_config_set_multivar(key, value, NULL, 0);
+ repo_config_set_multivar(r, key, value, NULL, 0);
trace2_cmd_set_config(key, value);
}
@@ -3293,11 +3222,12 @@ static void validate_comment_string(const char *comment)
* - the config file is removed and the lock file rename()d to it.
*
*/
-int git_config_set_multivar_in_file_gently(const char *config_filename,
- const char *key, const char *value,
- const char *value_pattern,
- const char *comment,
- unsigned flags)
+int repo_config_set_multivar_in_file_gently(struct repository *r,
+ const char *config_filename,
+ const char *key, const char *value,
+ const char *value_pattern,
+ const char *comment,
+ unsigned flags)
{
int fd = -1, in_fd = -1;
int ret;
@@ -3317,7 +3247,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
store.multi_replace = (flags & CONFIG_FLAGS_MULTI_REPLACE) != 0;
if (!config_filename)
- config_filename = filename_buf = git_pathdup("config");
+ config_filename = filename_buf = repo_git_path(r, "config");
/*
* The lock serves a purpose in addition to locking: the new
@@ -3526,7 +3456,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
ret = 0;
/* Invalidate the config cache */
- git_config_clear();
+ repo_config_clear(r);
out_free:
rollback_lock_file(&lock);
@@ -3543,12 +3473,13 @@ write_err_out:
goto out_free;
}
-void git_config_set_multivar_in_file(const char *config_filename,
- const char *key, const char *value,
- const char *value_pattern, unsigned flags)
+void repo_config_set_multivar_in_file(struct repository *r,
+ const char *config_filename,
+ const char *key, const char *value,
+ const char *value_pattern, unsigned flags)
{
- if (!git_config_set_multivar_in_file_gently(config_filename, key, value,
- value_pattern, NULL, flags))
+ if (!repo_config_set_multivar_in_file_gently(r, config_filename, key, value,
+ value_pattern, NULL, flags))
return;
if (value)
die(_("could not set '%s' to '%s'"), key, value);
@@ -3556,32 +3487,27 @@ void git_config_set_multivar_in_file(const char *config_filename,
die(_("could not unset '%s'"), key);
}
-int git_config_set_multivar_gently(const char *key, const char *value,
- const char *value_pattern, unsigned flags)
-{
- return repo_config_set_multivar_gently(the_repository, key, value,
- value_pattern, flags);
-}
-
int repo_config_set_multivar_gently(struct repository *r, const char *key,
const char *value,
const char *value_pattern, unsigned flags)
{
char *file = repo_git_path(r, "config");
- int res = git_config_set_multivar_in_file_gently(file,
- key, value,
- value_pattern,
- NULL, flags);
+ int res = repo_config_set_multivar_in_file_gently(r, file,
+ key, value,
+ value_pattern,
+ NULL, flags);
free(file);
return res;
}
-void git_config_set_multivar(const char *key, const char *value,
- const char *value_pattern, unsigned flags)
+void repo_config_set_multivar(struct repository *r,
+ const char *key, const char *value,
+ const char *value_pattern, unsigned flags)
{
- git_config_set_multivar_in_file(git_path("config"),
- key, value, value_pattern,
- flags);
+ char *file = repo_git_path(r, "config");
+ repo_config_set_multivar_in_file(r, file, key, value,
+ value_pattern, flags);
+ free(file);
}
static size_t section_name_match (const char *buf, const char *name)
@@ -3643,9 +3569,11 @@ static int section_name_is_ok(const char *name)
#define GIT_CONFIG_MAX_LINE_LEN (512 * 1024)
/* if new_name == NULL, the section is removed instead */
-static int git_config_copy_or_rename_section_in_file(const char *config_filename,
- const char *old_name,
- const char *new_name, int copy)
+static int repo_config_copy_or_rename_section_in_file(
+ struct repository *r,
+ const char *config_filename,
+ const char *old_name,
+ const char *new_name, int copy)
{
int ret = 0, remove = 0;
char *filename_buf = NULL;
@@ -3666,7 +3594,7 @@ static int git_config_copy_or_rename_section_in_file(const char *config_filename
}
if (!config_filename)
- config_filename = filename_buf = git_pathdup("config");
+ config_filename = filename_buf = repo_git_path(r, "config");
out_fd = hold_lock_file_for_update(&lock, config_filename, 0);
if (out_fd < 0) {
@@ -3809,28 +3737,28 @@ out_no_rollback:
return ret;
}
-int git_config_rename_section_in_file(const char *config_filename,
- const char *old_name, const char *new_name)
+int repo_config_rename_section_in_file(struct repository *r, const char *config_filename,
+ const char *old_name, const char *new_name)
{
- return git_config_copy_or_rename_section_in_file(config_filename,
+ return repo_config_copy_or_rename_section_in_file(r, config_filename,
old_name, new_name, 0);
}
-int git_config_rename_section(const char *old_name, const char *new_name)
+int repo_config_rename_section(struct repository *r, const char *old_name, const char *new_name)
{
- return git_config_rename_section_in_file(NULL, old_name, new_name);
+ return repo_config_rename_section_in_file(r, NULL, old_name, new_name);
}
-int git_config_copy_section_in_file(const char *config_filename,
- const char *old_name, const char *new_name)
+int repo_config_copy_section_in_file(struct repository *r, const char *config_filename,
+ const char *old_name, const char *new_name)
{
- return git_config_copy_or_rename_section_in_file(config_filename,
+ return repo_config_copy_or_rename_section_in_file(r, config_filename,
old_name, new_name, 1);
}
-int git_config_copy_section(const char *old_name, const char *new_name)
+int repo_config_copy_section(struct repository *r, const char *old_name, const char *new_name)
{
- return git_config_copy_section_in_file(NULL, old_name, new_name);
+ return repo_config_copy_section_in_file(r, NULL, old_name, new_name);
}
/*
diff --git a/config.h b/config.h
index 54b47dec9e..4d319a4193 100644
--- a/config.h
+++ b/config.h
@@ -26,7 +26,7 @@ struct object_id;
/* git_config_parse_key() returns these negated: */
#define CONFIG_INVALID_KEY 1
#define CONFIG_NO_SECTION_OR_NAME 2
-/* git_config_set_gently(), git_config_set_multivar_gently() return the above or these: */
+/* repo_config_set_gently(), repo_config_set_multivar_gently() return the above or these: */
#define CONFIG_NO_LOCK -1
#define CONFIG_INVALID_FILE 3
#define CONFIG_NO_WRITE 4
@@ -170,9 +170,9 @@ int git_default_config(const char *, const char *,
/**
* Read a specific file in git-config format.
- * This function takes the same callback and data parameters as `git_config`.
+ * This function takes the same callback and data parameters as `repo_config`.
*
- * Unlike git_config(), this function does not respect includes.
+ * Unlike repo_config(), this function does not respect includes.
*/
int git_config_from_file(config_fn_t fn, const char *, void *);
@@ -198,9 +198,9 @@ void read_very_early_config(config_fn_t cb, void *data);
/**
* Most programs will simply want to look up variables in all config files
* that Git knows about, using the normal precedence rules. To do this,
- * call `git_config` with a callback function and void data pointer.
+ * call `repo_config` with a callback function and void data pointer.
*
- * `git_config` will read all config sources in order of increasing
+ * `repo_config` will read all config sources in order of increasing
* priority. Thus a callback should typically overwrite previously-seen
* entries with new ones (e.g., if both the user-wide `~/.gitconfig` and
* repo-specific `.git/config` contain `color.ui`, the config machinery
@@ -210,11 +210,11 @@ void read_very_early_config(config_fn_t cb, void *data);
*
* Unlike git_config_from_file(), this function respects includes.
*/
-void git_config(config_fn_t fn, void *);
+void repo_config(struct repository *r, config_fn_t fn, void *);
/**
* Lets the caller examine config while adjusting some of the default
- * behavior of `git_config`. It should almost never be used by "regular"
+ * behavior of `repo_config`. It should almost never be used by "regular"
* Git code that is looking up configuration variables.
* It is intended for advanced callers like `git-config`, which are
* intentionally tweaking the normal config-lookup process.
@@ -223,12 +223,12 @@ void git_config(config_fn_t fn, void *);
* - `config_source`
* If this parameter is non-NULL, it specifies the source to parse for
* configuration, rather than looking in the usual files. See `struct
- * git_config_source` in `config.h` for details. Regular `git_config` defaults
+ * git_config_source` in `config.h` for details. Regular `repo_config` defaults
* to `NULL`.
*
* - `opts`
* Specify options to adjust the behavior of parsing config files. See `struct
- * config_options` in `config.h` for details. As an example: regular `git_config`
+ * config_options` in `config.h` for details. As an example: regular `repo_config`
* sets `opts.respect_includes` to `1` by default.
*/
int config_with_options(config_fn_t fn, void *,
@@ -297,15 +297,16 @@ int git_config_pathname(char **, const char *, const char *);
int git_config_expiry_date(timestamp_t *, const char *, const char *);
int git_config_color(char *, const char *, const char *);
-int git_config_set_in_file_gently(const char *, const char *, const char *, const char *);
+int repo_config_set_in_file_gently(struct repository *r, const char *config_filename,
+ const char *key, const char *comment, const char *value);
/**
* write config values to a specific config file, takes a key/value pair as
* parameter.
*/
-void git_config_set_in_file(const char *, const char *, const char *);
+void repo_config_set_in_file(struct repository *, const char *, const char *, const char *);
-int git_config_set_gently(const char *, const char *);
+int repo_config_set_gently(struct repository *r, const char *, const char *);
/**
* Write a config value that should apply to the current worktree. If
@@ -317,13 +318,13 @@ int repo_config_set_worktree_gently(struct repository *, const char *, const cha
/**
* write config values to `.git/config`, takes a key/value pair as parameter.
*/
-void git_config_set(const char *, const char *);
+void repo_config_set(struct repository *, const char *, const char *);
int git_config_parse_key(const char *, char **, size_t *);
/*
* The following macros specify flag bits that alter the behavior
- * of the git_config_set_multivar*() methods.
+ * of the repo_config_set_multivar*() methods.
*/
/*
@@ -340,10 +341,9 @@ int git_config_parse_key(const char *, char **, size_t *);
*/
#define CONFIG_FLAGS_FIXED_VALUE (1 << 1)
-int git_config_set_multivar_gently(const char *, const char *, const char *, unsigned);
-void git_config_set_multivar(const char *, const char *, const char *, unsigned);
int repo_config_set_multivar_gently(struct repository *, const char *, const char *, const char *, unsigned);
-int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, const char *, unsigned);
+void repo_config_set_multivar(struct repository *r, const char *, const char *, const char *, unsigned);
+int repo_config_set_multivar_in_file_gently(struct repository *, const char *, const char *, const char *, const char *, const char *, unsigned);
char *git_config_prepare_comment_string(const char *);
@@ -367,11 +367,12 @@ char *git_config_prepare_comment_string(const char *);
*
* It returns 0 on success.
*/
-void git_config_set_multivar_in_file(const char *config_filename,
- const char *key,
- const char *value,
- const char *value_pattern,
- unsigned flags);
+void repo_config_set_multivar_in_file(struct repository *r,
+ const char *config_filename,
+ const char *key,
+ const char *value,
+ const char *value_pattern,
+ unsigned flags);
/**
* rename or remove sections in the config file
@@ -379,11 +380,11 @@ void git_config_set_multivar_in_file(const char *config_filename,
* If NULL is passed through `new_name` parameter,
* the section will be removed from the config file.
*/
-int git_config_rename_section(const char *, const char *);
+int repo_config_rename_section(struct repository *, const char *, const char *);
-int git_config_rename_section_in_file(const char *, const char *, const char *);
-int git_config_copy_section(const char *, const char *);
-int git_config_copy_section_in_file(const char *, const char *, const char *);
+int repo_config_rename_section_in_file(struct repository *, const char *, const char *, const char *);
+int repo_config_copy_section(struct repository *, const char *, const char *);
+int repo_config_copy_section_in_file(struct repository *, const char *, const char *, const char *);
int git_config_system(void);
int config_error_nonbool(const char *);
#if defined(__GNUC__)
@@ -550,39 +551,11 @@ int git_configset_get_bool_or_int(struct config_set *cs, const char *key, int *i
int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);
int git_configset_get_pathname(struct config_set *cs, const char *key, char **dest);
-/* Functions for reading a repository's config */
-struct repository;
-void repo_config(struct repository *repo, config_fn_t fn, void *data);
-
/**
* Run only the discover part of the repo_config_get_*() functions
* below, in addition to 1 if not found, returns negative values on
* error (e.g. if the key itself is invalid).
*/
-RESULT_MUST_BE_USED
-int repo_config_get(struct repository *repo, const char *key);
-int repo_config_get_value(struct repository *repo,
- const char *key, const char **value);
-RESULT_MUST_BE_USED
-int repo_config_get_value_multi(struct repository *repo, const char *key,
- const struct string_list **dest);
-RESULT_MUST_BE_USED
-int repo_config_get_string_multi(struct repository *repo, const char *key,
- const struct string_list **dest);
-int repo_config_get_string(struct repository *repo,
- const char *key, char **dest);
-int repo_config_get_string_tmp(struct repository *repo,
- const char *key, const char **dest);
-int repo_config_get_int(struct repository *repo,
- const char *key, int *dest);
-int repo_config_get_ulong(struct repository *repo,
- const char *key, unsigned long *dest);
-int repo_config_get_bool(struct repository *repo,
- const char *key, int *dest);
-int repo_config_get_bool_or_int(struct repository *repo,
- const char *key, int *is_bool, int *dest);
-int repo_config_get_maybe_bool(struct repository *repo,
- const char *key, int *dest);
int repo_config_get_pathname(struct repository *repo,
const char *key, char **dest);
@@ -598,17 +571,17 @@ void git_protected_config(config_fn_t fn, void *data);
* -------------------------------
*
* For programs wanting to query for specific variables in a non-callback
- * manner, the config API provides two functions `git_config_get_value`
- * and `git_config_get_value_multi`. They both read values from an internal
+ * manner, the config API provides two functions `repo_config_get_value`
+ * and `repo_config_get_value_multi`. They both read values from an internal
* cache generated previously from reading the config files.
*
- * For those git_config_get*() functions that aren't documented,
+ * For those repo_config_get*() functions that aren't documented,
* consult the corresponding repo_config_get*() function's
* documentation.
*/
RESULT_MUST_BE_USED
-int git_config_get(const char *key);
+int repo_config_get(struct repository *r, const char *key);
/**
* Finds the highest-priority value for the configuration variable `key`,
@@ -617,7 +590,7 @@ int git_config_get(const char *key);
* `value`. The caller should not free or modify `value`, as it is owned
* by the cache.
*/
-int git_config_get_value(const char *key, const char **value);
+int repo_config_get_value(struct repository *r, const char *key, const char **value);
/**
* Finds and returns the value list, sorted in order of increasing priority
@@ -628,16 +601,16 @@ int git_config_get_value(const char *key, const char **value);
* owned by the cache.
*/
RESULT_MUST_BE_USED
-int git_config_get_value_multi(const char *key,
- const struct string_list **dest);
-RESULT_MUST_BE_USED
-int git_config_get_string_multi(const char *key,
+int repo_config_get_value_multi(struct repository *r, const char *key,
const struct string_list **dest);
+RESULT_MUST_BE_USED
+int repo_config_get_string_multi(struct repository *r, const char *key,
+ const struct string_list **dest);
/**
* Resets and invalidates the config cache.
*/
-void git_config_clear(void);
+void repo_config_clear(struct repository *repo);
/**
* Allocates and copies the retrieved string into the `dest` parameter for
@@ -645,14 +618,15 @@ void git_config_clear(void);
* error message and returns -1. When the configuration variable `key` is
* not found, returns 1 without touching `dest`.
*/
-int git_config_get_string(const char *key, char **dest);
+int repo_config_get_string(struct repository *r, const char *key, char **dest);
/**
- * Similar to `git_config_get_string`, but does not allocate any new
+ * Similar to `repo_config_get_string`, but does not allocate any new
* memory; on success `dest` will point to memory owned by the config
* machinery, which could be invalidated if it is discarded and reloaded.
*/
-int git_config_get_string_tmp(const char *key, const char **dest);
+int repo_config_get_string_tmp(struct repository *r,
+ const char *key, const char **dest);
/**
* Finds and parses the value to an integer for the configuration variable
@@ -660,12 +634,13 @@ int git_config_get_string_tmp(const char *key, const char **dest);
* `dest` and returns 0. When the configuration variable `key` is not found,
* returns 1 without touching `dest`.
*/
-int git_config_get_int(const char *key, int *dest);
+int repo_config_get_int(struct repository *r, const char *key, int *dest);
/**
- * Similar to `git_config_get_int` but for unsigned longs.
+ * Similar to `repo_config_get_int` but for unsigned longs.
*/
-int git_config_get_ulong(const char *key, unsigned long *dest);
+int repo_config_get_ulong(struct repository *r,
+ const char *key, unsigned long *dest);
/**
* Finds and parses the value into a boolean value, for the configuration
@@ -676,47 +651,45 @@ int git_config_get_ulong(const char *key, unsigned long *dest);
* configuration variable `key` is not found, returns 1 without touching
* `dest`.
*/
-int git_config_get_bool(const char *key, int *dest);
+int repo_config_get_bool(struct repository *r, const char *key, int *dest);
/**
- * Similar to `git_config_get_bool`, except that integers are copied as-is,
+ * Similar to `repo_config_get_bool`, except that integers are copied as-is,
* and `is_bool` flag is unset.
*/
-int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest);
+int repo_config_get_bool_or_int(struct repository *r, const char *key,
+ int *is_bool, int *dest);
/**
- * Similar to `git_config_get_bool`, except that it returns -1 on error
+ * Similar to `repo_config_get_bool`, except that it returns -1 on error
* rather than dying.
*/
-int git_config_get_maybe_bool(const char *key, int *dest);
-
-/**
- * Similar to `git_config_get_string`, but expands `~` or `~user` into
- * the user's home directory when found at the beginning of the path.
- */
-int git_config_get_pathname(const char *key, char **dest);
+int repo_config_get_maybe_bool(struct repository *r,
+ const char *key, int *dest);
-int git_config_get_index_threads(int *dest);
-int git_config_get_split_index(void);
-int git_config_get_max_percent_split_change(void);
+int repo_config_get_index_threads(struct repository *r, int *dest);
+int repo_config_get_split_index(struct repository *r);
+int repo_config_get_max_percent_split_change(struct repository *r);
/* This dies if the configured or default date is in the future */
-int git_config_get_expiry(const char *key, const char **output);
+int repo_config_get_expiry(struct repository *r, const char *key, const char **output);
/* parse either "this many days" integer, or "5.days.ago" approxidate */
-int git_config_get_expiry_in_days(const char *key, timestamp_t *, timestamp_t now);
+int repo_config_get_expiry_in_days(struct repository *r, const char *key,
+ timestamp_t *, timestamp_t now);
/**
* First prints the error message specified by the caller in `err` and then
* dies printing the line number and the file name of the highest priority
* value for the configuration variable `key`.
*/
-NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));
+NORETURN void git_die_config(struct repository *r, const char *key, const char *err, ...)
+ __attribute__((format(printf, 3, 4)));
/**
* Helper function which formats the die error message according to the
* parameters entered. Used by `git_die_config()`. It can be used by callers
- * handling `git_config_get_value_multi()` to print the correct error message
+ * handling `repo_config_get_value_multi()` to print the correct error message
* for the desired value.
*/
NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr);
@@ -725,4 +698,140 @@ NORETURN void git_die_config_linenr(const char *key, const char *filename, int l
lookup_config(mapping, ARRAY_SIZE(mapping), var)
int lookup_config(const char **mapping, int nr_mapping, const char *var);
+# ifdef USE_THE_REPOSITORY_VARIABLE
+static inline void git_config(config_fn_t fn, void *data)
+{
+ repo_config(the_repository, fn, data);
+}
+
+static inline void git_config_clear(void)
+{
+ repo_config_clear(the_repository);
+}
+
+static inline int git_config_get(const char *key)
+{
+ return repo_config_get(the_repository, key);
+}
+
+static inline int git_config_get_value(const char *key, const char **value)
+{
+ return repo_config_get_value(the_repository, key, value);
+}
+
+static inline int git_config_get_value_multi(const char *key, const struct string_list **dest)
+{
+ return repo_config_get_value_multi(the_repository, key, dest);
+}
+
+static inline int git_config_get_string_multi(const char *key,
+ const struct string_list **dest)
+{
+ return repo_config_get_string_multi(the_repository, key, dest);
+}
+
+static inline int git_config_get_string(const char *key, char **dest)
+{
+ return repo_config_get_string(the_repository, key, dest);
+}
+
+static inline int git_config_get_string_tmp(const char *key, const char **dest)
+{
+ return repo_config_get_string_tmp(the_repository, key, dest);
+}
+
+static inline int git_config_get_int(const char *key, int *dest)
+{
+ return repo_config_get_int(the_repository, key, dest);
+}
+
+static inline int git_config_get_ulong(const char *key, unsigned long *dest)
+{
+ return repo_config_get_ulong(the_repository, key, dest);
+}
+
+static inline int git_config_get_bool(const char *key, int *dest)
+{
+ return repo_config_get_bool(the_repository, key, dest);
+}
+
+static inline int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest)
+{
+ return repo_config_get_bool_or_int(the_repository, key, is_bool, dest);
+}
+
+static inline int git_config_get_maybe_bool(const char *key, int *dest)
+{
+ return repo_config_get_maybe_bool(the_repository, key, dest);
+}
+
+static inline int git_config_get_pathname(const char *key, char **dest)
+{
+ return repo_config_get_pathname(the_repository, key, dest);
+}
+
+static inline void git_config_set_in_file(const char *config_filename,
+ const char *key, const char *value)
+{
+ repo_config_set_in_file(the_repository, config_filename, key, value);
+}
+
+static inline int git_config_set_gently(const char *key, const char *value)
+{
+ return repo_config_set_gently(the_repository, key, value);
+}
+
+static inline void git_config_set(const char *key, const char *value)
+{
+ repo_config_set(the_repository, key, value);
+}
+
+static inline int git_config_set_in_file_gently(
+ const char *config_filename,
+ const char *key,
+ const char *comment,
+ const char *value)
+{
+ return repo_config_set_in_file_gently(the_repository, config_filename,
+ key, comment, value);
+}
+
+static inline int git_config_set_multivar_in_file_gently(
+ const char *config_filename,
+ const char *key, const char *value,
+ const char *value_pattern,
+ const char *comment,
+ unsigned flags)
+{
+ return repo_config_set_multivar_in_file_gently(the_repository, config_filename,
+ key, value, value_pattern,
+ comment, flags);
+}
+
+static inline void git_config_set_multivar_in_file(
+ const char *config_filename,
+ const char *key,
+ const char *value,
+ const char *value_pattern,
+ unsigned flags)
+{
+ repo_config_set_multivar_in_file(the_repository, config_filename,
+ key, value, value_pattern, flags);
+}
+
+static inline int git_config_set_multivar_gently(const char *key, const char *value,
+ const char *value_pattern, unsigned flags)
+{
+ return repo_config_set_multivar_gently(the_repository, key, value,
+ value_pattern, flags);
+}
+
+static inline void git_config_set_multivar(const char *key, const char *value,
+ const char *value_pattern, unsigned flags)
+{
+ repo_config_set_multivar(the_repository, key, value,
+ value_pattern, flags);
+}
+# endif /* USE_THE_REPOSITORY_VARIABLE */
+
#endif /* CONFIG_H */
diff --git a/connect.c b/connect.c
index cf84e631e9..6829ab3974 100644
--- a/connect.c
+++ b/connect.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "environment.h"
diff --git a/credential.c b/credential.c
index 4b1a2b94fe..ee46351ce0 100644
--- a/credential.c
+++ b/credential.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "config.h"
diff --git a/csum-file.c b/csum-file.c
index 2131ee6b12..bf82ad8f9f 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -56,7 +56,7 @@ void hashflush(struct hashfile *f)
}
}
-static void free_hashfile(struct hashfile *f)
+void free_hashfile(struct hashfile *f)
{
free(f->buffer);
free(f->check_buffer);
diff --git a/csum-file.h b/csum-file.h
index 36c7c5585f..7c73da0a40 100644
--- a/csum-file.h
+++ b/csum-file.h
@@ -46,6 +46,16 @@ int hashfile_truncate(struct hashfile *, struct hashfile_checkpoint *);
struct hashfile *hashfd(int fd, const char *name);
struct hashfile *hashfd_check(const char *name);
struct hashfile *hashfd_throughput(int fd, const char *name, struct progress *tp);
+
+/*
+ * Free the hashfile without flushing its contents to disk. This only
+ * needs to be called when not calling `finalize_hashfile()`.
+ */
+void free_hashfile(struct hashfile *f);
+
+/*
+ * Finalize the hashfile by flushing data to disk and free'ing it.
+ */
int finalize_hashfile(struct hashfile *, unsigned char *, enum fsync_component, unsigned int);
void discard_hashfile(struct hashfile *);
void hashwrite(struct hashfile *, const void *, unsigned int);
diff --git a/daemon.c b/daemon.c
index 17d331b2f3..c65b068b76 100644
--- a/daemon.c
+++ b/daemon.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "config.h"
diff --git a/delta-islands.c b/delta-islands.c
index ffe1ca2814..8443551259 100644
--- a/delta-islands.c
+++ b/delta-islands.c
@@ -390,7 +390,7 @@ static void add_ref_to_island(kh_str_t *remote_islands, const char *island_name,
rl->hash += sha_core;
}
-static int find_island_for_ref(const char *refname, const struct object_id *oid,
+static int find_island_for_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flags UNUSED, void *cb)
{
struct island_load_data *ild = cb;
diff --git a/diff.c b/diff.c
index ebb7538e04..4035a9374d 100644
--- a/diff.c
+++ b/diff.c
@@ -5464,9 +5464,13 @@ static int diff_opt_ignore_regex(const struct option *opt,
regex_t *regex;
BUG_ON_OPT_NEG(unset);
+
regex = xmalloc(sizeof(*regex));
- if (regcomp(regex, arg, REG_EXTENDED | REG_NEWLINE))
+ if (regcomp(regex, arg, REG_EXTENDED | REG_NEWLINE)) {
+ free(regex);
return error(_("invalid regex given to -I: '%s'"), arg);
+ }
+
ALLOC_GROW(options->ignore_regex, options->ignore_regex_nr + 1,
options->ignore_regex_alloc);
options->ignore_regex[options->ignore_regex_nr++] = regex;
@@ -6713,6 +6717,16 @@ void diff_free(struct diff_options *options)
if (options->no_free)
return;
+ if (options->objfind) {
+ oidset_clear(options->objfind);
+ FREE_AND_NULL(options->objfind);
+ }
+
+ for (size_t i = 0; i < options->anchors_nr; i++)
+ free(options->anchors[i]);
+ FREE_AND_NULL(options->anchors);
+ options->anchors_nr = options->anchors_alloc = 0;
+
diff_free_file(options);
diff_free_ignore_regex(options);
clear_pathspec(&options->pathspec);
diff --git a/editor.c b/editor.c
index d1ba2d7c34..6b9ce81d5f 100644
--- a/editor.c
+++ b/editor.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "advice.h"
@@ -133,14 +135,17 @@ int launch_sequence_editor(const char *path, struct strbuf *buffer,
return launch_specified_editor(git_sequence_editor(), path, buffer, env);
}
-int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
+int strbuf_edit_interactively(struct repository *r,
+ struct strbuf *buffer, const char *path,
const char *const *env)
{
- char *path2 = NULL;
+ struct strbuf sb = STRBUF_INIT;
int fd, res = 0;
- if (!is_absolute_path(path))
- path = path2 = xstrdup(git_path("%s", path));
+ if (!is_absolute_path(path)) {
+ strbuf_repo_git_path(&sb, r, "%s", path);
+ path = sb.buf;
+ }
fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (fd < 0)
@@ -157,6 +162,6 @@ int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
unlink(path);
}
- free(path2);
+ strbuf_release(&sb);
return res;
}
diff --git a/editor.h b/editor.h
index 8016bb5e00..f1c41df378 100644
--- a/editor.h
+++ b/editor.h
@@ -1,6 +1,7 @@
#ifndef EDITOR_H
#define EDITOR_H
+struct repository;
struct strbuf;
const char *git_editor(void);
@@ -28,7 +29,7 @@ int launch_sequence_editor(const char *path, struct strbuf *buffer,
*
* If `path` is relative, it refers to a file in the `.git` directory.
*/
-int strbuf_edit_interactively(struct strbuf *buffer, const char *path,
- const char *const *env);
+int strbuf_edit_interactively(struct repository *r, struct strbuf *buffer,
+ const char *path, const char *const *env);
#endif
diff --git a/environment.c b/environment.c
index 5cea2c9f54..1d6c48b52d 100644
--- a/environment.c
+++ b/environment.c
@@ -114,6 +114,7 @@ int protect_ntfs = PROTECT_NTFS_DEFAULT;
* that is subject to stripspace.
*/
const char *comment_line_str = "#";
+char *comment_line_str_to_free;
int auto_comment_line_char;
/* Parallel index stat data preload? */
diff --git a/environment.h b/environment.h
index e9f01d4d11..0148738ed6 100644
--- a/environment.h
+++ b/environment.h
@@ -9,6 +9,7 @@ struct strvec;
* that is subject to stripspace.
*/
extern const char *comment_line_str;
+extern char *comment_line_str_to_free;
extern int auto_comment_line_char;
/*
diff --git a/fetch-pack.c b/fetch-pack.c
index 732511604b..58b4581ad8 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -183,6 +183,7 @@ static int rev_list_insert_ref(struct fetch_negotiator *negotiator,
}
static int rev_list_insert_ref_oid(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flag UNUSED,
void *cb_data)
@@ -610,6 +611,7 @@ static int mark_complete(const struct object_id *oid)
}
static int mark_complete_oid(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flag UNUSED,
void *cb_data UNUSED)
diff --git a/fsck.c b/fsck.c
index eea7145470..3756f52459 100644
--- a/fsck.c
+++ b/fsck.c
@@ -205,7 +205,7 @@ void fsck_set_msg_types(struct fsck_options *options, const char *values)
if (!strcmp(buf, "skiplist")) {
if (equal == len)
die("skiplist requires a path");
- oidset_parse_file(&options->skiplist, buf + equal + 1,
+ oidset_parse_file(&options->skip_oids, buf + equal + 1,
the_repository->hash_algo);
buf += len + 1;
continue;
@@ -223,15 +223,18 @@ void fsck_set_msg_types(struct fsck_options *options, const char *values)
static int object_on_skiplist(struct fsck_options *opts,
const struct object_id *oid)
{
- return opts && oid && oidset_contains(&opts->skiplist, oid);
+ return opts && oid && oidset_contains(&opts->skip_oids, oid);
}
-__attribute__((format (printf, 5, 6)))
-static int report(struct fsck_options *options,
- const struct object_id *oid, enum object_type object_type,
- enum fsck_msg_id msg_id, const char *fmt, ...)
+/*
+ * Provide the common functionality for either fscking refs or objects.
+ * It will get the current msg error type and call the error_func callback
+ * which is registered in the "fsck_options" struct.
+ */
+static int fsck_vreport(struct fsck_options *options,
+ void *fsck_report,
+ enum fsck_msg_id msg_id, const char *fmt, va_list ap)
{
- va_list ap;
struct strbuf sb = STRBUF_INIT;
enum fsck_msg_type msg_type = fsck_msg_type(msg_id, options);
int result;
@@ -239,9 +242,6 @@ static int report(struct fsck_options *options,
if (msg_type == FSCK_IGNORE)
return 0;
- if (object_on_skiplist(options, oid))
- return 0;
-
if (msg_type == FSCK_FATAL)
msg_type = FSCK_ERROR;
else if (msg_type == FSCK_INFO)
@@ -250,16 +250,49 @@ static int report(struct fsck_options *options,
prepare_msg_ids();
strbuf_addf(&sb, "%s: ", msg_id_info[msg_id].camelcased);
- va_start(ap, fmt);
strbuf_vaddf(&sb, fmt, ap);
- result = options->error_func(options, oid, object_type,
+ result = options->error_func(options, fsck_report,
msg_type, msg_id, sb.buf);
strbuf_release(&sb);
+
+ return result;
+}
+
+__attribute__((format (printf, 5, 6)))
+static int report(struct fsck_options *options,
+ const struct object_id *oid, enum object_type object_type,
+ enum fsck_msg_id msg_id, const char *fmt, ...)
+{
+ va_list ap;
+ struct fsck_object_report report = {
+ .oid = oid,
+ .object_type = object_type
+ };
+ int result;
+
+ if (object_on_skiplist(options, oid))
+ return 0;
+
+ va_start(ap, fmt);
+ result = fsck_vreport(options, &report, msg_id, fmt, ap);
va_end(ap);
return result;
}
+int fsck_report_ref(struct fsck_options *options,
+ struct fsck_ref_report *report,
+ enum fsck_msg_id msg_id,
+ const char *fmt, ...)
+{
+ va_list ap;
+ int result;
+ va_start(ap, fmt);
+ result = fsck_vreport(options, report, msg_id, fmt, ap);
+ va_end(ap);
+ return result;
+}
+
void fsck_enable_object_names(struct fsck_options *options)
{
if (!options->object_names)
@@ -1200,13 +1233,15 @@ int fsck_buffer(const struct object_id *oid, enum object_type type,
type);
}
-int fsck_error_function(struct fsck_options *o,
- const struct object_id *oid,
- enum object_type object_type UNUSED,
- enum fsck_msg_type msg_type,
- enum fsck_msg_id msg_id UNUSED,
- const char *message)
+int fsck_objects_error_function(struct fsck_options *o,
+ void *fsck_report,
+ enum fsck_msg_type msg_type,
+ enum fsck_msg_id msg_id UNUSED,
+ const char *message)
{
+ struct fsck_object_report *report = fsck_report;
+ const struct object_id *oid = report->oid;
+
if (msg_type == FSCK_WARN) {
warning("object %s: %s", fsck_describe_object(o, oid), message);
return 0;
@@ -1215,6 +1250,32 @@ int fsck_error_function(struct fsck_options *o,
return 1;
}
+int fsck_refs_error_function(struct fsck_options *options UNUSED,
+ void *fsck_report,
+ enum fsck_msg_type msg_type,
+ enum fsck_msg_id msg_id UNUSED,
+ const char *message)
+{
+ struct fsck_ref_report *report = fsck_report;
+ struct strbuf sb = STRBUF_INIT;
+ int ret = 0;
+
+ strbuf_addstr(&sb, report->path);
+
+ if (report->oid)
+ strbuf_addf(&sb, " -> (%s)", oid_to_hex(report->oid));
+ else if (report->referent)
+ strbuf_addf(&sb, " -> (%s)", report->referent);
+
+ if (msg_type == FSCK_WARN)
+ warning("%s: %s", sb.buf, message);
+ else
+ ret = error("%s: %s", sb.buf, message);
+
+ strbuf_release(&sb);
+ return ret;
+}
+
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)
@@ -1270,6 +1331,17 @@ int fsck_finish(struct fsck_options *options)
return ret;
}
+void fsck_options_clear(struct fsck_options *options)
+{
+ free(options->msg_type);
+ oidset_clear(&options->skip_oids);
+ oidset_clear(&options->gitmodules_found);
+ oidset_clear(&options->gitmodules_done);
+ oidset_clear(&options->gitattributes_found);
+ oidset_clear(&options->gitattributes_done);
+ kh_clear_oid_map(options->object_names);
+}
+
int git_fsck_config(const char *var, const char *value,
const struct config_context *ctx, void *cb)
{
@@ -1303,16 +1375,17 @@ int git_fsck_config(const char *var, const char *value,
* Custom error callbacks that are used in more than one place.
*/
-int fsck_error_cb_print_missing_gitmodules(struct fsck_options *o,
- const struct object_id *oid,
- enum object_type object_type,
- enum fsck_msg_type msg_type,
- enum fsck_msg_id msg_id,
- const char *message)
+int fsck_objects_error_cb_print_missing_gitmodules(struct fsck_options *o,
+ void *fsck_report,
+ enum fsck_msg_type msg_type,
+ enum fsck_msg_id msg_id,
+ const char *message)
{
if (msg_id == FSCK_MSG_GITMODULES_MISSING) {
- puts(oid_to_hex(oid));
+ struct fsck_object_report *report = fsck_report;
+ puts(oid_to_hex(report->oid));
return 0;
}
- return fsck_error_function(o, oid, object_type, msg_type, msg_id, message);
+ return fsck_objects_error_function(o, fsck_report,
+ msg_type, msg_id, message);
}
diff --git a/fsck.h b/fsck.h
index 6085a384f6..500b4c04d2 100644
--- a/fsck.h
+++ b/fsck.h
@@ -31,6 +31,8 @@ enum fsck_msg_type {
FUNC(BAD_NAME, ERROR) \
FUNC(BAD_OBJECT_SHA1, ERROR) \
FUNC(BAD_PARENT_SHA1, ERROR) \
+ FUNC(BAD_REF_FILETYPE, ERROR) \
+ FUNC(BAD_REF_NAME, ERROR) \
FUNC(BAD_TIMEZONE, ERROR) \
FUNC(BAD_TREE, ERROR) \
FUNC(BAD_TREE_SHA1, ERROR) \
@@ -114,29 +116,49 @@ int is_valid_msg_type(const char *msg_id, const char *msg_type);
typedef int (*fsck_walk_func)(struct object *obj, enum object_type object_type,
void *data, struct fsck_options *options);
-/* callback for fsck_object, type is FSCK_ERROR or FSCK_WARN */
+/*
+ * Callback for reporting errors either for objects or refs. The "fsck_report"
+ * is a generic pointer that can be used to pass any information.
+ */
typedef int (*fsck_error)(struct fsck_options *o,
- const struct object_id *oid, enum object_type object_type,
+ void *fsck_report,
enum fsck_msg_type msg_type, enum fsck_msg_id msg_id,
const char *message);
-int fsck_error_function(struct fsck_options *o,
- const struct object_id *oid, enum object_type object_type,
- enum fsck_msg_type msg_type, enum fsck_msg_id msg_id,
- const char *message);
-int fsck_error_cb_print_missing_gitmodules(struct fsck_options *o,
- const struct object_id *oid,
- enum object_type object_type,
- enum fsck_msg_type msg_type,
- enum fsck_msg_id msg_id,
- const char *message);
+int fsck_objects_error_function(struct fsck_options *o,
+ void *fsck_report,
+ enum fsck_msg_type msg_type, enum fsck_msg_id msg_id,
+ const char *message);
+int fsck_objects_error_cb_print_missing_gitmodules(struct fsck_options *o,
+ void *fsck_report,
+ enum fsck_msg_type msg_type,
+ enum fsck_msg_id msg_id,
+ const char *message);
+
+int fsck_refs_error_function(struct fsck_options *options,
+ void *fsck_report,
+ enum fsck_msg_type msg_type,
+ enum fsck_msg_id msg_id,
+ const char *message);
+
+struct fsck_object_report {
+ const struct object_id *oid;
+ enum object_type object_type;
+};
+
+struct fsck_ref_report {
+ const char *path;
+ const struct object_id *oid;
+ const char *referent;
+};
struct fsck_options {
fsck_walk_func walk;
fsck_error error_func;
- unsigned strict:1;
+ unsigned strict;
+ unsigned verbose;
enum fsck_msg_type *msg_type;
- struct oidset skiplist;
+ struct oidset skip_oids;
struct oidset gitmodules_found;
struct oidset gitmodules_done;
struct oidset gitattributes_found;
@@ -145,12 +167,12 @@ struct fsck_options {
};
#define FSCK_OPTIONS_DEFAULT { \
- .skiplist = OIDSET_INIT, \
+ .skip_oids = OIDSET_INIT, \
.gitmodules_found = OIDSET_INIT, \
.gitmodules_done = OIDSET_INIT, \
.gitattributes_found = OIDSET_INIT, \
.gitattributes_done = OIDSET_INIT, \
- .error_func = fsck_error_function \
+ .error_func = fsck_objects_error_function \
}
#define FSCK_OPTIONS_STRICT { \
.strict = 1, \
@@ -158,7 +180,7 @@ struct fsck_options {
.gitmodules_done = OIDSET_INIT, \
.gitattributes_found = OIDSET_INIT, \
.gitattributes_done = OIDSET_INIT, \
- .error_func = fsck_error_function, \
+ .error_func = fsck_objects_error_function, \
}
#define FSCK_OPTIONS_MISSING_GITMODULES { \
.strict = 1, \
@@ -166,7 +188,10 @@ struct fsck_options {
.gitmodules_done = OIDSET_INIT, \
.gitattributes_found = OIDSET_INIT, \
.gitattributes_done = OIDSET_INIT, \
- .error_func = fsck_error_cb_print_missing_gitmodules, \
+ .error_func = fsck_objects_error_cb_print_missing_gitmodules, \
+}
+#define FSCK_REFS_OPTIONS_DEFAULT { \
+ .error_func = fsck_refs_error_function, \
}
/* descend in all linked child objects
@@ -210,6 +235,21 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,
int fsck_finish(struct fsck_options *options);
/*
+ * Clear the fsck_options struct, freeing any allocated memory.
+ */
+void fsck_options_clear(struct fsck_options *options);
+
+/*
+ * Report an error or warning for refs.
+ */
+__attribute__((format (printf, 4, 5)))
+int fsck_report_ref(struct fsck_options *options,
+ struct fsck_ref_report *report,
+ enum fsck_msg_id msg_id,
+ const char *fmt, ...);
+
+
+/*
* Subsystem for storing human-readable names for each object.
*
* If fsck_enable_object_names() has not been called, all other functions are
diff --git a/fsmonitor.c b/fsmonitor.c
index 2b17d60bbb..28130f748f 100644
--- a/fsmonitor.c
+++ b/fsmonitor.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "dir.h"
diff --git a/git-submodule.sh b/git-submodule.sh
index 7f9582d923..03c5a220a2 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -94,6 +94,14 @@ cmd_add()
--reference=*)
reference_path="${1#--reference=}"
;;
+ --ref-format)
+ case "$2" in '') usage ;; esac
+ ref_format="--ref-format=$2"
+ shift
+ ;;
+ --ref-format=*)
+ ref_format="$1"
+ ;;
--dissociate)
dissociate=1
;;
@@ -129,7 +137,18 @@ cmd_add()
usage
fi
- git ${wt_prefix:+-C "$wt_prefix"} submodule--helper add ${quiet:+--quiet} ${force:+--force} ${progress:+"--progress"} ${branch:+--branch "$branch"} ${reference_path:+--reference "$reference_path"} ${dissociate:+--dissociate} ${custom_name:+--name "$custom_name"} ${depth:+"$depth"} -- "$@"
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper add \
+ ${quiet:+--quiet} \
+ ${force:+--force} \
+ ${progress:+"--progress"} \
+ ${branch:+--branch "$branch"} \
+ ${reference_path:+--reference "$reference_path"} \
+ ${ref_format:+"$ref_format"} \
+ ${dissociate:+--dissociate} \
+ ${custom_name:+--name "$custom_name"} \
+ ${depth:+"$depth"} \
+ -- \
+ "$@"
}
#
@@ -160,7 +179,11 @@ cmd_foreach()
shift
done
- git ${wt_prefix:+-C "$wt_prefix"} submodule--helper foreach ${quiet:+--quiet} ${recursive:+--recursive} -- "$@"
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper foreach \
+ ${quiet:+--quiet} \
+ ${recursive:+--recursive} \
+ -- \
+ "$@"
}
#
@@ -191,7 +214,10 @@ cmd_init()
shift
done
- git ${wt_prefix:+-C "$wt_prefix"} submodule--helper init ${quiet:+--quiet} -- "$@"
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper init \
+ ${quiet:+--quiet} \
+ -- \
+ "$@"
}
#
@@ -227,7 +253,12 @@ cmd_deinit()
shift
done
- git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit ${quiet:+--quiet} ${force:+--force} ${deinit_all:+--all} -- "$@"
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit \
+ ${quiet:+--quiet} \
+ ${force:+--force} \
+ ${deinit_all:+--all} \
+ -- \
+ "$@"
}
#
@@ -268,6 +299,14 @@ cmd_update()
-r|--rebase)
rebase=1
;;
+ --ref-format)
+ case "$2" in '') usage ;; esac
+ ref_format="--ref-format=$2"
+ shift
+ ;;
+ --ref-format=*)
+ ref_format="$1"
+ ;;
--reference)
case "$2" in '') usage ;; esac
reference="--reference=$2"
@@ -349,6 +388,7 @@ cmd_update()
${rebase:+--rebase} \
${merge:+--merge} \
${checkout:+--checkout} \
+ ${ref_format:+"$ref_format"} \
${reference:+"$reference"} \
${dissociate:+"--dissociate"} \
${depth:+"$depth"} \
@@ -399,7 +439,12 @@ cmd_set_branch() {
shift
done
- git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-branch ${quiet:+--quiet} ${branch:+--branch "$branch"} ${default:+--default} -- "$@"
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-branch \
+ ${quiet:+--quiet} \
+ ${branch:+--branch "$branch"} \
+ ${default:+--default} \
+ -- \
+ "$@"
}
#
@@ -428,7 +473,10 @@ cmd_set_url() {
shift
done
- git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-url ${quiet:+--quiet} -- "$@"
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-url \
+ ${quiet:+--quiet} \
+ -- \
+ "$@"
}
#
@@ -480,7 +528,13 @@ cmd_summary() {
shift
done
- git ${wt_prefix:+-C "$wt_prefix"} submodule--helper summary ${files:+--files} ${cached:+--cached} ${for_status:+--for-status} ${summary_limit:+-n $summary_limit} -- "$@"
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper summary \
+ ${files:+--files} \
+ ${cached:+--cached} \
+ ${for_status:+--for-status} \
+ ${summary_limit:+-n $summary_limit} \
+ -- \
+ "$@"
}
#
# List all submodules, prefixed with:
@@ -521,8 +575,14 @@ cmd_status()
shift
done
- git ${wt_prefix:+-C "$wt_prefix"} submodule--helper status ${quiet:+--quiet} ${cached:+--cached} ${recursive:+--recursive} -- "$@"
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper status \
+ ${quiet:+--quiet} \
+ ${cached:+--cached} \
+ ${recursive:+--recursive} \
+ -- \
+ "$@"
}
+
#
# Sync remote urls for submodules
# This makes the value for remote.$remote.url match the value
@@ -554,7 +614,11 @@ cmd_sync()
esac
done
- git ${wt_prefix:+-C "$wt_prefix"} submodule--helper sync ${quiet:+--quiet} ${recursive:+--recursive} -- "$@"
+ git ${wt_prefix:+-C "$wt_prefix"} submodule--helper sync \
+ ${quiet:+--quiet} \
+ ${recursive:+--recursive} \
+ -- \
+ "$@"
}
cmd_absorbgitdirs()
diff --git a/git-svn.perl b/git-svn.perl
index b0d0a50984..01e7a70de1 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -219,11 +219,11 @@ my %cmd = (
"Set an SVN repository to a git tree-ish",
{ 'stdin' => \$_stdin, %cmt_opts, %fc_opts, } ],
'create-ignore' => [ \&cmd_create_ignore,
- 'Create a .gitignore per svn:ignore',
+ "Create a .gitignore per directory with SVN ignore properties",
{ 'revision|r=i' => \$_revision
} ],
'mkdirs' => [ \&cmd_mkdirs ,
- "recreate empty directories after a checkout",
+ "Recreate empty directories after a checkout",
{ 'revision|r=i' => \$_revision } ],
'propget' => [ \&cmd_propget,
'Print the value of a property on a file or directory',
@@ -234,7 +234,7 @@ my %cmd = (
'proplist' => [ \&cmd_proplist,
'List all properties of a file or directory',
{ 'revision|r=i' => \$_revision } ],
- 'show-ignore' => [ \&cmd_show_ignore, "Show svn:ignore listings",
+ 'show-ignore' => [ \&cmd_show_ignore, "Show .gitignore patterns from SVN ignore properties",
{ 'revision|r=i' => \$_revision
} ],
'show-externals' => [ \&cmd_show_externals, "Show svn:externals listings",
@@ -1279,12 +1279,20 @@ sub cmd_show_ignore {
$gs->prop_walk($gs->path, $r, sub {
my ($gs, $path, $props) = @_;
print STDOUT "\n# $path\n";
- my $s = $props->{'svn:ignore'} or return;
- $s =~ s/[\r\n]+/\n/g;
- $s =~ s/^\n+//;
- chomp $s;
- $s =~ s#^#$path#gm;
- print STDOUT "$s\n";
+ if (my $s = $props->{'svn:ignore'}) {
+ $s =~ s/[\r\n]+/\n/g;
+ $s =~ s/^\n+//;
+ chomp $s;
+ $s =~ s#^#$path#gm;
+ print STDOUT "$s\n";
+ }
+ if (my $s = $props->{'svn:global-ignores'}) {
+ $s =~ s/[\r\n]+/\n/g;
+ $s =~ s/^\n+//;
+ chomp $s;
+ $s =~ s#^#$path**/#gm;
+ print STDOUT "$s\n";
+ }
});
}
@@ -1315,16 +1323,25 @@ sub cmd_create_ignore {
# which git won't track
mkpath([$path]) unless -d $path;
my $ignore = $path . '.gitignore';
- my $s = $props->{'svn:ignore'} or return;
open(GITIGNORE, '>', $ignore)
or fatal("Failed to open `$ignore' for writing: $!");
- $s =~ s/[\r\n]+/\n/g;
- $s =~ s/^\n+//;
- chomp $s;
- # Prefix all patterns so that the ignore doesn't apply
- # to sub-directories.
- $s =~ s#^#/#gm;
- print GITIGNORE "$s\n";
+ if (my $s = $props->{'svn:ignore'}) {
+ $s =~ s/[\r\n]+/\n/g;
+ $s =~ s/^\n+//;
+ chomp $s;
+ # Prefix all patterns so that the ignore doesn't apply
+ # to sub-directories.
+ $s =~ s#^#/#gm;
+ print GITIGNORE "$s\n";
+ }
+ if (my $s = $props->{'svn:global-ignores'}) {
+ $s =~ s/[\r\n]+/\n/g;
+ $s =~ s/^\n+//;
+ chomp $s;
+ # Global ignores apply to sub-directories, so they are
+ # not prefixed.
+ print GITIGNORE "$s\n";
+ }
close(GITIGNORE)
or fatal("Failed to close `$ignore': $!");
command_noisy('add', '-f', $ignore);
diff --git a/git.c b/git.c
index e35af9b0e5..9a618a2740 100644
--- a/git.c
+++ b/git.c
@@ -143,6 +143,13 @@ void setup_auto_pager(const char *cmd, int def)
commit_pager_choice();
}
+static void print_system_path(const char *path)
+{
+ char *s_path = system_path(path);
+ puts(s_path);
+ free(s_path);
+}
+
static int handle_options(const char ***argv, int *argc, int *envchanged)
{
const char **orig_argv = *argv;
@@ -173,15 +180,15 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
exit(0);
}
} else if (!strcmp(cmd, "--html-path")) {
- puts(system_path(GIT_HTML_PATH));
+ print_system_path(GIT_HTML_PATH);
trace2_cmd_name("_query_");
exit(0);
} else if (!strcmp(cmd, "--man-path")) {
- puts(system_path(GIT_MAN_PATH));
+ print_system_path(GIT_MAN_PATH);
trace2_cmd_name("_query_");
exit(0);
} else if (!strcmp(cmd, "--info-path")) {
- puts(system_path(GIT_INFO_PATH));
+ print_system_path(GIT_INFO_PATH);
trace2_cmd_name("_query_");
exit(0);
} else if (!strcmp(cmd, "-p") || !strcmp(cmd, "--paginate")) {
diff --git a/gpg-interface.c b/gpg-interface.c
index 5c824aeb25..6587085cd1 100644
--- a/gpg-interface.c
+++ b/gpg-interface.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "commit.h"
#include "config.h"
diff --git a/graph.c b/graph.c
index 1ca34770ee..091c14cf4f 100644
--- a/graph.c
+++ b/graph.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "gettext.h"
#include "config.h"
diff --git a/help.c b/help.c
index a6b4d3b1eb..c03863f226 100644
--- a/help.c
+++ b/help.c
@@ -804,7 +804,7 @@ struct similar_ref_cb {
struct string_list *similar_refs;
};
-static int append_similar_ref(const char *refname,
+static int append_similar_ref(const char *refname, const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flags UNUSED, void *cb_data)
{
diff --git a/hook.c b/hook.c
index 7e90787bca..a9320cb0ce 100644
--- a/hook.c
+++ b/hook.c
@@ -10,14 +10,14 @@
#include "environment.h"
#include "setup.h"
-const char *find_hook(const char *name)
+const char *find_hook(struct repository *r, const char *name)
{
static struct strbuf path = STRBUF_INIT;
int found_hook;
strbuf_reset(&path);
- strbuf_git_path(&path, "hooks/%s", name);
+ strbuf_repo_git_path(&path, r, "hooks/%s", name);
found_hook = access(path.buf, X_OK) >= 0;
#ifdef STRIP_EXTENSION
if (!found_hook) {
@@ -48,9 +48,9 @@ const char *find_hook(const char *name)
return path.buf;
}
-int hook_exists(const char *name)
+int hook_exists(struct repository *r, const char *name)
{
- return !!find_hook(name);
+ return !!find_hook(r, name);
}
static int pick_next_hook(struct child_process *cp,
@@ -121,7 +121,8 @@ static void run_hooks_opt_clear(struct run_hooks_opt *options)
strvec_clear(&options->args);
}
-int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
+int run_hooks_opt(struct repository *r, const char *hook_name,
+ struct run_hooks_opt *options)
{
struct strbuf abs_path = STRBUF_INIT;
struct hook_cb_data cb_data = {
@@ -129,7 +130,7 @@ int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options)
.hook_name = hook_name,
.options = options,
};
- const char *const hook_path = find_hook(hook_name);
+ const char *const hook_path = find_hook(r, hook_name);
int ret = 0;
const struct run_process_parallel_opts opts = {
.tr2_category = "hook",
@@ -173,14 +174,14 @@ cleanup:
return ret;
}
-int run_hooks(const char *hook_name)
+int run_hooks(struct repository *r, const char *hook_name)
{
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
- return run_hooks_opt(hook_name, &opt);
+ return run_hooks_opt(r, hook_name, &opt);
}
-int run_hooks_l(const char *hook_name, ...)
+int run_hooks_l(struct repository *r, const char *hook_name, ...)
{
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
va_list ap;
@@ -191,5 +192,5 @@ int run_hooks_l(const char *hook_name, ...)
strvec_push(&opt.args, arg);
va_end(ap);
- return run_hooks_opt(hook_name, &opt);
+ return run_hooks_opt(r, hook_name, &opt);
}
diff --git a/hook.h b/hook.h
index 6511525aeb..11863fa734 100644
--- a/hook.h
+++ b/hook.h
@@ -2,6 +2,8 @@
#define HOOK_H
#include "strvec.h"
+struct repository;
+
struct run_hooks_opt
{
/* Environment vars to be set for each hook */
@@ -55,12 +57,12 @@ struct hook_cb_data {
* or disabled. Note that this points to static storage that will be
* overwritten by further calls to find_hook and run_hook_*.
*/
-const char *find_hook(const char *name);
+const char *find_hook(struct repository *r, const char *name);
/**
* A boolean version of find_hook()
*/
-int hook_exists(const char *hookname);
+int hook_exists(struct repository *r, const char *hookname);
/**
* Takes a `hook_name`, resolves it to a path with find_hook(), and
@@ -70,13 +72,14 @@ int hook_exists(const char *hookname);
* Returns the status code of the run hook, or a negative value on
* error().
*/
-int run_hooks_opt(const char *hook_name, struct run_hooks_opt *options);
+int run_hooks_opt(struct repository *r, const char *hook_name,
+ struct run_hooks_opt *options);
/**
* A wrapper for run_hooks_opt() which provides a dummy "struct
* run_hooks_opt" initialized with "RUN_HOOKS_OPT_INIT".
*/
-int run_hooks(const char *hook_name);
+int run_hooks(struct repository *r, const char *hook_name);
/**
* Like run_hooks(), a wrapper for run_hooks_opt().
@@ -87,5 +90,5 @@ int run_hooks(const char *hook_name);
* hook. This function behaves like the old run_hook_le() API.
*/
LAST_ARG_MUST_BE_NULL
-int run_hooks_l(const char *hook_name, ...);
+int run_hooks_l(struct repository *r, const char *hook_name, ...);
#endif
diff --git a/http-backend.c b/http-backend.c
index 461424972b..79ce097359 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -512,7 +512,7 @@ static void run_service(const char **argv, int buffer_input)
exit(1);
}
-static int show_text_ref(const char *name, const struct object_id *oid,
+static int show_text_ref(const char *name, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data)
{
const char *name_nons = strip_namespace(name);
@@ -568,7 +568,7 @@ static void get_info_refs(struct strbuf *hdr, char *arg UNUSED)
strbuf_release(&buf);
}
-static int show_head_ref(const char *refname, const struct object_id *oid,
+static int show_head_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag, void *cb_data)
{
struct strbuf *buf = cb_data;
diff --git a/imap-send.c b/imap-send.c
index 01404e5047..b2eb3d2dd0 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -21,6 +21,8 @@
* along with this program; if not, see <https://www.gnu.org/licenses/>.
*/
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "credential.h"
diff --git a/log-tree.c b/log-tree.c
index fdb24cbef2..04cef08b83 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -146,7 +146,7 @@ static int ref_filter_match(const char *refname,
return 1;
}
-static int add_ref_decoration(const char *refname, const struct object_id *oid,
+static int add_ref_decoration(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flags UNUSED,
void *cb_data)
{
diff --git a/ls-refs.c b/ls-refs.c
index 2dd925b43d..c824aea714 100644
--- a/ls-refs.c
+++ b/ls-refs.c
@@ -77,7 +77,7 @@ struct ls_refs_data {
unsigned unborn : 1;
};
-static int send_ref(const char *refname, const struct object_id *oid,
+static int send_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag, void *cb_data)
{
struct ls_refs_data *data = cb_data;
@@ -135,7 +135,7 @@ static void send_possibly_unborn_head(struct ls_refs_data *data)
oid_is_null = is_null_oid(&oid);
if (!oid_is_null ||
(data->unborn && data->symrefs && (flag & REF_ISSYMREF)))
- send_ref(namespaced.buf, oid_is_null ? NULL : &oid, flag, data);
+ send_ref(namespaced.buf, NULL, oid_is_null ? NULL : &oid, flag, data);
strbuf_release(&namespaced);
}
diff --git a/mailinfo.c b/mailinfo.c
index 94b9b0abf2..95228531a6 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "gettext.h"
diff --git a/merge-ll.c b/merge-ll.c
index 180c19df67..badb6dea57 100644
--- a/merge-ll.c
+++ b/merge-ll.c
@@ -4,6 +4,8 @@
* Copyright (c) 2007 Junio C Hamano
*/
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "convert.h"
diff --git a/merge-ort.c b/merge-ort.c
index e9d01ac7f7..3752c7e595 100644
--- a/merge-ort.c
+++ b/merge-ort.c
@@ -689,8 +689,7 @@ static void clear_or_reinit_internal_opts(struct merge_options_internal *opti,
*/
strmap_clear_func(&opti->conflicted, 0);
- if (opti->attr_index.cache_nr) /* true iff opt->renormalize */
- discard_index(&opti->attr_index);
+ discard_index(&opti->attr_index);
/* Free memory used by various renames maps */
for (i = MERGE_SIDE1; i <= MERGE_SIDE2; ++i) {
diff --git a/midx-write.c b/midx-write.c
index a77ee73c68..e3fa33203f 100644
--- a/midx-write.c
+++ b/midx-write.c
@@ -17,6 +17,8 @@
#include "refs.h"
#include "revision.h"
#include "list-objects.h"
+#include "path.h"
+#include "pack-revindex.h"
#define PACK_EXPIRED UINT_MAX
#define BITMAP_POS_UNKNOWN (~((uint32_t)0))
@@ -25,7 +27,11 @@
extern int midx_checksum_valid(struct multi_pack_index *m);
extern void clear_midx_files_ext(const char *object_dir, const char *ext,
- unsigned char *keep_hash);
+ const char *keep_hash);
+extern void clear_incremental_midx_files_ext(const char *object_dir,
+ const char *ext,
+ const char **keep_hashes,
+ uint32_t hashes_nr);
extern int cmp_idx_or_pack_name(const char *idx_or_pack_name,
const char *idx_name);
@@ -86,6 +92,7 @@ struct write_midx_context {
size_t nr;
size_t alloc;
struct multi_pack_index *m;
+ struct multi_pack_index *base_midx;
struct progress *progress;
unsigned pack_paths_checked;
@@ -99,6 +106,9 @@ struct write_midx_context {
int preferred_pack_idx;
+ int incremental;
+ uint32_t num_multi_pack_indexes_before;
+
struct string_list *to_include;
};
@@ -122,6 +132,9 @@ static int should_include_pack(const struct write_midx_context *ctx,
*/
if (ctx->m && midx_contains_pack(ctx->m, file_name))
return 0;
+ else if (ctx->base_midx && midx_contains_pack(ctx->base_midx,
+ file_name))
+ return 0;
else if (ctx->to_include &&
!string_list_has_string(ctx->to_include, file_name))
return 0;
@@ -196,7 +209,7 @@ static int nth_midxed_pack_midx_entry(struct multi_pack_index *m,
struct pack_midx_entry *e,
uint32_t pos)
{
- if (pos >= m->num_objects)
+ if (pos >= m->num_objects + m->num_objects_in_base)
return 1;
nth_midxed_object_oid(&e->oid, m, pos);
@@ -247,12 +260,16 @@ static void midx_fanout_add_midx_fanout(struct midx_fanout *fanout,
uint32_t cur_fanout,
int preferred_pack)
{
- uint32_t start = 0, end;
+ uint32_t start = m->num_objects_in_base, end;
uint32_t cur_object;
+ if (m->base_midx)
+ midx_fanout_add_midx_fanout(fanout, m->base_midx, cur_fanout,
+ preferred_pack);
+
if (cur_fanout)
- start = ntohl(m->chunk_oid_fanout[cur_fanout - 1]);
- end = ntohl(m->chunk_oid_fanout[cur_fanout]);
+ start += ntohl(m->chunk_oid_fanout[cur_fanout - 1]);
+ end = m->num_objects_in_base + ntohl(m->chunk_oid_fanout[cur_fanout]);
for (cur_object = start; cur_object < end; cur_object++) {
if ((preferred_pack > -1) &&
@@ -334,7 +351,7 @@ static void compute_sorted_entries(struct write_midx_context *ctx,
for (cur_fanout = 0; cur_fanout < 256; cur_fanout++) {
fanout.nr = 0;
- if (ctx->m)
+ if (ctx->m && !ctx->incremental)
midx_fanout_add_midx_fanout(&fanout, ctx->m, cur_fanout,
ctx->preferred_pack_idx);
@@ -360,6 +377,10 @@ static void compute_sorted_entries(struct write_midx_context *ctx,
if (cur_object && oideq(&fanout.entries[cur_object - 1].oid,
&fanout.entries[cur_object].oid))
continue;
+ if (ctx->incremental && ctx->base_midx &&
+ midx_has_oid(ctx->base_midx,
+ &fanout.entries[cur_object].oid))
+ continue;
ALLOC_GROW(ctx->entries, st_add(ctx->entries_nr, 1),
alloc_objects);
@@ -543,10 +564,16 @@ static int write_midx_revindex(struct hashfile *f,
void *data)
{
struct write_midx_context *ctx = data;
- uint32_t i;
+ uint32_t i, nr_base;
+
+ if (ctx->incremental && ctx->base_midx)
+ nr_base = ctx->base_midx->num_objects +
+ ctx->base_midx->num_objects_in_base;
+ else
+ nr_base = 0;
for (i = 0; i < ctx->entries_nr; i++)
- hashwrite_be32(f, ctx->pack_order[i]);
+ hashwrite_be32(f, ctx->pack_order[i] + nr_base);
return 0;
}
@@ -575,12 +602,18 @@ static int midx_pack_order_cmp(const void *va, const void *vb)
static uint32_t *midx_pack_order(struct write_midx_context *ctx)
{
struct midx_pack_order_data *data;
- uint32_t *pack_order;
+ uint32_t *pack_order, base_objects = 0;
uint32_t i;
trace2_region_enter("midx", "midx_pack_order", the_repository);
+ if (ctx->incremental && ctx->base_midx)
+ base_objects = ctx->base_midx->num_objects +
+ ctx->base_midx->num_objects_in_base;
+
+ ALLOC_ARRAY(pack_order, ctx->entries_nr);
ALLOC_ARRAY(data, ctx->entries_nr);
+
for (i = 0; i < ctx->entries_nr; i++) {
struct pack_midx_entry *e = &ctx->entries[i];
data[i].nr = i;
@@ -592,12 +625,11 @@ static uint32_t *midx_pack_order(struct write_midx_context *ctx)
QSORT(data, ctx->entries_nr, midx_pack_order_cmp);
- ALLOC_ARRAY(pack_order, ctx->entries_nr);
for (i = 0; i < ctx->entries_nr; i++) {
struct pack_midx_entry *e = &ctx->entries[data[i].nr];
struct pack_info *pack = &ctx->info[ctx->pack_perm[e->pack_int_id]];
if (pack->bitmap_pos == BITMAP_POS_UNKNOWN)
- pack->bitmap_pos = i;
+ pack->bitmap_pos = i + base_objects;
pack->bitmap_nr++;
pack_order[i] = data[i].nr;
}
@@ -645,7 +677,8 @@ static void prepare_midx_packing_data(struct packing_data *pdata,
prepare_packing_data(the_repository, pdata);
for (i = 0; i < ctx->entries_nr; i++) {
- struct pack_midx_entry *from = &ctx->entries[ctx->pack_order[i]];
+ uint32_t pos = ctx->pack_order[i];
+ struct pack_midx_entry *from = &ctx->entries[pos];
struct object_entry *to = packlist_alloc(pdata, &from->oid);
oe_set_in_pack(pdata, to,
@@ -655,7 +688,7 @@ static void prepare_midx_packing_data(struct packing_data *pdata,
trace2_region_leave("midx", "prepare_midx_packing_data", the_repository);
}
-static int add_ref_to_pending(const char *refname,
+static int add_ref_to_pending(const char *refname, const char *referent UNUSED,
const struct object_id *oid,
int flag, void *cb_data)
{
@@ -893,35 +926,128 @@ cleanup:
static int fill_packs_from_midx(struct write_midx_context *ctx,
const char *preferred_pack_name, uint32_t flags)
{
- uint32_t i;
+ struct multi_pack_index *m;
- for (i = 0; i < ctx->m->num_packs; i++) {
- ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc);
+ for (m = ctx->m; m; m = m->base_midx) {
+ uint32_t i;
+
+ for (i = 0; i < m->num_packs; i++) {
+ ALLOC_GROW(ctx->info, ctx->nr + 1, ctx->alloc);
- if (flags & MIDX_WRITE_REV_INDEX || preferred_pack_name) {
/*
* If generating a reverse index, need to have
* packed_git's loaded to compare their
* mtimes and object count.
*
- *
* If a preferred pack is specified, need to
* have packed_git's loaded to ensure the chosen
* preferred pack has a non-zero object count.
*/
- if (prepare_midx_pack(the_repository, ctx->m, i))
- return error(_("could not load pack"));
+ if (flags & MIDX_WRITE_REV_INDEX ||
+ preferred_pack_name) {
+ if (prepare_midx_pack(the_repository, m,
+ m->num_packs_in_base + i)) {
+ error(_("could not load pack"));
+ return 1;
+ }
+
+ if (open_pack_index(m->packs[i]))
+ die(_("could not open index for %s"),
+ m->packs[i]->pack_name);
+ }
+
+ fill_pack_info(&ctx->info[ctx->nr++], m->packs[i],
+ m->pack_names[i],
+ m->num_packs_in_base + i);
+ }
+ }
+ return 0;
+}
+
+static struct {
+ const char *non_split;
+ const char *split;
+} midx_exts[] = {
+ {NULL, MIDX_EXT_MIDX},
+ {MIDX_EXT_BITMAP, MIDX_EXT_BITMAP},
+ {MIDX_EXT_REV, MIDX_EXT_REV},
+};
+
+static int link_midx_to_chain(struct multi_pack_index *m)
+{
+ struct strbuf from = STRBUF_INIT;
+ struct strbuf to = STRBUF_INIT;
+ int ret = 0;
+ size_t i;
+
+ if (!m || m->has_chain) {
+ /*
+ * Either no MIDX previously existed, or it was already
+ * part of a MIDX chain. In both cases, we have nothing
+ * to link, so return early.
+ */
+ goto done;
+ }
- if (open_pack_index(ctx->m->packs[i]))
- die(_("could not open index for %s"),
- ctx->m->packs[i]->pack_name);
+ for (i = 0; i < ARRAY_SIZE(midx_exts); i++) {
+ const unsigned char *hash = get_midx_checksum(m);
+
+ get_midx_filename_ext(&from, m->object_dir, hash,
+ midx_exts[i].non_split);
+ get_split_midx_filename_ext(&to, m->object_dir, hash,
+ midx_exts[i].split);
+
+ if (link(from.buf, to.buf) < 0 && errno != ENOENT) {
+ ret = error_errno(_("unable to link '%s' to '%s'"),
+ from.buf, to.buf);
+ goto done;
}
- fill_pack_info(&ctx->info[ctx->nr++], ctx->m->packs[i],
- ctx->m->pack_names[i], i);
+ strbuf_reset(&from);
+ strbuf_reset(&to);
}
- return 0;
+done:
+ strbuf_release(&from);
+ strbuf_release(&to);
+ return ret;
+}
+
+static void clear_midx_files(const char *object_dir,
+ const char **hashes,
+ uint32_t hashes_nr,
+ unsigned incremental)
+{
+ /*
+ * if incremental:
+ * - remove all non-incremental MIDX files
+ * - remove any incremental MIDX files not in the current one
+ *
+ * if non-incremental:
+ * - remove all incremental MIDX files
+ * - remove any non-incremental MIDX files not matching the current
+ * hash
+ */
+ struct strbuf buf = STRBUF_INIT;
+ const char *exts[] = { MIDX_EXT_BITMAP, MIDX_EXT_REV, MIDX_EXT_MIDX };
+ uint32_t i, j;
+
+ for (i = 0; i < ARRAY_SIZE(exts); i++) {
+ clear_incremental_midx_files_ext(object_dir, exts[i],
+ hashes, hashes_nr);
+ for (j = 0; j < hashes_nr; j++)
+ clear_midx_files_ext(object_dir, exts[i], hashes[j]);
+ }
+
+ if (incremental)
+ get_midx_filename(&buf, object_dir);
+ else
+ get_midx_chain_filename(&buf, object_dir);
+
+ if (unlink(buf.buf) && errno != ENOENT)
+ die_errno(_("failed to clear multi-pack-index at %s"), buf.buf);
+
+ strbuf_release(&buf);
}
static int write_midx_internal(const char *object_dir,
@@ -936,42 +1062,66 @@ static int write_midx_internal(const char *object_dir,
uint32_t i, start_pack;
struct hashfile *f = NULL;
struct lock_file lk;
+ struct tempfile *incr;
struct write_midx_context ctx = { 0 };
int bitmapped_packs_concat_len = 0;
int pack_name_concat_len = 0;
int dropped_packs = 0;
int result = 0;
+ const char **keep_hashes = NULL;
struct chunkfile *cf;
trace2_region_enter("midx", "write_midx_internal", the_repository);
- get_midx_filename(&midx_name, object_dir);
+ ctx.incremental = !!(flags & MIDX_WRITE_INCREMENTAL);
+ if (ctx.incremental && (flags & MIDX_WRITE_BITMAP))
+ die(_("cannot write incremental MIDX with bitmap"));
+
+ if (ctx.incremental)
+ strbuf_addf(&midx_name,
+ "%s/pack/multi-pack-index.d/tmp_midx_XXXXXX",
+ object_dir);
+ else
+ get_midx_filename(&midx_name, object_dir);
if (safe_create_leading_directories(midx_name.buf))
die_errno(_("unable to create leading directories of %s"),
midx_name.buf);
- if (!packs_to_include) {
- /*
- * Only reference an existing MIDX when not filtering which
- * packs to include, since all packs and objects are copied
- * blindly from an existing MIDX if one is present.
- */
- ctx.m = lookup_multi_pack_index(the_repository, object_dir);
- }
+ if (!packs_to_include || ctx.incremental) {
+ struct multi_pack_index *m = lookup_multi_pack_index(the_repository,
+ object_dir);
+ if (m && !midx_checksum_valid(m)) {
+ warning(_("ignoring existing multi-pack-index; checksum mismatch"));
+ m = NULL;
+ }
- if (ctx.m && !midx_checksum_valid(ctx.m)) {
- warning(_("ignoring existing multi-pack-index; checksum mismatch"));
- ctx.m = NULL;
+ if (m) {
+ /*
+ * Only reference an existing MIDX when not filtering
+ * which packs to include, since all packs and objects
+ * are copied blindly from an existing MIDX if one is
+ * present.
+ */
+ if (ctx.incremental)
+ ctx.base_midx = m;
+ else if (!packs_to_include)
+ ctx.m = m;
+ }
}
ctx.nr = 0;
- ctx.alloc = ctx.m ? ctx.m->num_packs : 16;
+ ctx.alloc = ctx.m ? ctx.m->num_packs + ctx.m->num_packs_in_base : 16;
ctx.info = NULL;
ALLOC_ARRAY(ctx.info, ctx.alloc);
- if (ctx.m && fill_packs_from_midx(&ctx, preferred_pack_name,
- flags) < 0) {
- result = 1;
+ if (ctx.incremental) {
+ struct multi_pack_index *m = ctx.base_midx;
+ while (m) {
+ ctx.num_multi_pack_indexes_before++;
+ m = m->base_midx;
+ }
+ } else if (ctx.m && fill_packs_from_midx(&ctx, preferred_pack_name,
+ flags) < 0) {
goto cleanup;
}
@@ -988,7 +1138,8 @@ static int write_midx_internal(const char *object_dir,
for_each_file_in_pack_dir(object_dir, add_pack_to_midx, &ctx);
stop_progress(&ctx.progress);
- if ((ctx.m && ctx.nr == ctx.m->num_packs) &&
+ if ((ctx.m && ctx.nr == ctx.m->num_packs + ctx.m->num_packs_in_base) &&
+ !ctx.incremental &&
!(packs_to_include || packs_to_drop)) {
struct bitmap_index *bitmap_git;
int bitmap_exists;
@@ -1004,12 +1155,14 @@ static int write_midx_internal(const char *object_dir,
* corresponding bitmap (or one wasn't requested).
*/
if (!want_bitmap)
- clear_midx_files_ext(object_dir, ".bitmap",
- NULL);
+ clear_midx_files_ext(object_dir, "bitmap", NULL);
goto cleanup;
}
}
+ if (ctx.incremental && !ctx.nr)
+ goto cleanup; /* nothing to do */
+
if (preferred_pack_name) {
ctx.preferred_pack_idx = -1;
@@ -1155,8 +1308,30 @@ static int write_midx_internal(const char *object_dir,
pack_name_concat_len += MIDX_CHUNK_ALIGNMENT -
(pack_name_concat_len % MIDX_CHUNK_ALIGNMENT);
- hold_lock_file_for_update(&lk, midx_name.buf, LOCK_DIE_ON_ERROR);
- f = hashfd(get_lock_file_fd(&lk), get_lock_file_path(&lk));
+ if (ctx.incremental) {
+ struct strbuf lock_name = STRBUF_INIT;
+
+ get_midx_chain_filename(&lock_name, object_dir);
+ hold_lock_file_for_update(&lk, lock_name.buf, LOCK_DIE_ON_ERROR);
+ strbuf_release(&lock_name);
+
+ incr = mks_tempfile_m(midx_name.buf, 0444);
+ if (!incr) {
+ error(_("unable to create temporary MIDX layer"));
+ return -1;
+ }
+
+ if (adjust_shared_perm(get_tempfile_path(incr))) {
+ error(_("unable to adjust shared permissions for '%s'"),
+ get_tempfile_path(incr));
+ return -1;
+ }
+
+ f = hashfd(get_tempfile_fd(incr), get_tempfile_path(incr));
+ } else {
+ hold_lock_file_for_update(&lk, midx_name.buf, LOCK_DIE_ON_ERROR);
+ f = hashfd(get_lock_file_fd(&lk), get_lock_file_path(&lk));
+ }
if (ctx.nr - dropped_packs == 0) {
error(_("no pack files to index."));
@@ -1249,14 +1424,55 @@ static int write_midx_internal(const char *object_dir,
* have been freed in the previous if block.
*/
- if (ctx.m)
+ CALLOC_ARRAY(keep_hashes, ctx.num_multi_pack_indexes_before + 1);
+
+ if (ctx.incremental) {
+ FILE *chainf = fdopen_lock_file(&lk, "w");
+ struct strbuf final_midx_name = STRBUF_INIT;
+ struct multi_pack_index *m = ctx.base_midx;
+
+ if (!chainf) {
+ error_errno(_("unable to open multi-pack-index chain file"));
+ return -1;
+ }
+
+ if (link_midx_to_chain(ctx.base_midx) < 0)
+ return -1;
+
+ get_split_midx_filename_ext(&final_midx_name, object_dir,
+ midx_hash, MIDX_EXT_MIDX);
+
+ if (rename_tempfile(&incr, final_midx_name.buf) < 0) {
+ error_errno(_("unable to rename new multi-pack-index layer"));
+ return -1;
+ }
+
+ keep_hashes[ctx.num_multi_pack_indexes_before] =
+ xstrdup(hash_to_hex(midx_hash));
+
+ for (i = 0; i < ctx.num_multi_pack_indexes_before; i++) {
+ uint32_t j = ctx.num_multi_pack_indexes_before - i - 1;
+
+ keep_hashes[j] = xstrdup(hash_to_hex(get_midx_checksum(m)));
+ m = m->base_midx;
+ }
+
+ for (i = 0; i < ctx.num_multi_pack_indexes_before + 1; i++)
+ fprintf(get_lock_file_fp(&lk), "%s\n", keep_hashes[i]);
+ } else {
+ keep_hashes[ctx.num_multi_pack_indexes_before] =
+ xstrdup(hash_to_hex(midx_hash));
+ }
+
+ if (ctx.m || ctx.base_midx)
close_object_store(the_repository->objects);
if (commit_lock_file(&lk) < 0)
die_errno(_("could not write multi-pack-index"));
- clear_midx_files_ext(object_dir, ".bitmap", midx_hash);
- clear_midx_files_ext(object_dir, ".rev", midx_hash);
+ clear_midx_files(object_dir, keep_hashes,
+ ctx.num_multi_pack_indexes_before + 1,
+ ctx.incremental);
cleanup:
for (i = 0; i < ctx.nr; i++) {
@@ -1271,6 +1487,11 @@ cleanup:
free(ctx.entries);
free(ctx.pack_perm);
free(ctx.pack_order);
+ if (keep_hashes) {
+ for (i = 0; i < ctx.num_multi_pack_indexes_before + 1; i++)
+ free((char *)keep_hashes[i]);
+ free(keep_hashes);
+ }
strbuf_release(&midx_name);
trace2_region_leave("midx", "write_midx_internal", the_repository);
@@ -1307,6 +1528,9 @@ int expire_midx_packs(struct repository *r, const char *object_dir, unsigned fla
if (!m)
return 0;
+ if (m->base_midx)
+ die(_("cannot expire packs from an incremental multi-pack-index"));
+
CALLOC_ARRAY(count, m->num_packs);
if (flags & MIDX_PROGRESS)
@@ -1481,6 +1705,8 @@ int midx_repack(struct repository *r, const char *object_dir, size_t batch_size,
if (!m)
return 0;
+ if (m->base_midx)
+ die(_("cannot repack an incremental multi-pack-index"));
CALLOC_ARRAY(include_pack, m->num_packs);
diff --git a/midx.c b/midx.c
index 3992b05465..ca98bfd7c6 100644
--- a/midx.c
+++ b/midx.c
@@ -16,7 +16,10 @@
int midx_checksum_valid(struct multi_pack_index *m);
void clear_midx_files_ext(const char *object_dir, const char *ext,
- unsigned char *keep_hash);
+ const char *keep_hash);
+void clear_incremental_midx_files_ext(const char *object_dir, const char *ext,
+ char **keep_hashes,
+ uint32_t hashes_nr);
int cmp_idx_or_pack_name(const char *idx_or_pack_name,
const char *idx_name);
@@ -91,7 +94,9 @@ static int midx_read_object_offsets(const unsigned char *chunk_start,
#define MIDX_MIN_SIZE (MIDX_HEADER_SIZE + the_hash_algo->rawsz)
-struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local)
+static struct multi_pack_index *load_multi_pack_index_one(const char *object_dir,
+ const char *midx_name,
+ int local)
{
struct multi_pack_index *m = NULL;
int fd;
@@ -99,31 +104,26 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
size_t midx_size;
void *midx_map = NULL;
uint32_t hash_version;
- struct strbuf midx_name = STRBUF_INIT;
uint32_t i;
const char *cur_pack_name;
struct chunkfile *cf = NULL;
- get_midx_filename(&midx_name, object_dir);
-
- fd = git_open(midx_name.buf);
+ fd = git_open(midx_name);
if (fd < 0)
goto cleanup_fail;
if (fstat(fd, &st)) {
- error_errno(_("failed to read %s"), midx_name.buf);
+ error_errno(_("failed to read %s"), midx_name);
goto cleanup_fail;
}
midx_size = xsize_t(st.st_size);
if (midx_size < MIDX_MIN_SIZE) {
- error(_("multi-pack-index file %s is too small"), midx_name.buf);
+ error(_("multi-pack-index file %s is too small"), midx_name);
goto cleanup_fail;
}
- strbuf_release(&midx_name);
-
midx_map = xmmap(NULL, midx_size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
@@ -213,7 +213,6 @@ struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local
cleanup_fail:
free(m);
- strbuf_release(&midx_name);
free_chunkfile(cf);
if (midx_map)
munmap(midx_map, midx_size);
@@ -222,6 +221,169 @@ cleanup_fail:
return NULL;
}
+void get_midx_chain_dirname(struct strbuf *buf, const char *object_dir)
+{
+ strbuf_addf(buf, "%s/pack/multi-pack-index.d", object_dir);
+}
+
+void get_midx_chain_filename(struct strbuf *buf, const char *object_dir)
+{
+ get_midx_chain_dirname(buf, object_dir);
+ strbuf_addstr(buf, "/multi-pack-index-chain");
+}
+
+void get_split_midx_filename_ext(struct strbuf *buf, const char *object_dir,
+ const unsigned char *hash, const char *ext)
+{
+ get_midx_chain_dirname(buf, object_dir);
+ strbuf_addf(buf, "/multi-pack-index-%s.%s", hash_to_hex(hash), ext);
+}
+
+static int open_multi_pack_index_chain(const char *chain_file,
+ int *fd, struct stat *st)
+{
+ *fd = git_open(chain_file);
+ if (*fd < 0)
+ return 0;
+ if (fstat(*fd, st)) {
+ close(*fd);
+ return 0;
+ }
+ if (st->st_size < the_hash_algo->hexsz) {
+ close(*fd);
+ if (!st->st_size) {
+ /* treat empty files the same as missing */
+ errno = ENOENT;
+ } else {
+ warning(_("multi-pack-index chain file too small"));
+ errno = EINVAL;
+ }
+ return 0;
+ }
+ return 1;
+}
+
+static int add_midx_to_chain(struct multi_pack_index *midx,
+ struct multi_pack_index *midx_chain)
+{
+ if (midx_chain) {
+ if (unsigned_add_overflows(midx_chain->num_packs,
+ midx_chain->num_packs_in_base)) {
+ warning(_("pack count in base MIDX too high: %"PRIuMAX),
+ (uintmax_t)midx_chain->num_packs_in_base);
+ return 0;
+ }
+ if (unsigned_add_overflows(midx_chain->num_objects,
+ midx_chain->num_objects_in_base)) {
+ warning(_("object count in base MIDX too high: %"PRIuMAX),
+ (uintmax_t)midx_chain->num_objects_in_base);
+ return 0;
+ }
+ midx->num_packs_in_base = midx_chain->num_packs +
+ midx_chain->num_packs_in_base;
+ midx->num_objects_in_base = midx_chain->num_objects +
+ midx_chain->num_objects_in_base;
+ }
+
+ midx->base_midx = midx_chain;
+ midx->has_chain = 1;
+
+ return 1;
+}
+
+static struct multi_pack_index *load_midx_chain_fd_st(const char *object_dir,
+ int local,
+ int fd, struct stat *st,
+ int *incomplete_chain)
+{
+ struct multi_pack_index *midx_chain = NULL;
+ struct strbuf buf = STRBUF_INIT;
+ int valid = 1;
+ uint32_t i, count;
+ FILE *fp = xfdopen(fd, "r");
+
+ count = st->st_size / (the_hash_algo->hexsz + 1);
+
+ for (i = 0; i < count; i++) {
+ struct multi_pack_index *m;
+ struct object_id layer;
+
+ if (strbuf_getline_lf(&buf, fp) == EOF)
+ break;
+
+ if (get_oid_hex(buf.buf, &layer)) {
+ warning(_("invalid multi-pack-index chain: line '%s' "
+ "not a hash"),
+ buf.buf);
+ valid = 0;
+ break;
+ }
+
+ valid = 0;
+
+ strbuf_reset(&buf);
+ get_split_midx_filename_ext(&buf, object_dir, layer.hash,
+ MIDX_EXT_MIDX);
+ m = load_multi_pack_index_one(object_dir, buf.buf, local);
+
+ if (m) {
+ if (add_midx_to_chain(m, midx_chain)) {
+ midx_chain = m;
+ valid = 1;
+ } else {
+ close_midx(m);
+ }
+ }
+ if (!valid) {
+ warning(_("unable to find all multi-pack index files"));
+ break;
+ }
+ }
+
+ fclose(fp);
+ strbuf_release(&buf);
+
+ *incomplete_chain = !valid;
+ return midx_chain;
+}
+
+static struct multi_pack_index *load_multi_pack_index_chain(const char *object_dir,
+ int local)
+{
+ struct strbuf chain_file = STRBUF_INIT;
+ struct stat st;
+ int fd;
+ struct multi_pack_index *m = NULL;
+
+ get_midx_chain_filename(&chain_file, object_dir);
+ if (open_multi_pack_index_chain(chain_file.buf, &fd, &st)) {
+ int incomplete;
+ /* ownership of fd is taken over by load function */
+ m = load_midx_chain_fd_st(object_dir, local, fd, &st,
+ &incomplete);
+ }
+
+ strbuf_release(&chain_file);
+ return m;
+}
+
+struct multi_pack_index *load_multi_pack_index(const char *object_dir,
+ int local)
+{
+ struct strbuf midx_name = STRBUF_INIT;
+ struct multi_pack_index *m;
+
+ get_midx_filename(&midx_name, object_dir);
+
+ m = load_multi_pack_index_one(object_dir, midx_name.buf, local);
+ if (!m)
+ m = load_multi_pack_index_chain(object_dir, local);
+
+ strbuf_release(&midx_name);
+
+ return m;
+}
+
void close_midx(struct multi_pack_index *m)
{
uint32_t i;
@@ -230,6 +392,7 @@ void close_midx(struct multi_pack_index *m)
return;
close_midx(m->next);
+ close_midx(m->base_midx);
munmap((unsigned char *)m->data, m->data_len);
@@ -242,14 +405,49 @@ void close_midx(struct multi_pack_index *m)
free(m);
}
-int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, uint32_t pack_int_id)
+static uint32_t midx_for_object(struct multi_pack_index **_m, uint32_t pos)
+{
+ struct multi_pack_index *m = *_m;
+ while (m && pos < m->num_objects_in_base)
+ m = m->base_midx;
+
+ if (!m)
+ BUG("NULL multi-pack-index for object position: %"PRIu32, pos);
+
+ if (pos >= m->num_objects + m->num_objects_in_base)
+ die(_("invalid MIDX object position, MIDX is likely corrupt"));
+
+ *_m = m;
+
+ return pos - m->num_objects_in_base;
+}
+
+static uint32_t midx_for_pack(struct multi_pack_index **_m,
+ uint32_t pack_int_id)
+{
+ struct multi_pack_index *m = *_m;
+ while (m && pack_int_id < m->num_packs_in_base)
+ m = m->base_midx;
+
+ if (!m)
+ BUG("NULL multi-pack-index for pack ID: %"PRIu32, pack_int_id);
+
+ if (pack_int_id >= m->num_packs + m->num_packs_in_base)
+ die(_("bad pack-int-id: %u (%u total packs)"),
+ pack_int_id, m->num_packs + m->num_packs_in_base);
+
+ *_m = m;
+
+ return pack_int_id - m->num_packs_in_base;
+}
+
+int prepare_midx_pack(struct repository *r, struct multi_pack_index *m,
+ uint32_t pack_int_id)
{
struct strbuf pack_name = STRBUF_INIT;
struct packed_git *p;
- if (pack_int_id >= m->num_packs)
- die(_("bad pack-int-id: %u (%u total packs)"),
- pack_int_id, m->num_packs);
+ pack_int_id = midx_for_pack(&m, pack_int_id);
if (m->packs[pack_int_id])
return 0;
@@ -271,41 +469,71 @@ int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, uint32_t
return 0;
}
+struct packed_git *nth_midxed_pack(struct multi_pack_index *m,
+ uint32_t pack_int_id)
+{
+ uint32_t local_pack_int_id = midx_for_pack(&m, pack_int_id);
+ return m->packs[local_pack_int_id];
+}
+
#define MIDX_CHUNK_BITMAPPED_PACKS_WIDTH (2 * sizeof(uint32_t))
int nth_bitmapped_pack(struct repository *r, struct multi_pack_index *m,
struct bitmapped_pack *bp, uint32_t pack_int_id)
{
+ uint32_t local_pack_int_id = midx_for_pack(&m, pack_int_id);
+
if (!m->chunk_bitmapped_packs)
return error(_("MIDX does not contain the BTMP chunk"));
if (prepare_midx_pack(r, m, pack_int_id))
return error(_("could not load bitmapped pack %"PRIu32), pack_int_id);
- bp->p = m->packs[pack_int_id];
+ bp->p = m->packs[local_pack_int_id];
bp->bitmap_pos = get_be32((char *)m->chunk_bitmapped_packs +
- MIDX_CHUNK_BITMAPPED_PACKS_WIDTH * pack_int_id);
+ MIDX_CHUNK_BITMAPPED_PACKS_WIDTH * local_pack_int_id);
bp->bitmap_nr = get_be32((char *)m->chunk_bitmapped_packs +
- MIDX_CHUNK_BITMAPPED_PACKS_WIDTH * pack_int_id +
+ MIDX_CHUNK_BITMAPPED_PACKS_WIDTH * local_pack_int_id +
sizeof(uint32_t));
bp->pack_int_id = pack_int_id;
return 0;
}
-int bsearch_midx(const struct object_id *oid, struct multi_pack_index *m, uint32_t *result)
+int bsearch_one_midx(const struct object_id *oid, struct multi_pack_index *m,
+ uint32_t *result)
+{
+ int ret = bsearch_hash(oid->hash, m->chunk_oid_fanout,
+ m->chunk_oid_lookup, the_hash_algo->rawsz,
+ result);
+ if (result)
+ *result += m->num_objects_in_base;
+ return ret;
+}
+
+int bsearch_midx(const struct object_id *oid, struct multi_pack_index *m,
+ uint32_t *result)
+{
+ for (; m; m = m->base_midx)
+ if (bsearch_one_midx(oid, m, result))
+ return 1;
+ return 0;
+}
+
+int midx_has_oid(struct multi_pack_index *m, const struct object_id *oid)
{
- return bsearch_hash(oid->hash, m->chunk_oid_fanout, m->chunk_oid_lookup,
- the_hash_algo->rawsz, result);
+ return bsearch_midx(oid, m, NULL);
}
struct object_id *nth_midxed_object_oid(struct object_id *oid,
struct multi_pack_index *m,
uint32_t n)
{
- if (n >= m->num_objects)
+ if (n >= m->num_objects + m->num_objects_in_base)
return NULL;
+ n = midx_for_object(&m, n);
+
oidread(oid, m->chunk_oid_lookup + st_mult(m->hash_len, n),
the_repository->hash_algo);
return oid;
@@ -316,6 +544,8 @@ off_t nth_midxed_offset(struct multi_pack_index *m, uint32_t pos)
const unsigned char *offset_data;
uint32_t offset32;
+ pos = midx_for_object(&m, pos);
+
offset_data = m->chunk_object_offsets + (off_t)pos * MIDX_CHUNK_OFFSET_WIDTH;
offset32 = get_be32(offset_data + sizeof(uint32_t));
@@ -334,8 +564,10 @@ off_t nth_midxed_offset(struct multi_pack_index *m, uint32_t pos)
uint32_t nth_midxed_pack_int_id(struct multi_pack_index *m, uint32_t pos)
{
- return get_be32(m->chunk_object_offsets +
- (off_t)pos * MIDX_CHUNK_OFFSET_WIDTH);
+ pos = midx_for_object(&m, pos);
+
+ return m->num_packs_in_base + get_be32(m->chunk_object_offsets +
+ (off_t)pos * MIDX_CHUNK_OFFSET_WIDTH);
}
int fill_midx_entry(struct repository *r,
@@ -350,14 +582,12 @@ int fill_midx_entry(struct repository *r,
if (!bsearch_midx(oid, m, &pos))
return 0;
- if (pos >= m->num_objects)
- return 0;
-
+ midx_for_object(&m, pos);
pack_int_id = nth_midxed_pack_int_id(m, pos);
if (prepare_midx_pack(r, m, pack_int_id))
return 0;
- p = m->packs[pack_int_id];
+ p = m->packs[pack_int_id - m->num_packs_in_base];
/*
* We are about to tell the caller where they can locate the
@@ -411,8 +641,8 @@ int cmp_idx_or_pack_name(const char *idx_or_pack_name,
return strcmp(idx_or_pack_name, idx_name);
}
-int midx_locate_pack(struct multi_pack_index *m, const char *idx_or_pack_name,
- uint32_t *pos)
+static int midx_contains_pack_1(struct multi_pack_index *m,
+ const char *idx_or_pack_name)
{
uint32_t first = 0, last = m->num_packs;
@@ -423,11 +653,8 @@ int midx_locate_pack(struct multi_pack_index *m, const char *idx_or_pack_name,
current = m->pack_names[mid];
cmp = cmp_idx_or_pack_name(idx_or_pack_name, current);
- if (!cmp) {
- if (pos)
- *pos = mid;
+ if (!cmp)
return 1;
- }
if (cmp > 0) {
first = mid + 1;
continue;
@@ -440,19 +667,25 @@ int midx_locate_pack(struct multi_pack_index *m, const char *idx_or_pack_name,
int midx_contains_pack(struct multi_pack_index *m, const char *idx_or_pack_name)
{
- return midx_locate_pack(m, idx_or_pack_name, NULL);
+ for (; m; m = m->base_midx)
+ if (midx_contains_pack_1(m, idx_or_pack_name))
+ return 1;
+ return 0;
}
int midx_preferred_pack(struct multi_pack_index *m, uint32_t *pack_int_id)
{
if (m->preferred_pack_idx == -1) {
+ uint32_t midx_pos;
if (load_midx_revindex(m) < 0) {
m->preferred_pack_idx = -2;
return -1;
}
- m->preferred_pack_idx =
- nth_midxed_pack_int_id(m, pack_pos_to_midx(m, 0));
+ midx_pos = pack_pos_to_midx(m, m->num_objects_in_base);
+
+ m->preferred_pack_idx = nth_midxed_pack_int_id(m, midx_pos);
+
} else if (m->preferred_pack_idx == -2)
return -1; /* no revindex */
@@ -494,7 +727,8 @@ int midx_checksum_valid(struct multi_pack_index *m)
}
struct clear_midx_data {
- char *keep;
+ char **keep;
+ uint32_t keep_nr;
const char *ext;
};
@@ -502,32 +736,63 @@ static void clear_midx_file_ext(const char *full_path, size_t full_path_len UNUS
const char *file_name, void *_data)
{
struct clear_midx_data *data = _data;
+ uint32_t i;
if (!(starts_with(file_name, "multi-pack-index-") &&
ends_with(file_name, data->ext)))
return;
- if (data->keep && !strcmp(data->keep, file_name))
- return;
-
+ for (i = 0; i < data->keep_nr; i++) {
+ if (!strcmp(data->keep[i], file_name))
+ return;
+ }
if (unlink(full_path))
die_errno(_("failed to remove %s"), full_path);
}
void clear_midx_files_ext(const char *object_dir, const char *ext,
- unsigned char *keep_hash)
+ const char *keep_hash)
{
struct clear_midx_data data;
memset(&data, 0, sizeof(struct clear_midx_data));
- if (keep_hash)
- data.keep = xstrfmt("multi-pack-index-%s%s",
- hash_to_hex(keep_hash), ext);
+ if (keep_hash) {
+ ALLOC_ARRAY(data.keep, 1);
+
+ data.keep[0] = xstrfmt("multi-pack-index-%s.%s", keep_hash, ext);
+ data.keep_nr = 1;
+ }
data.ext = ext;
for_each_file_in_pack_dir(object_dir,
clear_midx_file_ext,
&data);
+ if (keep_hash)
+ free(data.keep[0]);
+ free(data.keep);
+}
+
+void clear_incremental_midx_files_ext(const char *object_dir, const char *ext,
+ char **keep_hashes,
+ uint32_t hashes_nr)
+{
+ struct clear_midx_data data;
+ uint32_t i;
+
+ memset(&data, 0, sizeof(struct clear_midx_data));
+
+ ALLOC_ARRAY(data.keep, hashes_nr);
+ for (i = 0; i < hashes_nr; i++)
+ data.keep[i] = xstrfmt("multi-pack-index-%s.%s", keep_hashes[i],
+ ext);
+ data.keep_nr = hashes_nr;
+ data.ext = ext;
+
+ for_each_file_in_pack_subdir(object_dir, "multi-pack-index.d",
+ clear_midx_file_ext, &data);
+
+ for (i = 0; i < hashes_nr; i++)
+ free(data.keep[i]);
free(data.keep);
}
@@ -545,8 +810,8 @@ void clear_midx_file(struct repository *r)
if (remove_path(midx.buf))
die(_("failed to clear multi-pack-index at %s"), midx.buf);
- clear_midx_files_ext(r->objects->odb->path, ".bitmap", NULL);
- clear_midx_files_ext(r->objects->odb->path, ".rev", NULL);
+ clear_midx_files_ext(r->objects->odb->path, MIDX_EXT_BITMAP, NULL);
+ clear_midx_files_ext(r->objects->odb->path, MIDX_EXT_REV, NULL);
strbuf_release(&midx);
}
@@ -596,6 +861,7 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
uint32_t i;
struct progress *progress = NULL;
struct multi_pack_index *m = load_multi_pack_index(object_dir, 1);
+ struct multi_pack_index *curr;
verify_midx_error = 0;
if (!m) {
@@ -618,8 +884,8 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
if (flags & MIDX_PROGRESS)
progress = start_delayed_progress(_("Looking for referenced packfiles"),
- m->num_packs);
- for (i = 0; i < m->num_packs; i++) {
+ m->num_packs + m->num_packs_in_base);
+ for (i = 0; i < m->num_packs + m->num_packs_in_base; i++) {
if (prepare_midx_pack(r, m, i))
midx_report("failed to load pack in position %d", i);
@@ -639,17 +905,20 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
if (flags & MIDX_PROGRESS)
progress = start_sparse_progress(_("Verifying OID order in multi-pack-index"),
m->num_objects - 1);
- for (i = 0; i < m->num_objects - 1; i++) {
- struct object_id oid1, oid2;
- nth_midxed_object_oid(&oid1, m, i);
- nth_midxed_object_oid(&oid2, m, i + 1);
+ for (curr = m; curr; curr = curr->base_midx) {
+ for (i = 0; i < m->num_objects - 1; i++) {
+ struct object_id oid1, oid2;
- if (oidcmp(&oid1, &oid2) >= 0)
- midx_report(_("oid lookup out of order: oid[%d] = %s >= %s = oid[%d]"),
- i, oid_to_hex(&oid1), oid_to_hex(&oid2), i + 1);
+ nth_midxed_object_oid(&oid1, m, m->num_objects_in_base + i);
+ nth_midxed_object_oid(&oid2, m, m->num_objects_in_base + i + 1);
- midx_display_sparse_progress(progress, i + 1);
+ if (oidcmp(&oid1, &oid2) >= 0)
+ midx_report(_("oid lookup out of order: oid[%d] = %s >= %s = oid[%d]"),
+ i, oid_to_hex(&oid1), oid_to_hex(&oid2), i + 1);
+
+ midx_display_sparse_progress(progress, i + 1);
+ }
}
stop_progress(&progress);
@@ -659,8 +928,8 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
* each of the objects and only require 1 packfile to be open at a
* time.
*/
- ALLOC_ARRAY(pairs, m->num_objects);
- for (i = 0; i < m->num_objects; i++) {
+ ALLOC_ARRAY(pairs, m->num_objects + m->num_objects_in_base);
+ for (i = 0; i < m->num_objects + m->num_objects_in_base; i++) {
pairs[i].pos = i;
pairs[i].pack_int_id = nth_midxed_pack_int_id(m, i);
}
@@ -674,16 +943,18 @@ int verify_midx_file(struct repository *r, const char *object_dir, unsigned flag
if (flags & MIDX_PROGRESS)
progress = start_sparse_progress(_("Verifying object offsets"), m->num_objects);
- for (i = 0; i < m->num_objects; i++) {
+ for (i = 0; i < m->num_objects + m->num_objects_in_base; i++) {
struct object_id oid;
struct pack_entry e;
off_t m_offset, p_offset;
if (i > 0 && pairs[i-1].pack_int_id != pairs[i].pack_int_id &&
- m->packs[pairs[i-1].pack_int_id])
- {
- close_pack_fd(m->packs[pairs[i-1].pack_int_id]);
- close_pack_index(m->packs[pairs[i-1].pack_int_id]);
+ nth_midxed_pack(m, pairs[i-1].pack_int_id)) {
+ uint32_t pack_int_id = pairs[i-1].pack_int_id;
+ struct packed_git *p = nth_midxed_pack(m, pack_int_id);
+
+ close_pack_fd(p);
+ close_pack_index(p);
}
nth_midxed_object_oid(&oid, m, pairs[i].pos);
diff --git a/midx.h b/midx.h
index 8554f2d616..42d4f8d149 100644
--- a/midx.h
+++ b/midx.h
@@ -24,12 +24,13 @@ struct bitmapped_pack;
#define MIDX_CHUNKID_OBJECTOFFSETS 0x4f4f4646 /* "OOFF" */
#define MIDX_CHUNKID_LARGEOFFSETS 0x4c4f4646 /* "LOFF" */
#define MIDX_CHUNKID_REVINDEX 0x52494458 /* "RIDX" */
+#define MIDX_CHUNKID_BASE 0x42415345 /* "BASE" */
#define MIDX_CHUNK_OFFSET_WIDTH (2 * sizeof(uint32_t))
#define MIDX_LARGE_OFFSET_NEEDED 0x80000000
#define GIT_TEST_MULTI_PACK_INDEX "GIT_TEST_MULTI_PACK_INDEX"
-#define GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP \
- "GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP"
+#define GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL \
+ "GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL"
struct multi_pack_index {
struct multi_pack_index *next;
@@ -50,6 +51,7 @@ struct multi_pack_index {
int preferred_pack_idx;
int local;
+ int has_chain;
const unsigned char *chunk_pack_names;
size_t chunk_pack_names_len;
@@ -63,6 +65,10 @@ struct multi_pack_index {
const unsigned char *chunk_revindex;
size_t chunk_revindex_len;
+ struct multi_pack_index *base_midx;
+ uint32_t num_objects_in_base;
+ uint32_t num_packs_in_base;
+
const char **pack_names;
struct packed_git **packs;
char object_dir[FLEX_ARRAY];
@@ -73,20 +79,32 @@ struct multi_pack_index {
#define MIDX_WRITE_BITMAP (1 << 2)
#define MIDX_WRITE_BITMAP_HASH_CACHE (1 << 3)
#define MIDX_WRITE_BITMAP_LOOKUP_TABLE (1 << 4)
+#define MIDX_WRITE_INCREMENTAL (1 << 5)
#define MIDX_EXT_REV "rev"
#define MIDX_EXT_BITMAP "bitmap"
+#define MIDX_EXT_MIDX "midx"
const unsigned char *get_midx_checksum(struct multi_pack_index *m);
void get_midx_filename(struct strbuf *out, const char *object_dir);
void get_midx_filename_ext(struct strbuf *out, const char *object_dir,
const unsigned char *hash, const char *ext);
+void get_midx_chain_dirname(struct strbuf *buf, const char *object_dir);
+void get_midx_chain_filename(struct strbuf *buf, const char *object_dir);
+void get_split_midx_filename_ext(struct strbuf *buf, const char *object_dir,
+ const unsigned char *hash, const char *ext);
struct multi_pack_index *load_multi_pack_index(const char *object_dir, int local);
int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, uint32_t pack_int_id);
+struct packed_git *nth_midxed_pack(struct multi_pack_index *m,
+ uint32_t pack_int_id);
int nth_bitmapped_pack(struct repository *r, struct multi_pack_index *m,
struct bitmapped_pack *bp, uint32_t pack_int_id);
-int bsearch_midx(const struct object_id *oid, struct multi_pack_index *m, uint32_t *result);
+int bsearch_one_midx(const struct object_id *oid, struct multi_pack_index *m,
+ uint32_t *result);
+int bsearch_midx(const struct object_id *oid, struct multi_pack_index *m,
+ uint32_t *result);
+int midx_has_oid(struct multi_pack_index *m, const struct object_id *oid);
off_t nth_midxed_offset(struct multi_pack_index *m, uint32_t pos);
uint32_t nth_midxed_pack_int_id(struct multi_pack_index *m, uint32_t pos);
struct object_id *nth_midxed_object_oid(struct object_id *oid,
@@ -95,8 +113,6 @@ struct object_id *nth_midxed_object_oid(struct object_id *oid,
int fill_midx_entry(struct repository *r, const struct object_id *oid, struct pack_entry *e, struct multi_pack_index *m);
int midx_contains_pack(struct multi_pack_index *m,
const char *idx_or_pack_name);
-int midx_locate_pack(struct multi_pack_index *m, const char *idx_or_pack_name,
- uint32_t *pos);
int midx_preferred_pack(struct multi_pack_index *m, uint32_t *pack_int_id);
int prepare_multi_pack_index_one(struct repository *r, const char *object_dir, int local);
diff --git a/negotiator/default.c b/negotiator/default.c
index e3fa5c3324..c479da9b09 100644
--- a/negotiator/default.c
+++ b/negotiator/default.c
@@ -38,7 +38,7 @@ static void rev_list_push(struct negotiation_state *ns,
}
}
-static int clear_marks(const char *refname, const struct object_id *oid,
+static int clear_marks(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED,
void *cb_data UNUSED)
{
diff --git a/negotiator/skipping.c b/negotiator/skipping.c
index f109928ad0..f65d47858b 100644
--- a/negotiator/skipping.c
+++ b/negotiator/skipping.c
@@ -75,7 +75,7 @@ static struct entry *rev_list_push(struct data *data, struct commit *commit, int
return entry;
}
-static int clear_marks(const char *refname, const struct object_id *oid,
+static int clear_marks(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED,
void *cb_data UNUSED)
{
diff --git a/notes.c b/notes.c
index 1ba6412aae..da42df282d 100644
--- a/notes.c
+++ b/notes.c
@@ -932,7 +932,7 @@ out:
return ret;
}
-static int string_list_add_one_ref(const char *refname,
+static int string_list_add_one_ref(const char *refname, const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flag UNUSED, void *cb)
{
diff --git a/object-file.c b/object-file.c
index 065103be3e..c5994202ba 100644
--- a/object-file.c
+++ b/object-file.c
@@ -2470,11 +2470,10 @@ int repo_has_object_file(struct repository *r,
* give more context.
*/
static int hash_format_check_report(struct fsck_options *opts UNUSED,
- const struct object_id *oid UNUSED,
- enum object_type object_type UNUSED,
- enum fsck_msg_type msg_type UNUSED,
- enum fsck_msg_id msg_id UNUSED,
- const char *message)
+ void *fsck_report UNUSED,
+ enum fsck_msg_type msg_type UNUSED,
+ enum fsck_msg_id msg_id UNUSED,
+ const char *message)
{
error(_("object fails fsck: %s"), message);
return 1;
@@ -2954,6 +2953,7 @@ int read_loose_object(const char *path,
if (unpack_loose_header(&stream, map, mapsize, hdr, sizeof(hdr),
NULL) != ULHR_OK) {
error(_("unable to unpack header of %s"), path);
+ git_inflate_end(&stream);
goto out;
}
diff --git a/object-name.c b/object-name.c
index 240a93e7ce..09c1bd93a3 100644
--- a/object-name.c
+++ b/object-name.c
@@ -135,28 +135,32 @@ static int match_hash(unsigned len, const unsigned char *a, const unsigned char
static void unique_in_midx(struct multi_pack_index *m,
struct disambiguate_state *ds)
{
- uint32_t num, i, first = 0;
- const struct object_id *current = NULL;
- int len = ds->len > ds->repo->hash_algo->hexsz ?
- ds->repo->hash_algo->hexsz : ds->len;
- num = m->num_objects;
+ for (; m; m = m->base_midx) {
+ uint32_t num, i, first = 0;
+ const struct object_id *current = NULL;
+ int len = ds->len > ds->repo->hash_algo->hexsz ?
+ ds->repo->hash_algo->hexsz : ds->len;
- if (!num)
- return;
+ if (!m->num_objects)
+ continue;
- bsearch_midx(&ds->bin_pfx, m, &first);
+ num = m->num_objects + m->num_objects_in_base;
- /*
- * At this point, "first" is the location of the lowest object
- * with an object name that could match "bin_pfx". See if we have
- * 0, 1 or more objects that actually match(es).
- */
- for (i = first; i < num && !ds->ambiguous; i++) {
- struct object_id oid;
- current = nth_midxed_object_oid(&oid, m, i);
- if (!match_hash(len, ds->bin_pfx.hash, current->hash))
- break;
- update_candidates(ds, current);
+ bsearch_one_midx(&ds->bin_pfx, m, &first);
+
+ /*
+ * At this point, "first" is the location of the lowest
+ * object with an object name that could match
+ * "bin_pfx". See if we have 0, 1 or more objects that
+ * actually match(es).
+ */
+ for (i = first; i < num && !ds->ambiguous; i++) {
+ struct object_id oid;
+ current = nth_midxed_object_oid(&oid, m, i);
+ if (!match_hash(len, ds->bin_pfx.hash, current->hash))
+ break;
+ update_candidates(ds, current);
+ }
}
}
@@ -709,37 +713,40 @@ static int repo_extend_abbrev_len(struct repository *r UNUSED,
static void find_abbrev_len_for_midx(struct multi_pack_index *m,
struct min_abbrev_data *mad)
{
- int match = 0;
- uint32_t num, first = 0;
- struct object_id oid;
- const struct object_id *mad_oid;
+ for (; m; m = m->base_midx) {
+ int match = 0;
+ uint32_t num, first = 0;
+ struct object_id oid;
+ const struct object_id *mad_oid;
- if (!m->num_objects)
- return;
+ if (!m->num_objects)
+ continue;
- num = m->num_objects;
- mad_oid = mad->oid;
- match = bsearch_midx(mad_oid, m, &first);
+ num = m->num_objects + m->num_objects_in_base;
+ mad_oid = mad->oid;
+ match = bsearch_one_midx(mad_oid, m, &first);
- /*
- * first is now the position in the packfile where we would insert
- * mad->hash if it does not exist (or the position of mad->hash if
- * it does exist). Hence, we consider a maximum of two objects
- * nearby for the abbreviation length.
- */
- mad->init_len = 0;
- if (!match) {
- if (nth_midxed_object_oid(&oid, m, first))
- extend_abbrev_len(&oid, mad);
- } else if (first < num - 1) {
- if (nth_midxed_object_oid(&oid, m, first + 1))
- extend_abbrev_len(&oid, mad);
- }
- if (first > 0) {
- if (nth_midxed_object_oid(&oid, m, first - 1))
- extend_abbrev_len(&oid, mad);
+ /*
+ * first is now the position in the packfile where we
+ * would insert mad->hash if it does not exist (or the
+ * position of mad->hash if it does exist). Hence, we
+ * consider a maximum of two objects nearby for the
+ * abbreviation length.
+ */
+ mad->init_len = 0;
+ if (!match) {
+ if (nth_midxed_object_oid(&oid, m, first))
+ extend_abbrev_len(&oid, mad);
+ } else if (first < num - 1) {
+ if (nth_midxed_object_oid(&oid, m, first + 1))
+ extend_abbrev_len(&oid, mad);
+ }
+ if (first > 0) {
+ if (nth_midxed_object_oid(&oid, m, first - 1))
+ extend_abbrev_len(&oid, mad);
+ }
+ mad->init_len = mad->cur_len;
}
- mad->init_len = mad->cur_len;
}
static void find_abbrev_len_for_pack(struct packed_git *p,
@@ -1368,7 +1375,7 @@ struct handle_one_ref_cb {
struct commit_list **list;
};
-static int handle_one_ref(const char *path, const struct object_id *oid,
+static int handle_one_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED,
void *cb_data)
{
@@ -1765,6 +1772,7 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name)
void object_context_release(struct object_context *ctx)
{
free(ctx->path);
+ strbuf_release(&ctx->symlink_path);
}
/*
diff --git a/object.c b/object.c
index 0c0fcb76c0..d756c7f2ea 100644
--- a/object.c
+++ b/object.c
@@ -614,6 +614,15 @@ void raw_object_store_clear(struct raw_object_store *o)
INIT_LIST_HEAD(&o->packed_git_mru);
close_object_store(o);
+
+ /*
+ * `close_object_store()` only closes the packfiles, but doesn't free
+ * them. We thus have to do this manually.
+ */
+ for (struct packed_git *p = o->packed_git, *next; p; p = next) {
+ next = p->next;
+ free(p);
+ }
o->packed_git = NULL;
hashmap_clear(&o->pack_map);
diff --git a/packfile.c b/packfile.c
index 813584646f..cf12a539ea 100644
--- a/packfile.c
+++ b/packfile.c
@@ -815,9 +815,10 @@ static void report_pack_garbage(struct string_list *list)
report_helper(list, seen_bits, first, list->nr);
}
-void for_each_file_in_pack_dir(const char *objdir,
- each_file_in_pack_dir_fn fn,
- void *data)
+void for_each_file_in_pack_subdir(const char *objdir,
+ const char *subdir,
+ each_file_in_pack_dir_fn fn,
+ void *data)
{
struct strbuf path = STRBUF_INIT;
size_t dirnamelen;
@@ -826,6 +827,8 @@ void for_each_file_in_pack_dir(const char *objdir,
strbuf_addstr(&path, objdir);
strbuf_addstr(&path, "/pack");
+ if (subdir)
+ strbuf_addf(&path, "/%s", subdir);
dir = opendir(path.buf);
if (!dir) {
if (errno != ENOENT)
@@ -847,6 +850,13 @@ void for_each_file_in_pack_dir(const char *objdir,
strbuf_release(&path);
}
+void for_each_file_in_pack_dir(const char *objdir,
+ each_file_in_pack_dir_fn fn,
+ void *data)
+{
+ for_each_file_in_pack_subdir(objdir, NULL, fn, data);
+}
+
struct prepare_pack_data {
struct repository *r;
struct string_list *garbage;
@@ -880,7 +890,8 @@ static void prepare_pack(const char *full_name, size_t full_name_len,
if (!report_garbage)
return;
- if (!strcmp(file_name, "multi-pack-index"))
+ if (!strcmp(file_name, "multi-pack-index") ||
+ !strcmp(file_name, "multi-pack-index.d"))
return;
if (starts_with(file_name, "multi-pack-index") &&
(ends_with(file_name, ".bitmap") || ends_with(file_name, ".rev")))
@@ -1064,7 +1075,7 @@ struct packed_git *get_all_packs(struct repository *r)
prepare_packed_git(r);
for (m = r->objects->multi_pack_index; m; m = m->next) {
uint32_t i;
- for (i = 0; i < m->num_packs; i++)
+ for (i = 0; i < m->num_packs + m->num_packs_in_base; i++)
prepare_midx_pack(r, m, i);
}
diff --git a/packfile.h b/packfile.h
index eb18ec15db..0f78658229 100644
--- a/packfile.h
+++ b/packfile.h
@@ -55,6 +55,10 @@ struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
typedef void each_file_in_pack_dir_fn(const char *full_path, size_t full_path_len,
const char *file_name, void *data);
+void for_each_file_in_pack_subdir(const char *objdir,
+ const char *subdir,
+ each_file_in_pack_dir_fn fn,
+ void *data);
void for_each_file_in_pack_dir(const char *objdir,
each_file_in_pack_dir_fn fn,
void *data);
diff --git a/parallel-checkout.c b/parallel-checkout.c
index 08b960aac8..01736f1352 100644
--- a/parallel-checkout.c
+++ b/parallel-checkout.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "entry.h"
diff --git a/path.c b/path.c
index 19f7684f38..a3bf25b7de 100644
--- a/path.c
+++ b/path.c
@@ -2,8 +2,6 @@
* Utilities for paths and pathnames
*/
-#define USE_THE_REPOSITORY_VARIABLE
-
#include "git-compat-util.h"
#include "abspath.h"
#include "environment.h"
@@ -30,7 +28,7 @@ static int get_st_mode_bits(const char *path, int *mode)
return 0;
}
-static struct strbuf *get_pathname(void)
+struct strbuf *get_pathname(void)
{
static struct strbuf pathname_array[4] = {
STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
@@ -365,15 +363,15 @@ static void update_common_dir(struct strbuf *buf, int git_dir_len,
strbuf_addstr(buf, LOCK_SUFFIX);
}
-void report_linked_checkout_garbage(void)
+void report_linked_checkout_garbage(struct repository *r)
{
struct strbuf sb = STRBUF_INIT;
const struct common_dir *p;
int len;
- if (!the_repository->different_commondir)
+ if (!r->different_commondir)
return;
- strbuf_addf(&sb, "%s/", get_git_dir());
+ strbuf_addf(&sb, "%s/", r->gitdir);
len = sb.len;
for (p = common_list; p->path; p++) {
const char *path = p->path;
@@ -417,9 +415,9 @@ static void strbuf_worktree_gitdir(struct strbuf *buf,
strbuf_git_common_path(buf, repo, "worktrees/%s", wt->id);
}
-static void do_git_path(const struct repository *repo,
- const struct worktree *wt, struct strbuf *buf,
- const char *fmt, va_list args)
+void repo_git_pathv(const struct repository *repo,
+ const struct worktree *wt, struct strbuf *buf,
+ const char *fmt, va_list args)
{
int gitdir_len;
strbuf_worktree_gitdir(buf, repo, wt);
@@ -438,7 +436,7 @@ char *repo_git_path(const struct repository *repo,
struct strbuf path = STRBUF_INIT;
va_list args;
va_start(args, fmt);
- do_git_path(repo, NULL, &path, fmt, args);
+ repo_git_pathv(repo, NULL, &path, fmt, args);
va_end(args);
return strbuf_detach(&path, NULL);
}
@@ -449,48 +447,10 @@ void strbuf_repo_git_path(struct strbuf *sb,
{
va_list args;
va_start(args, fmt);
- do_git_path(repo, NULL, sb, fmt, args);
- va_end(args);
-}
-
-char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
-{
- va_list args;
- strbuf_reset(buf);
- va_start(args, fmt);
- do_git_path(the_repository, NULL, buf, fmt, args);
- va_end(args);
- return buf->buf;
-}
-
-void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- do_git_path(the_repository, NULL, sb, fmt, args);
+ repo_git_pathv(repo, NULL, sb, fmt, args);
va_end(args);
}
-const char *git_path(const char *fmt, ...)
-{
- struct strbuf *pathname = get_pathname();
- va_list args;
- va_start(args, fmt);
- do_git_path(the_repository, NULL, pathname, fmt, args);
- va_end(args);
- return pathname->buf;
-}
-
-char *git_pathdup(const char *fmt, ...)
-{
- struct strbuf path = STRBUF_INIT;
- va_list args;
- va_start(args, fmt);
- do_git_path(the_repository, NULL, &path, fmt, args);
- va_end(args);
- return strbuf_detach(&path, NULL);
-}
-
char *mkpathdup(const char *fmt, ...)
{
struct strbuf sb = STRBUF_INIT;
@@ -512,12 +472,17 @@ const char *mkpath(const char *fmt, ...)
return cleanup_path(pathname->buf);
}
-const char *worktree_git_path(const struct worktree *wt, const char *fmt, ...)
+const char *worktree_git_path(struct repository *r,
+ const struct worktree *wt, const char *fmt, ...)
{
struct strbuf *pathname = get_pathname();
va_list args;
+
+ if (wt && wt->repo != r)
+ BUG("worktree not connected to expected repository");
+
va_start(args, fmt);
- do_git_path(the_repository, wt, pathname, fmt, args);
+ repo_git_pathv(r, wt, pathname, fmt, args);
va_end(args);
return pathname->buf;
}
@@ -617,26 +582,16 @@ int strbuf_git_path_submodule(struct strbuf *buf, const char *path,
return err;
}
-static void do_git_common_path(const struct repository *repo,
- struct strbuf *buf,
- const char *fmt,
- va_list args)
+void repo_common_pathv(const struct repository *repo,
+ struct strbuf *sb,
+ const char *fmt,
+ va_list args)
{
- strbuf_addstr(buf, repo->commondir);
- if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
- strbuf_addch(buf, '/');
- strbuf_vaddf(buf, fmt, args);
- strbuf_cleanup_path(buf);
-}
-
-const char *git_common_path(const char *fmt, ...)
-{
- struct strbuf *pathname = get_pathname();
- va_list args;
- va_start(args, fmt);
- do_git_common_path(the_repository, pathname, fmt, args);
- va_end(args);
- return pathname->buf;
+ strbuf_addstr(sb, repo->commondir);
+ if (sb->len && !is_dir_sep(sb->buf[sb->len - 1]))
+ strbuf_addch(sb, '/');
+ strbuf_vaddf(sb, fmt, args);
+ strbuf_cleanup_path(sb);
}
void strbuf_git_common_path(struct strbuf *sb,
@@ -645,7 +600,7 @@ void strbuf_git_common_path(struct strbuf *sb,
{
va_list args;
va_start(args, fmt);
- do_git_common_path(repo, sb, fmt, args);
+ repo_common_pathv(repo, sb, fmt, args);
va_end(args);
}
diff --git a/path.h b/path.h
index a6f0b70692..e91d19fff6 100644
--- a/path.h
+++ b/path.h
@@ -25,7 +25,7 @@ char *mkpathdup(const char *fmt, ...)
__attribute__((format (printf, 1, 2)));
/*
- * The `git_common_path` family of functions will construct a path into a
+ * The `strbuf_git_common_path` family of functions will construct a path into a
* repository's common git directory, which is shared by all worktrees.
*/
@@ -37,17 +37,13 @@ void strbuf_git_common_path(struct strbuf *sb,
const struct repository *repo,
const char *fmt, ...)
__attribute__((format (printf, 3, 4)));
+void repo_common_pathv(const struct repository *repo,
+ struct strbuf *buf,
+ const char *fmt,
+ va_list args);
/*
- * Return a statically allocated path into the main repository's
- * (the_repository) common git directory.
- */
-const char *git_common_path(const char *fmt, ...)
- __attribute__((format (printf, 1, 2)));
-
-
-/*
- * The `git_path` family of functions will construct a path into a repository's
+ * The `repo_git_path` family of functions will construct a path into a repository's
* git directory.
*
* These functions will perform adjustments to the resultant path to account
@@ -67,6 +63,14 @@ char *repo_git_path(const struct repository *repo,
__attribute__((format (printf, 2, 3)));
/*
+ * Print a path into the git directory of repository `repo` into the provided
+ * buffer.
+ */
+void repo_git_pathv(const struct repository *repo,
+ const struct worktree *wt, struct strbuf *buf,
+ const char *fmt, va_list args);
+
+/*
* Construct a path into the git directory of repository `repo` and append it
* to the provided buffer `sb`.
*/
@@ -76,40 +80,14 @@ void strbuf_repo_git_path(struct strbuf *sb,
__attribute__((format (printf, 3, 4)));
/*
- * Return a statically allocated path into the main repository's
- * (the_repository) git directory.
- */
-const char *git_path(const char *fmt, ...)
- __attribute__((format (printf, 1, 2)));
-
-/*
- * Similar to git_path() but can produce paths for a specified
- * worktree instead of current one
+ * Similar to repo_git_path() but can produce paths for a specified
+ * worktree instead of current one. When no worktree is given, then the path is
+ * computed relative to main worktree of the given repository.
*/
-const char *worktree_git_path(const struct worktree *wt,
+const char *worktree_git_path(struct repository *r,
+ const struct worktree *wt,
const char *fmt, ...)
- __attribute__((format (printf, 2, 3)));
-
-/*
- * Return a path into the main repository's (the_repository) git directory.
- */
-char *git_pathdup(const char *fmt, ...)
- __attribute__((format (printf, 1, 2)));
-
-/*
- * Construct a path into the main repository's (the_repository) git directory
- * and place it in the provided buffer `buf`, the contents of the buffer will
- * be overridden.
- */
-char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
- __attribute__((format (printf, 2, 3)));
-
-/*
- * Construct a path into the main repository's (the_repository) git directory
- * and append it to the provided buffer `sb`.
- */
-void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
- __attribute__((format (printf, 2, 3)));
+ __attribute__((format (printf, 3, 4)));
/*
* Return a path into the worktree of repository `repo`.
@@ -147,24 +125,15 @@ int strbuf_git_path_submodule(struct strbuf *sb, const char *path,
const char *fmt, ...)
__attribute__((format (printf, 3, 4)));
-void report_linked_checkout_garbage(void);
+void report_linked_checkout_garbage(struct repository *r);
/*
* You can define a static memoized git path like:
*
- * static GIT_PATH_FUNC(git_path_foo, "FOO")
+ * static REPO_GIT_PATH_FUNC(git_path_foo, "FOO")
*
* or use one of the global ones below.
*/
-#define GIT_PATH_FUNC(func, filename) \
- const char *func(void) \
- { \
- static char *ret; \
- if (!ret) \
- ret = git_pathdup(filename); \
- return ret; \
- }
-
#define REPO_GIT_PATH_FUNC(var, filename) \
const char *git_path_##var(struct repository *r) \
{ \
@@ -248,4 +217,99 @@ char *xdg_cache_home(const char *filename);
*/
void safe_create_dir(const char *dir, int share);
+/*
+ * Do not use this function. It is only exported to other subsystems until we
+ * can get rid of the below block of functions that implicitly rely on
+ * `the_repository`.
+ */
+struct strbuf *get_pathname(void);
+
+# ifdef USE_THE_REPOSITORY_VARIABLE
+# include "strbuf.h"
+# include "repository.h"
+
+/*
+ * Return a statically allocated path into the main repository's
+ * (the_repository) common git directory.
+ */
+__attribute__((format (printf, 1, 2)))
+static inline const char *git_common_path(const char *fmt, ...)
+{
+ struct strbuf *pathname = get_pathname();
+ va_list args;
+ va_start(args, fmt);
+ repo_common_pathv(the_repository, pathname, fmt, args);
+ va_end(args);
+ return pathname->buf;
+}
+
+/*
+ * Construct a path into the main repository's (the_repository) git directory
+ * and place it in the provided buffer `buf`, the contents of the buffer will
+ * be overridden.
+ */
+__attribute__((format (printf, 2, 3)))
+static inline char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
+{
+ va_list args;
+ strbuf_reset(buf);
+ va_start(args, fmt);
+ repo_git_pathv(the_repository, NULL, buf, fmt, args);
+ va_end(args);
+ return buf->buf;
+}
+
+/*
+ * Construct a path into the main repository's (the_repository) git directory
+ * and append it to the provided buffer `sb`.
+ */
+__attribute__((format (printf, 2, 3)))
+static inline void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ repo_git_pathv(the_repository, NULL, sb, fmt, args);
+ va_end(args);
+}
+
+/*
+ * Return a statically allocated path into the main repository's
+ * (the_repository) git directory.
+ */
+__attribute__((format (printf, 1, 2)))
+static inline const char *git_path(const char *fmt, ...)
+{
+ struct strbuf *pathname = get_pathname();
+ va_list args;
+ va_start(args, fmt);
+ repo_git_pathv(the_repository, NULL, pathname, fmt, args);
+ va_end(args);
+ return pathname->buf;
+}
+
+#define GIT_PATH_FUNC(func, filename) \
+ const char *func(void) \
+ { \
+ static char *ret; \
+ if (!ret) \
+ ret = git_pathdup(filename); \
+ return ret; \
+ }
+
+/*
+ * Return a path into the main repository's (the_repository) git directory.
+ */
+__attribute__((format (printf, 1, 2)))
+static inline char *git_pathdup(const char *fmt, ...)
+{
+ struct strbuf path = STRBUF_INIT;
+ va_list args;
+ va_start(args, fmt);
+ repo_git_pathv(the_repository, NULL, &path, fmt, args);
+ va_end(args);
+ return strbuf_detach(&path, NULL);
+}
+
+# endif /* USE_THE_REPOSITORY_VARIABLE */
+
#endif /* PATH_H */
diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm
index 7721708ce5..b0913ca1b6 100644
--- a/perl/Git/SVN.pm
+++ b/perl/Git/SVN.pm
@@ -763,7 +763,7 @@ sub prop_walk {
# this needs to be updated.
++$interesting_props if /^svn:(?:ignore|keywords|executable
|eol-style|mime-type
- |externals|needs-lock)$/x;
+ |externals|needs-lock|global-ignores)$/x;
}
&$sub($self, $p, $props) if $interesting_props;
diff --git a/protocol.c b/protocol.c
index 079ba75acf..bae7226ff4 100644
--- a/protocol.c
+++ b/protocol.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "environment.h"
diff --git a/pseudo-merge.c b/pseudo-merge.c
index f0fde13c47..77a83b9c5c 100644
--- a/pseudo-merge.c
+++ b/pseudo-merge.c
@@ -201,6 +201,7 @@ void load_pseudo_merges_from_config(struct string_list *list)
}
static int find_pseudo_merge_group_for_ref(const char *refname,
+ const char *referent UNUSED,
const struct object_id *oid,
int flags UNUSED,
void *_data)
diff --git a/range-diff.c b/range-diff.c
index 5f01605550..bbb0952264 100644
--- a/range-diff.c
+++ b/range-diff.c
@@ -450,8 +450,10 @@ static void output_pair_header(struct diff_options *diffopt,
}
static struct userdiff_driver section_headers = {
- .funcname = { "^ ## (.*) ##$\n"
- "^.?@@ (.*)$", REG_EXTENDED }
+ .funcname = {
+ .pattern = "^ ## (.*) ##$\n^.?@@ (.*)$",
+ .cflags = REG_EXTENDED,
+ },
};
static struct diff_filespec *get_filespec(const char *name, const char *p)
diff --git a/reachable.c b/reachable.c
index 46613a6bb6..3e9b3dd0a4 100644
--- a/reachable.c
+++ b/reachable.c
@@ -79,7 +79,7 @@ static void add_rebase_files(struct rev_info *revs)
free_worktrees(worktrees);
}
-static int add_one_ref(const char *path, const struct object_id *oid,
+static int add_one_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
int flag, void *cb_data)
{
struct rev_info *revs = (struct rev_info *)cb_data;
diff --git a/read-cache.c b/read-cache.c
index 1f67bb755b..5464398162 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -1945,7 +1945,7 @@ static void tweak_untracked_cache(struct index_state *istate)
static void tweak_split_index(struct index_state *istate)
{
- switch (git_config_get_split_index()) {
+ switch (repo_config_get_split_index(the_repository)) {
case -1: /* unset: do nothing */
break;
case 0: /* false */
@@ -2267,7 +2267,7 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
src_offset = sizeof(*hdr);
- if (git_config_get_index_threads(&nr_threads))
+ if (repo_config_get_index_threads(the_repository, &nr_threads))
nr_threads = 1;
/* TODO: does creating more threads than cores help? */
@@ -2787,7 +2787,7 @@ static int record_eoie(void)
* used for threading is written by default if the user
* explicitly requested threaded index reads.
*/
- return !git_config_get_index_threads(&val) && val != 1;
+ return !repo_config_get_index_threads(the_repository, &val) && val != 1;
}
static int record_ieot(void)
@@ -2802,7 +2802,7 @@ static int record_ieot(void)
* written by default if the user explicitly requested
* threaded index reads.
*/
- return !git_config_get_index_threads(&val) && val != 1;
+ return !repo_config_get_index_threads(the_repository, &val) && val != 1;
}
enum write_extensions {
@@ -2840,8 +2840,9 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
int csum_fsync_flag;
int ieot_entries = 1;
struct index_entry_offset_table *ieot = NULL;
- int nr, nr_threads;
struct repository *r = istate->repo;
+ struct strbuf sb = STRBUF_INIT;
+ int nr, nr_threads, ret;
f = hashfd(tempfile->fd, tempfile->filename.buf);
@@ -2875,7 +2876,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
hashwrite(f, &hdr, sizeof(hdr));
- if (!HAVE_THREADS || git_config_get_index_threads(&nr_threads))
+ if (!HAVE_THREADS || repo_config_get_index_threads(the_repository, &nr_threads))
nr_threads = 1;
if (nr_threads != 1 && record_ieot()) {
@@ -2962,8 +2963,8 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
strbuf_release(&previous_name_buf);
if (err) {
- free(ieot);
- goto cleanup;
+ ret = err;
+ goto out;
}
offset = hashfile_total(f);
@@ -2985,26 +2986,20 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
* index.
*/
if (ieot) {
- struct strbuf sb = STRBUF_INIT;
+ strbuf_reset(&sb);
write_ieot_extension(&sb, ieot);
err = write_index_ext_header(f, eoie_c, CACHE_EXT_INDEXENTRYOFFSETTABLE, sb.len) < 0;
hashwrite(f, sb.buf, sb.len);
- strbuf_release(&sb);
- free(ieot);
- /*
- * NEEDSWORK: write_index_ext_header() never returns a failure,
- * and this part may want to be simplified.
- */
if (err) {
- err = -1;
- goto cleanup;
+ ret = -1;
+ goto out;
}
}
if (write_extensions & WRITE_SPLIT_INDEX_EXTENSION &&
istate->split_index) {
- struct strbuf sb = STRBUF_INIT;
+ strbuf_reset(&sb);
if (istate->sparse_index)
die(_("cannot write split index for a sparse index"));
@@ -3013,95 +3008,65 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
write_index_ext_header(f, eoie_c, CACHE_EXT_LINK,
sb.len) < 0;
hashwrite(f, sb.buf, sb.len);
- strbuf_release(&sb);
- /*
- * NEEDSWORK: write_link_extension() never returns a failure,
- * and this part may want to be simplified.
- */
if (err) {
- err = -1;
- goto cleanup;
+ ret = -1;
+ goto out;
}
}
if (write_extensions & WRITE_CACHE_TREE_EXTENSION &&
!drop_cache_tree && istate->cache_tree) {
- struct strbuf sb = STRBUF_INIT;
+ strbuf_reset(&sb);
cache_tree_write(&sb, istate->cache_tree);
err = write_index_ext_header(f, eoie_c, CACHE_EXT_TREE, sb.len) < 0;
hashwrite(f, sb.buf, sb.len);
- strbuf_release(&sb);
- /*
- * NEEDSWORK: write_index_ext_header() never returns a failure,
- * and this part may want to be simplified.
- */
if (err) {
- err = -1;
- goto cleanup;
+ ret = -1;
+ goto out;
}
}
if (write_extensions & WRITE_RESOLVE_UNDO_EXTENSION &&
istate->resolve_undo) {
- struct strbuf sb = STRBUF_INIT;
+ strbuf_reset(&sb);
resolve_undo_write(&sb, istate->resolve_undo);
err = write_index_ext_header(f, eoie_c, CACHE_EXT_RESOLVE_UNDO,
sb.len) < 0;
hashwrite(f, sb.buf, sb.len);
- strbuf_release(&sb);
- /*
- * NEEDSWORK: write_index_ext_header() never returns a failure,
- * and this part may want to be simplified.
- */
if (err) {
- err = -1;
- goto cleanup;
+ ret = -1;
+ goto out;
}
}
if (write_extensions & WRITE_UNTRACKED_CACHE_EXTENSION &&
istate->untracked) {
- struct strbuf sb = STRBUF_INIT;
+ strbuf_reset(&sb);
write_untracked_extension(&sb, istate->untracked);
err = write_index_ext_header(f, eoie_c, CACHE_EXT_UNTRACKED,
sb.len) < 0;
hashwrite(f, sb.buf, sb.len);
- strbuf_release(&sb);
- /*
- * NEEDSWORK: write_index_ext_header() never returns a failure,
- * and this part may want to be simplified.
- */
if (err) {
- err = -1;
- goto cleanup;
+ ret = -1;
+ goto out;
}
}
if (write_extensions & WRITE_FSMONITOR_EXTENSION &&
istate->fsmonitor_last_update) {
- struct strbuf sb = STRBUF_INIT;
+ strbuf_reset(&sb);
write_fsmonitor_extension(&sb, istate);
err = write_index_ext_header(f, eoie_c, CACHE_EXT_FSMONITOR, sb.len) < 0;
hashwrite(f, sb.buf, sb.len);
- strbuf_release(&sb);
- /*
- * NEEDSWORK: write_index_ext_header() never returns a failure,
- * and this part may want to be simplified.
- */
if (err) {
- err = -1;
- goto cleanup;
+ ret = -1;
+ goto out;
}
}
if (istate->sparse_index) {
- err = write_index_ext_header(f, eoie_c, CACHE_EXT_SPARSE_DIRECTORIES, 0);
- /*
- * NEEDSWORK: write_index_ext_header() never returns a failure,
- * and this part may want to be simplified.
- */
- if (err) {
- err = -1;
- goto cleanup;
+ if (write_index_ext_header(f, eoie_c, CACHE_EXT_SPARSE_DIRECTORIES, 0) < 0) {
+ ret = -1;
+ goto out;
}
}
@@ -3112,19 +3077,14 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
* when loading the shared index.
*/
if (eoie_c) {
- struct strbuf sb = STRBUF_INIT;
+ strbuf_reset(&sb);
write_eoie_extension(&sb, eoie_c, offset);
err = write_index_ext_header(f, NULL, CACHE_EXT_ENDOFINDEXENTRIES, sb.len) < 0;
hashwrite(f, sb.buf, sb.len);
- strbuf_release(&sb);
- /*
- * NEEDSWORK: write_index_ext_header() never returns a failure,
- * and this part may want to be simplified.
- */
if (err) {
- err = -1;
- goto cleanup;
+ ret = -1;
+ goto out;
}
}
@@ -3137,12 +3097,12 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
f = NULL;
if (close_tempfile_gently(tempfile)) {
- err = error(_("could not close '%s'"), get_tempfile_path(tempfile));
- goto cleanup;
+ ret = error(_("could not close '%s'"), get_tempfile_path(tempfile));
+ goto out;
}
if (stat(get_tempfile_path(tempfile), &st)) {
- err = error_errno(_("could not stat '%s'"), get_tempfile_path(tempfile));
- goto cleanup;
+ ret = -1;
+ goto out;
}
istate->timestamp.sec = (unsigned int)st.st_mtime;
istate->timestamp.nsec = ST_MTIME_NSEC(st);
@@ -3157,12 +3117,14 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
trace2_data_intmax("index", the_repository, "write/cache_nr",
istate->cache_nr);
- return 0;
+ ret = 0;
-cleanup:
+out:
if (f)
- discard_hashfile(f);
- return err;
+ free_hashfile(f);
+ strbuf_release(&sb);
+ free(ieot);
+ return ret;
}
void set_alternate_index_output(const char *name)
@@ -3213,9 +3175,9 @@ static int do_write_locked_index(struct index_state *istate,
else
ret = close_lock_file_gently(lock);
- run_hooks_l("post-index-change",
- istate->updated_workdir ? "1" : "0",
- istate->updated_skipworktree ? "1" : "0", NULL);
+ run_hooks_l(the_repository, "post-index-change",
+ istate->updated_workdir ? "1" : "0",
+ istate->updated_skipworktree ? "1" : "0", NULL);
istate->updated_workdir = 0;
istate->updated_skipworktree = 0;
@@ -3241,8 +3203,8 @@ static unsigned long get_shared_index_expire_date(void)
static int shared_index_expire_date_prepared;
if (!shared_index_expire_date_prepared) {
- git_config_get_expiry("splitindex.sharedindexexpire",
- &shared_index_expire);
+ repo_config_get_expiry(the_repository, "splitindex.sharedindexexpire",
+ &shared_index_expire);
shared_index_expire_date = approxidate(shared_index_expire);
shared_index_expire_date_prepared = 1;
}
@@ -3332,7 +3294,7 @@ static const int default_max_percent_split_change = 20;
static int too_many_not_shared_entries(struct index_state *istate)
{
int i, not_shared = 0;
- int max_split = git_config_get_max_percent_split_change();
+ int max_split = repo_config_get_max_percent_split_change(the_repository);
switch (max_split) {
case -1:
diff --git a/ref-filter.c b/ref-filter.c
index 54880a2497..6d8b591930 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -2344,6 +2344,12 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
CALLOC_ARRAY(ref->value, used_atom_cnt);
+ /**
+ * NEEDSWORK: The following code might be unncessary if all codepaths
+ * that call populate_value() populates the symref member of ref_array_item
+ * like in apply_ref_filter(). Currently pretty_print_ref() is the only codepath
+ * that calls populate_value() without first populating symref.
+ */
if (need_symref && (ref->flag & REF_ISSYMREF) && !ref->symref) {
ref->symref = refs_resolve_refdup(get_main_ref_store(the_repository),
ref->refname,
@@ -2784,7 +2790,7 @@ static int filter_ref_kind(struct ref_filter *filter, const char *refname)
return ref_kind_from_refname(refname);
}
-static struct ref_array_item *apply_ref_filter(const char *refname, const struct object_id *oid,
+static struct ref_array_item *apply_ref_filter(const char *refname, const char *referent, const struct object_id *oid,
int flag, struct ref_filter *filter)
{
struct ref_array_item *ref;
@@ -2853,6 +2859,7 @@ static struct ref_array_item *apply_ref_filter(const char *refname, const struct
ref->commit = commit;
ref->flag = flag;
ref->kind = kind;
+ ref->symref = xstrdup_or_null(referent);
return ref;
}
@@ -2866,12 +2873,12 @@ struct ref_filter_cbdata {
* A call-back given to for_each_ref(). Filter refs and keep them for
* later object processing.
*/
-static int filter_one(const char *refname, const struct object_id *oid, int flag, void *cb_data)
+static int filter_one(const char *refname, const char *referent, const struct object_id *oid, int flag, void *cb_data)
{
struct ref_filter_cbdata *ref_cbdata = cb_data;
struct ref_array_item *ref;
- ref = apply_ref_filter(refname, oid, flag, ref_cbdata->filter);
+ ref = apply_ref_filter(refname, referent, oid, flag, ref_cbdata->filter);
if (ref)
ref_array_append(ref_cbdata->array, ref);
@@ -2901,13 +2908,13 @@ struct ref_filter_and_format_cbdata {
} internal;
};
-static int filter_and_format_one(const char *refname, const struct object_id *oid, int flag, void *cb_data)
+static int filter_and_format_one(const char *refname, const char *referent, const struct object_id *oid, int flag, void *cb_data)
{
struct ref_filter_and_format_cbdata *ref_cbdata = cb_data;
struct ref_array_item *ref;
struct strbuf output = STRBUF_INIT, err = STRBUF_INIT;
- ref = apply_ref_filter(refname, oid, flag, ref_cbdata->filter);
+ ref = apply_ref_filter(refname, referent, oid, flag, ref_cbdata->filter);
if (!ref)
return 0;
diff --git a/reflog.c b/reflog.c
index eeccd5fab4..875ac1aa66 100644
--- a/reflog.c
+++ b/reflog.c
@@ -300,6 +300,7 @@ int should_expire_reflog_ent_verbose(struct object_id *ooid,
}
static int push_tip_to_list(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flags, void *cb_data)
{
diff --git a/refs.c b/refs.c
index e082fc59b0..57ffd60be0 100644
--- a/refs.c
+++ b/refs.c
@@ -2,6 +2,8 @@
* The backend-independent part of the reference module.
*/
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "advice.h"
#include "config.h"
@@ -316,6 +318,11 @@ int check_refname_format(const char *refname, int flags)
return check_or_sanitize_refname(refname, flags, NULL);
}
+int refs_fsck(struct ref_store *refs, struct fsck_options *o)
+{
+ return refs->be->fsck(refs, o);
+}
+
void sanitize_refname_component(const char *refname, struct strbuf *out)
{
if (check_or_sanitize_refname(refname, REFNAME_ALLOW_ONELEVEL, out))
@@ -412,7 +419,7 @@ int refs_ref_exists(struct ref_store *refs, const char *refname)
NULL, NULL);
}
-static int for_each_filter_refs(const char *refname,
+static int for_each_filter_refs(const char *refname, const char *referent,
const struct object_id *oid,
int flags, void *data)
{
@@ -422,7 +429,7 @@ static int for_each_filter_refs(const char *refname,
return 0;
if (filter->prefix)
skip_prefix(refname, filter->prefix, &refname);
- return filter->fn(refname, oid, flags, filter->cb_data);
+ return filter->fn(refname, referent, oid, flags, filter->cb_data);
}
struct warn_if_dangling_data {
@@ -433,7 +440,7 @@ struct warn_if_dangling_data {
const char *msg_fmt;
};
-static int warn_if_dangling_symref(const char *refname,
+static int warn_if_dangling_symref(const char *refname, const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flags, void *cb_data)
{
@@ -504,7 +511,7 @@ int refs_head_ref_namespaced(struct ref_store *refs, each_ref_fn fn, void *cb_da
strbuf_addf(&buf, "%sHEAD", get_git_namespace());
if (!refs_read_ref_full(refs, buf.buf, RESOLVE_REF_READING, &oid, &flag))
- ret = fn(buf.buf, &oid, flag, cb_data);
+ ret = fn(buf.buf, NULL, &oid, flag, cb_data);
strbuf_release(&buf);
return ret;
@@ -1545,7 +1552,7 @@ int refs_head_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
if (refs_resolve_ref_unsafe(refs, "HEAD", RESOLVE_REF_READING,
&oid, &flag))
- return fn("HEAD", &oid, flag, cb_data);
+ return fn("HEAD", NULL, &oid, flag, cb_data);
return 0;
}
@@ -2009,7 +2016,7 @@ struct ref_store *repo_get_submodule_ref_store(struct repository *repo,
free(subrepo);
goto done;
}
- refs = ref_store_init(subrepo, repo->ref_storage_format,
+ refs = ref_store_init(subrepo, subrepo->ref_storage_format,
submodule_sb.buf,
REF_STORE_READ | REF_STORE_ODB);
register_ref_store_map(&repo->submodule_ref_stores, "submodule",
@@ -2132,7 +2139,7 @@ static int run_transaction_hook(struct ref_transaction *transaction,
const char *hook;
int ret = 0, i;
- hook = find_hook("reference-transaction");
+ hook = find_hook(transaction->ref_store->repo, "reference-transaction");
if (!hook)
return ret;
@@ -2385,7 +2392,7 @@ struct do_for_each_reflog_help {
void *cb_data;
};
-static int do_for_each_reflog_helper(const char *refname,
+static int do_for_each_reflog_helper(const char *refname, const char *referent,
const struct object_id *oid UNUSED,
int flags,
void *cb_data)
@@ -2591,7 +2598,7 @@ struct migration_data {
struct strbuf *errbuf;
};
-static int migrate_one_ref(const char *refname, const struct object_id *oid,
+static int migrate_one_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flags, void *cb_data)
{
struct migration_data *data = cb_data;
diff --git a/refs.h b/refs.h
index 9fbd2cdb2c..f8b919a138 100644
--- a/refs.h
+++ b/refs.h
@@ -4,6 +4,7 @@
#include "commit.h"
#include "repository.h"
+struct fsck_options;
struct object_id;
struct ref_store;
struct strbuf;
@@ -298,7 +299,7 @@ struct ref_transaction;
* arguments is only guaranteed to be valid for the duration of a
* single callback invocation.
*/
-typedef int each_ref_fn(const char *refname,
+typedef int each_ref_fn(const char *refname, const char *referent,
const struct object_id *oid, int flags, void *cb_data);
/*
@@ -542,6 +543,13 @@ int refs_for_each_reflog(struct ref_store *refs, each_reflog_fn fn, void *cb_dat
int check_refname_format(const char *refname, int flags);
/*
+ * Check the reference database for consistency. Return 0 if refs and
+ * reflogs are consistent, and non-zero otherwise. The errors will be
+ * written to stderr.
+ */
+int refs_fsck(struct ref_store *refs, struct fsck_options *o);
+
+/*
* Apply the rules from check_refname_format, but mutate the result until it
* is acceptable, and place the result in "out".
*/
diff --git a/refs/debug.c b/refs/debug.c
index 547d9245b9..45e2e784a0 100644
--- a/refs/debug.c
+++ b/refs/debug.c
@@ -419,6 +419,15 @@ static int debug_reflog_expire(struct ref_store *ref_store, const char *refname,
return res;
}
+static int debug_fsck(struct ref_store *ref_store,
+ struct fsck_options *o)
+{
+ struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
+ int res = drefs->refs->be->fsck(drefs->refs, o);
+ trace_printf_key(&trace_refs, "fsck: %d\n", res);
+ return res;
+}
+
struct ref_storage_be refs_be_debug = {
.name = "debug",
.init = NULL,
@@ -451,4 +460,6 @@ struct ref_storage_be refs_be_debug = {
.create_reflog = debug_create_reflog,
.delete_reflog = debug_delete_reflog,
.reflog_expire = debug_reflog_expire,
+
+ .fsck = debug_fsck,
};
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 6380dff443..8d6ec9458d 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -4,6 +4,7 @@
#include "../gettext.h"
#include "../hash.h"
#include "../hex.h"
+#include "../fsck.h"
#include "../refs.h"
#include "refs-internal.h"
#include "ref-cache.h"
@@ -244,9 +245,12 @@ static void loose_fill_ref_dir_regular_file(struct files_ref_store *refs,
{
struct object_id oid;
int flag;
+ const char *referent = refs_resolve_ref_unsafe(&refs->base,
+ refname,
+ RESOLVE_REF_READING,
+ &oid, &flag);
- if (!refs_resolve_ref_unsafe(&refs->base, refname, RESOLVE_REF_READING,
- &oid, &flag)) {
+ if (!referent) {
oidclr(&oid, refs->base.repo->hash_algo);
flag |= REF_ISBROKEN;
} else if (is_null_oid(&oid)) {
@@ -267,7 +271,11 @@ static void loose_fill_ref_dir_regular_file(struct files_ref_store *refs,
oidclr(&oid, refs->base.repo->hash_algo);
flag |= REF_BAD_NAME | REF_ISBROKEN;
}
- add_entry_to_dir(dir, create_ref_entry(refname, &oid, flag));
+
+ if (!(flag & REF_ISSYMREF))
+ referent = NULL;
+
+ add_entry_to_dir(dir, create_ref_entry(refname, referent, &oid, flag));
}
/*
@@ -887,6 +895,8 @@ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)
iter->base.refname = iter->iter0->refname;
iter->base.oid = iter->iter0->oid;
iter->base.flags = iter->iter0->flags;
+ iter->base.referent = iter->iter0->referent;
+
return ITER_OK;
}
@@ -3037,7 +3047,7 @@ static int files_transaction_abort(struct ref_store *ref_store,
return 0;
}
-static int ref_present(const char *refname,
+static int ref_present(const char *refname, const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flags UNUSED,
void *cb_data)
@@ -3410,6 +3420,116 @@ static int files_ref_store_remove_on_disk(struct ref_store *ref_store,
return ret;
}
+/*
+ * For refs and reflogs, they share a unified interface when scanning
+ * the whole directory. This function is used as the callback for each
+ * regular file or symlink in the directory.
+ */
+typedef int (*files_fsck_refs_fn)(struct ref_store *ref_store,
+ struct fsck_options *o,
+ const char *refs_check_dir,
+ struct dir_iterator *iter);
+
+static int files_fsck_refs_name(struct ref_store *ref_store UNUSED,
+ struct fsck_options *o,
+ const char *refs_check_dir,
+ struct dir_iterator *iter)
+{
+ struct strbuf sb = STRBUF_INIT;
+ int ret = 0;
+
+ /*
+ * Ignore the files ending with ".lock" as they may be lock files
+ * However, do not allow bare ".lock" files.
+ */
+ if (iter->basename[0] != '.' && ends_with(iter->basename, ".lock"))
+ goto cleanup;
+
+ if (check_refname_format(iter->basename, REFNAME_ALLOW_ONELEVEL)) {
+ struct fsck_ref_report report = { .path = NULL };
+
+ strbuf_addf(&sb, "%s/%s", refs_check_dir, iter->relative_path);
+ report.path = sb.buf;
+ ret = fsck_report_ref(o, &report,
+ FSCK_MSG_BAD_REF_NAME,
+ "invalid refname format");
+ }
+
+cleanup:
+ strbuf_release(&sb);
+ return ret;
+}
+
+static int files_fsck_refs_dir(struct ref_store *ref_store,
+ struct fsck_options *o,
+ const char *refs_check_dir,
+ files_fsck_refs_fn *fsck_refs_fn)
+{
+ struct strbuf sb = STRBUF_INIT;
+ struct dir_iterator *iter;
+ int iter_status;
+ int ret = 0;
+
+ strbuf_addf(&sb, "%s/%s", ref_store->gitdir, refs_check_dir);
+
+ iter = dir_iterator_begin(sb.buf, 0);
+ if (!iter) {
+ ret = error_errno(_("cannot open directory %s"), sb.buf);
+ goto out;
+ }
+
+ while ((iter_status = dir_iterator_advance(iter)) == ITER_OK) {
+ if (S_ISDIR(iter->st.st_mode)) {
+ continue;
+ } else if (S_ISREG(iter->st.st_mode) ||
+ S_ISLNK(iter->st.st_mode)) {
+ if (o->verbose)
+ fprintf_ln(stderr, "Checking %s/%s",
+ refs_check_dir, iter->relative_path);
+ for (size_t i = 0; fsck_refs_fn[i]; i++) {
+ if (fsck_refs_fn[i](ref_store, o, refs_check_dir, iter))
+ ret = -1;
+ }
+ } else {
+ struct fsck_ref_report report = { .path = iter->basename };
+ if (fsck_report_ref(o, &report,
+ FSCK_MSG_BAD_REF_FILETYPE,
+ "unexpected file type"))
+ ret = -1;
+ }
+ }
+
+ if (iter_status != ITER_DONE)
+ ret = error(_("failed to iterate over '%s'"), sb.buf);
+
+out:
+ strbuf_release(&sb);
+ return ret;
+}
+
+static int files_fsck_refs(struct ref_store *ref_store,
+ struct fsck_options *o)
+{
+ files_fsck_refs_fn fsck_refs_fn[]= {
+ files_fsck_refs_name,
+ NULL,
+ };
+
+ if (o->verbose)
+ fprintf_ln(stderr, _("Checking references consistency"));
+ return files_fsck_refs_dir(ref_store, o, "refs", fsck_refs_fn);
+}
+
+static int files_fsck(struct ref_store *ref_store,
+ struct fsck_options *o)
+{
+ struct files_ref_store *refs =
+ files_downcast(ref_store, REF_STORE_READ, "fsck");
+
+ return files_fsck_refs(ref_store, o) |
+ refs->packed_ref_store->be->fsck(refs->packed_ref_store, o);
+}
+
struct ref_storage_be refs_be_files = {
.name = "files",
.init = files_ref_store_init,
@@ -3436,5 +3556,7 @@ struct ref_storage_be refs_be_files = {
.reflog_exists = files_reflog_exists,
.create_reflog = files_create_reflog,
.delete_reflog = files_delete_reflog,
- .reflog_expire = files_reflog_expire
+ .reflog_expire = files_reflog_expire,
+
+ .fsck = files_fsck,
};
diff --git a/refs/iterator.c b/refs/iterator.c
index d355ebf0d5..8e999d81fc 100644
--- a/refs/iterator.c
+++ b/refs/iterator.c
@@ -29,6 +29,7 @@ void base_ref_iterator_init(struct ref_iterator *iter,
{
iter->vtable = vtable;
iter->refname = NULL;
+ iter->referent = NULL;
iter->oid = NULL;
iter->flags = 0;
}
@@ -199,6 +200,7 @@ static int merge_ref_iterator_advance(struct ref_iterator *ref_iterator)
}
if (selection & ITER_YIELD_CURRENT) {
+ iter->base.referent = (*iter->current)->referent;
iter->base.refname = (*iter->current)->refname;
iter->base.oid = (*iter->current)->oid;
iter->base.flags = (*iter->current)->flags;
@@ -448,7 +450,7 @@ int do_for_each_ref_iterator(struct ref_iterator *iter,
current_ref_iter = iter;
while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
- retval = fn(iter->refname, iter->oid, iter->flags, cb_data);
+ retval = fn(iter->refname, iter->referent, iter->oid, iter->flags, cb_data);
if (retval) {
/*
* If ref_iterator_abort() returns ITER_ERROR,
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index 89976aa359..3ab7e99a88 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "../git-compat-util.h"
#include "../config.h"
#include "../dir.h"
@@ -1733,6 +1735,12 @@ static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_s
return empty_ref_iterator_begin();
}
+static int packed_fsck(struct ref_store *ref_store,
+ struct fsck_options *o)
+{
+ return 0;
+}
+
struct ref_storage_be refs_be_packed = {
.name = "packed",
.init = packed_ref_store_init,
@@ -1760,4 +1768,6 @@ struct ref_storage_be refs_be_packed = {
.create_reflog = NULL,
.delete_reflog = NULL,
.reflog_expire = NULL,
+
+ .fsck = packed_fsck,
};
diff --git a/refs/ref-cache.c b/refs/ref-cache.c
index 4ce519bbc8..35bae7e05d 100644
--- a/refs/ref-cache.c
+++ b/refs/ref-cache.c
@@ -34,6 +34,7 @@ struct ref_dir *get_ref_dir(struct ref_entry *entry)
}
struct ref_entry *create_ref_entry(const char *refname,
+ const char *referent,
const struct object_id *oid, int flag)
{
struct ref_entry *ref;
@@ -41,6 +42,8 @@ struct ref_entry *create_ref_entry(const char *refname,
FLEX_ALLOC_STR(ref, name, refname);
oidcpy(&ref->u.value.oid, oid);
ref->flag = flag;
+ ref->u.value.referent = xstrdup_or_null(referent);
+
return ref;
}
@@ -66,6 +69,7 @@ static void free_ref_entry(struct ref_entry *entry)
*/
clear_ref_dir(&entry->u.subdir);
}
+ free(entry->u.value.referent);
free(entry);
}
@@ -431,6 +435,7 @@ static int cache_ref_iterator_advance(struct ref_iterator *ref_iterator)
level->index = -1;
} else {
iter->base.refname = entry->name;
+ iter->base.referent = entry->u.value.referent;
iter->base.oid = &entry->u.value.oid;
iter->base.flags = entry->flag;
return ITER_OK;
diff --git a/refs/ref-cache.h b/refs/ref-cache.h
index 31ebe24f6c..5f04e518c3 100644
--- a/refs/ref-cache.h
+++ b/refs/ref-cache.h
@@ -42,6 +42,7 @@ struct ref_value {
* referred to by the last reference in the symlink chain.
*/
struct object_id oid;
+ char *referent;
};
/*
@@ -173,6 +174,7 @@ struct ref_entry *create_dir_entry(struct ref_cache *cache,
const char *dirname, size_t len);
struct ref_entry *create_ref_entry(const char *refname,
+ const char *referent,
const struct object_id *oid, int flag);
/*
diff --git a/refs/refs-internal.h b/refs/refs-internal.h
index 309b382284..2313c830d8 100644
--- a/refs/refs-internal.h
+++ b/refs/refs-internal.h
@@ -4,6 +4,7 @@
#include "refs.h"
#include "iterator.h"
+struct fsck_options;
struct ref_transaction;
/*
@@ -299,6 +300,7 @@ enum do_for_each_ref_flags {
struct ref_iterator {
struct ref_iterator_vtable *vtable;
const char *refname;
+ const char *referent;
const struct object_id *oid;
unsigned int flags;
};
@@ -650,6 +652,9 @@ typedef int read_raw_ref_fn(struct ref_store *ref_store, const char *refname,
typedef int read_symbolic_ref_fn(struct ref_store *ref_store, const char *refname,
struct strbuf *referent);
+typedef int fsck_fn(struct ref_store *ref_store,
+ struct fsck_options *o);
+
struct ref_storage_be {
const char *name;
ref_store_init_fn *init;
@@ -677,6 +682,8 @@ struct ref_storage_be {
create_reflog_fn *create_reflog;
delete_reflog_fn *delete_reflog;
reflog_expire_fn *reflog_expire;
+
+ fsck_fn *fsck;
};
extern struct ref_storage_be refs_be_files;
diff --git a/refs/reftable-backend.c b/refs/reftable-backend.c
index bf4446afd3..ef0f9b0d42 100644
--- a/refs/reftable-backend.c
+++ b/refs/reftable-backend.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "../git-compat-util.h"
#include "../abspath.h"
#include "../chdir-notify.h"
@@ -454,6 +456,7 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
struct reftable_ref_iterator *iter =
(struct reftable_ref_iterator *)ref_iterator;
struct reftable_ref_store *refs = iter->refs;
+ const char *referent = NULL;
while (!iter->err) {
int flags = 0;
@@ -493,8 +496,11 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
refs->base.repo->hash_algo);
break;
case REFTABLE_REF_SYMREF:
- if (!refs_resolve_ref_unsafe(&iter->refs->base, iter->ref.refname,
- RESOLVE_REF_READING, &iter->oid, &flags))
+ referent = refs_resolve_ref_unsafe(&iter->refs->base,
+ iter->ref.refname,
+ RESOLVE_REF_READING,
+ &iter->oid, &flags);
+ if (!referent)
oidclr(&iter->oid, refs->base.repo->hash_algo);
break;
default:
@@ -522,6 +528,7 @@ static int reftable_ref_iterator_advance(struct ref_iterator *ref_iterator)
continue;
iter->base.refname = iter->ref.refname;
+ iter->base.referent = referent;
iter->base.oid = &iter->oid;
iter->base.flags = flags;
@@ -2304,6 +2311,12 @@ done:
return ret;
}
+static int reftable_be_fsck(struct ref_store *ref_store,
+ struct fsck_options *o)
+{
+ return 0;
+}
+
struct ref_storage_be refs_be_reftable = {
.name = "reftable",
.init = reftable_be_init,
@@ -2331,4 +2344,6 @@ struct ref_storage_be refs_be_reftable = {
.create_reflog = reftable_be_create_reflog,
.delete_reflog = reftable_be_delete_reflog,
.reflog_expire = reftable_be_reflog_expire,
+
+ .fsck = reftable_be_fsck,
};
diff --git a/reftable/reftable-tests.h b/reftable/reftable-tests.h
index 4b666810af..f25034fca8 100644
--- a/reftable/reftable-tests.h
+++ b/reftable/reftable-tests.h
@@ -12,7 +12,6 @@ https://developers.google.com/open-source/licenses/bsd
int basics_test_main(int argc, const char **argv);
int block_test_main(int argc, const char **argv);
int record_test_main(int argc, const char **argv);
-int readwrite_test_main(int argc, const char **argv);
int stack_test_main(int argc, const char **argv);
int reftable_dump_main(int argc, char *const *argv);
diff --git a/reftable/stack.c b/reftable/stack.c
index 737591125e..2071e428a8 100644
--- a/reftable/stack.c
+++ b/reftable/stack.c
@@ -567,7 +567,7 @@ static void format_name(struct strbuf *dest, uint64_t min, uint64_t max)
}
struct reftable_addition {
- struct tempfile *lock_file;
+ struct lock_file tables_list_lock;
struct reftable_stack *stack;
char **new_tables;
@@ -581,13 +581,13 @@ static int reftable_stack_init_addition(struct reftable_addition *add,
struct reftable_stack *st)
{
struct strbuf lock_file_name = STRBUF_INIT;
- int err = 0;
- add->stack = st;
+ int err;
- strbuf_addf(&lock_file_name, "%s.lock", st->list_file);
+ add->stack = st;
- add->lock_file = create_tempfile(lock_file_name.buf);
- if (!add->lock_file) {
+ err = hold_lock_file_for_update(&add->tables_list_lock, st->list_file,
+ LOCK_NO_DEREF);
+ if (err < 0) {
if (errno == EEXIST) {
err = REFTABLE_LOCK_ERROR;
} else {
@@ -596,7 +596,8 @@ static int reftable_stack_init_addition(struct reftable_addition *add,
goto done;
}
if (st->opts.default_permissions) {
- if (chmod(add->lock_file->filename.buf, st->opts.default_permissions) < 0) {
+ if (chmod(get_lock_file_path(&add->tables_list_lock),
+ st->opts.default_permissions) < 0) {
err = REFTABLE_IO_ERROR;
goto done;
}
@@ -635,7 +636,7 @@ static void reftable_addition_close(struct reftable_addition *add)
add->new_tables_len = 0;
add->new_tables_cap = 0;
- delete_tempfile(&add->lock_file);
+ rollback_lock_file(&add->tables_list_lock);
strbuf_release(&nm);
}
@@ -651,7 +652,7 @@ void reftable_addition_destroy(struct reftable_addition *add)
int reftable_addition_commit(struct reftable_addition *add)
{
struct strbuf table_list = STRBUF_INIT;
- int lock_file_fd = get_tempfile_fd(add->lock_file);
+ int lock_file_fd = get_lock_file_fd(&add->tables_list_lock);
int err = 0;
size_t i;
@@ -674,10 +675,13 @@ int reftable_addition_commit(struct reftable_addition *add)
goto done;
}
- fsync_component_or_die(FSYNC_COMPONENT_REFERENCE, lock_file_fd,
- get_tempfile_path(add->lock_file));
+ err = fsync_component(FSYNC_COMPONENT_REFERENCE, lock_file_fd);
+ if (err < 0) {
+ err = REFTABLE_IO_ERROR;
+ goto done;
+ }
- err = rename_tempfile(&add->lock_file, add->stack->list_file);
+ err = commit_lock_file(&add->tables_list_lock);
if (err < 0) {
err = REFTABLE_IO_ERROR;
goto done;
@@ -995,6 +999,15 @@ done:
return err;
}
+enum stack_compact_range_flags {
+ /*
+ * Perform a best-effort compaction. That is, even if we cannot lock
+ * all tables in the specified range, we will try to compact the
+ * remaining slice.
+ */
+ STACK_COMPACT_RANGE_BEST_EFFORT = (1 << 0),
+};
+
/*
* Compact all tables in the range `[first, last)` into a single new table.
*
@@ -1006,7 +1019,8 @@ done:
*/
static int stack_compact_range(struct reftable_stack *st,
size_t first, size_t last,
- struct reftable_log_expiry_config *expiry)
+ struct reftable_log_expiry_config *expiry,
+ unsigned int flags)
{
struct strbuf tables_list_buf = STRBUF_INIT;
struct strbuf new_table_name = STRBUF_INIT;
@@ -1016,7 +1030,9 @@ static int stack_compact_range(struct reftable_stack *st,
struct lock_file *table_locks = NULL;
struct tempfile *new_table = NULL;
int is_empty_table = 0, err = 0;
- size_t i;
+ size_t first_to_replace, last_to_replace;
+ size_t i, nlocks = 0;
+ char **names = NULL;
if (first > last || (!expiry && first == last)) {
err = 0;
@@ -1046,19 +1062,47 @@ static int stack_compact_range(struct reftable_stack *st,
/*
* Lock all tables in the user-provided range. This is the slice of our
* stack which we'll compact.
+ *
+ * Note that we lock tables in reverse order from last to first. The
+ * intent behind this is to allow a newer process to perform best
+ * effort compaction of tables that it has added in the case where an
+ * older process is still busy compacting tables which are preexisting
+ * from the point of view of the newer process.
*/
REFTABLE_CALLOC_ARRAY(table_locks, last - first + 1);
- for (i = first; i <= last; i++) {
- stack_filename(&table_name, st, reader_name(st->readers[i]));
+ for (i = last + 1; i > first; i--) {
+ stack_filename(&table_name, st, reader_name(st->readers[i - 1]));
- err = hold_lock_file_for_update(&table_locks[i - first],
+ err = hold_lock_file_for_update(&table_locks[nlocks],
table_name.buf, LOCK_NO_DEREF);
if (err < 0) {
- if (errno == EEXIST)
+ /*
+ * When the table is locked already we may do a
+ * best-effort compaction and compact only the tables
+ * that we have managed to lock so far. This of course
+ * requires that we have been able to lock at least two
+ * tables, otherwise there would be nothing to compact.
+ * In that case, we return a lock error to our caller.
+ */
+ if (errno == EEXIST && last - (i - 1) >= 2 &&
+ flags & STACK_COMPACT_RANGE_BEST_EFFORT) {
+ err = 0;
+ /*
+ * The subtraction is to offset the index, the
+ * addition is to only compact up to the table
+ * of the preceding iteration. They obviously
+ * cancel each other out, but that may be
+ * non-obvious when it was omitted.
+ */
+ first = (i - 1) + 1;
+ break;
+ } else if (errno == EEXIST) {
err = REFTABLE_LOCK_ERROR;
- else
+ goto done;
+ } else {
err = REFTABLE_IO_ERROR;
- goto done;
+ goto done;
+ }
}
/*
@@ -1066,7 +1110,7 @@ static int stack_compact_range(struct reftable_stack *st,
* run into file descriptor exhaustion when we compress a lot
* of tables.
*/
- err = close_lock_file_gently(&table_locks[i - first]);
+ err = close_lock_file_gently(&table_locks[nlocks++]);
if (err < 0) {
err = REFTABLE_IO_ERROR;
goto done;
@@ -1120,6 +1164,100 @@ static int stack_compact_range(struct reftable_stack *st,
}
/*
+ * As we have unlocked the stack while compacting our slice of tables
+ * it may have happened that a concurrently running process has updated
+ * the stack while we were compacting. In that case, we need to check
+ * whether the tables that we have just compacted still exist in the
+ * stack in the exact same order as we have compacted them.
+ *
+ * If they do exist, then it is fine to continue and replace those
+ * tables with our compacted version. If they don't, then we need to
+ * abort.
+ */
+ err = stack_uptodate(st);
+ if (err < 0)
+ goto done;
+ if (err > 0) {
+ ssize_t new_offset = -1;
+ int fd;
+
+ fd = open(st->list_file, O_RDONLY);
+ if (fd < 0) {
+ err = REFTABLE_IO_ERROR;
+ goto done;
+ }
+
+ err = fd_read_lines(fd, &names);
+ close(fd);
+ if (err < 0)
+ goto done;
+
+ /*
+ * Search for the offset of the first table that we have
+ * compacted in the updated "tables.list" file.
+ */
+ for (size_t i = 0; names[i]; i++) {
+ if (strcmp(names[i], st->readers[first]->name))
+ continue;
+
+ /*
+ * We have found the first entry. Verify that all the
+ * subsequent tables we have compacted still exist in
+ * the modified stack in the exact same order as we
+ * have compacted them.
+ */
+ for (size_t j = 1; j < last - first + 1; j++) {
+ const char *old = first + j < st->merged->stack_len ?
+ st->readers[first + j]->name : NULL;
+ const char *new = names[i + j];
+
+ /*
+ * If some entries are missing or in case the tables
+ * have changed then we need to bail out. Again, this
+ * shouldn't ever happen because we have locked the
+ * tables we are compacting.
+ */
+ if (!old || !new || strcmp(old, new)) {
+ err = REFTABLE_OUTDATED_ERROR;
+ goto done;
+ }
+ }
+
+ new_offset = i;
+ break;
+ }
+
+ /*
+ * In case we didn't find our compacted tables in the stack we
+ * need to bail out. In theory, this should have never happened
+ * because we locked the tables we are compacting.
+ */
+ if (new_offset < 0) {
+ err = REFTABLE_OUTDATED_ERROR;
+ goto done;
+ }
+
+ /*
+ * We have found the new range that we want to replace, so
+ * let's update the range of tables that we want to replace.
+ */
+ first_to_replace = new_offset;
+ last_to_replace = last + (new_offset - first);
+ } else {
+ /*
+ * `fd_read_lines()` uses a `NULL` sentinel to indicate that
+ * the array is at its end. As we use `free_names()` to free
+ * the array, we need to include this sentinel value here and
+ * thus have to allocate `stack_len + 1` many entries.
+ */
+ REFTABLE_CALLOC_ARRAY(names, st->merged->stack_len + 1);
+ for (size_t i = 0; i < st->merged->stack_len; i++)
+ names[i] = xstrdup(st->readers[i]->name);
+ first_to_replace = first;
+ last_to_replace = last;
+ }
+
+ /*
* If the resulting compacted table is not empty, then we need to move
* it into place now.
*/
@@ -1141,12 +1279,12 @@ static int stack_compact_range(struct reftable_stack *st,
* have just written. In case the compacted table became empty we
* simply skip writing it.
*/
- for (i = 0; i < first; i++)
- strbuf_addf(&tables_list_buf, "%s\n", st->readers[i]->name);
+ for (i = 0; i < first_to_replace; i++)
+ strbuf_addf(&tables_list_buf, "%s\n", names[i]);
if (!is_empty_table)
strbuf_addf(&tables_list_buf, "%s\n", new_table_name.buf);
- for (i = last + 1; i < st->merged->stack_len; i++)
- strbuf_addf(&tables_list_buf, "%s\n", st->readers[i]->name);
+ for (i = last_to_replace + 1; names[i]; i++)
+ strbuf_addf(&tables_list_buf, "%s\n", names[i]);
err = write_in_full(get_lock_file_fd(&tables_list_lock),
tables_list_buf.buf, tables_list_buf.len);
@@ -1183,8 +1321,8 @@ static int stack_compact_range(struct reftable_stack *st,
* Delete the old tables. They may still be in use by concurrent
* readers, so it is expected that unlinking tables may fail.
*/
- for (i = first; i <= last; i++) {
- struct lock_file *table_lock = &table_locks[i - first];
+ for (i = 0; i < nlocks; i++) {
+ struct lock_file *table_lock = &table_locks[i];
char *table_path = get_locked_file_path(table_lock);
unlink(table_path);
free(table_path);
@@ -1192,36 +1330,38 @@ static int stack_compact_range(struct reftable_stack *st,
done:
rollback_lock_file(&tables_list_lock);
- for (i = first; table_locks && i <= last; i++)
- rollback_lock_file(&table_locks[i - first]);
+ for (i = 0; table_locks && i < nlocks; i++)
+ rollback_lock_file(&table_locks[i]);
reftable_free(table_locks);
delete_tempfile(&new_table);
strbuf_release(&new_table_name);
strbuf_release(&new_table_path);
-
strbuf_release(&tables_list_buf);
strbuf_release(&table_name);
- return err;
-}
+ free_names(names);
-int reftable_stack_compact_all(struct reftable_stack *st,
- struct reftable_log_expiry_config *config)
-{
- return stack_compact_range(st, 0, st->merged->stack_len ?
- st->merged->stack_len - 1 : 0, config);
+ return err;
}
static int stack_compact_range_stats(struct reftable_stack *st,
size_t first, size_t last,
- struct reftable_log_expiry_config *config)
+ struct reftable_log_expiry_config *config,
+ unsigned int flags)
{
- int err = stack_compact_range(st, first, last, config);
+ int err = stack_compact_range(st, first, last, config, flags);
if (err == REFTABLE_LOCK_ERROR)
st->stats.failures++;
return err;
}
+int reftable_stack_compact_all(struct reftable_stack *st,
+ struct reftable_log_expiry_config *config)
+{
+ size_t last = st->merged->stack_len ? st->merged->stack_len - 1 : 0;
+ return stack_compact_range_stats(st, 0, last, config, 0);
+}
+
static int segment_size(struct segment *s)
{
return s->end - s->start;
@@ -1305,14 +1445,15 @@ struct segment suggest_compaction_segment(uint64_t *sizes, size_t n,
static uint64_t *stack_table_sizes_for_compaction(struct reftable_stack *st)
{
- uint64_t *sizes =
- reftable_calloc(st->merged->stack_len, sizeof(*sizes));
int version = (st->opts.hash_id == GIT_SHA1_FORMAT_ID) ? 1 : 2;
int overhead = header_size(version) - 1;
- int i = 0;
- for (i = 0; i < st->merged->stack_len; i++) {
+ uint64_t *sizes;
+
+ REFTABLE_CALLOC_ARRAY(sizes, st->merged->stack_len);
+
+ for (size_t i = 0; i < st->merged->stack_len; i++)
sizes[i] = st->readers[i]->size - overhead;
- }
+
return sizes;
}
@@ -1325,7 +1466,7 @@ int reftable_stack_auto_compact(struct reftable_stack *st)
reftable_free(sizes);
if (segment_size(&seg) > 0)
return stack_compact_range_stats(st, seg.start, seg.end - 1,
- NULL);
+ NULL, STACK_COMPACT_RANGE_BEST_EFFORT);
return 0;
}
diff --git a/reftable/stack_test.c b/reftable/stack_test.c
index e3c11e6a6e..8c36590ff0 100644
--- a/reftable/stack_test.c
+++ b/reftable/stack_test.c
@@ -109,6 +109,34 @@ static int write_test_ref(struct reftable_writer *wr, void *arg)
return reftable_writer_add_ref(wr, ref);
}
+static void write_n_ref_tables(struct reftable_stack *st,
+ size_t n)
+{
+ struct strbuf buf = STRBUF_INIT;
+ int disable_auto_compact;
+ int err;
+
+ disable_auto_compact = st->opts.disable_auto_compact;
+ st->opts.disable_auto_compact = 1;
+
+ for (size_t i = 0; i < n; i++) {
+ struct reftable_ref_record ref = {
+ .update_index = reftable_stack_next_update_index(st),
+ .value_type = REFTABLE_REF_VAL1,
+ };
+
+ strbuf_addf(&buf, "refs/heads/branch-%04u", (unsigned) i);
+ ref.refname = buf.buf;
+ set_test_hash(ref.value.val1, i);
+
+ err = reftable_stack_add(st, &write_test_ref, &ref);
+ EXPECT_ERR(err);
+ }
+
+ st->opts.disable_auto_compact = disable_auto_compact;
+ strbuf_release(&buf);
+}
+
struct write_log_arg {
struct reftable_log_record *log;
uint64_t update_index;
@@ -863,6 +891,47 @@ static void test_reftable_stack_auto_compaction(void)
clear_dir(dir);
}
+static void test_reftable_stack_auto_compaction_with_locked_tables(void)
+{
+ struct reftable_write_options opts = {
+ .disable_auto_compact = 1,
+ };
+ struct reftable_stack *st = NULL;
+ struct strbuf buf = STRBUF_INIT;
+ char *dir = get_tmp_dir(__LINE__);
+ int err;
+
+ err = reftable_new_stack(&st, dir, &opts);
+ EXPECT_ERR(err);
+
+ write_n_ref_tables(st, 5);
+ EXPECT(st->merged->stack_len == 5);
+
+ /*
+ * Given that all tables we have written should be roughly the same
+ * size, we expect that auto-compaction will want to compact all of the
+ * tables. Locking any of the tables will keep it from doing so.
+ */
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "%s/%s.lock", dir, st->readers[2]->name);
+ write_file_buf(buf.buf, "", 0);
+
+ /*
+ * When parts of the stack are locked, then auto-compaction does a best
+ * effort compaction of those tables which aren't locked. So while this
+ * would in theory compact all tables, due to the preexisting lock we
+ * only compact the newest two tables.
+ */
+ err = reftable_stack_auto_compact(st);
+ EXPECT_ERR(err);
+ EXPECT(st->stats.failures == 0);
+ EXPECT(st->merged->stack_len == 4);
+
+ reftable_stack_destroy(st);
+ strbuf_release(&buf);
+ clear_dir(dir);
+}
+
static void test_reftable_stack_add_performs_auto_compaction(void)
{
struct reftable_write_options opts = { 0 };
@@ -911,30 +980,51 @@ static void test_reftable_stack_add_performs_auto_compaction(void)
clear_dir(dir);
}
+static void test_reftable_stack_compaction_with_locked_tables(void)
+{
+ struct reftable_write_options opts = {
+ .disable_auto_compact = 1,
+ };
+ struct reftable_stack *st = NULL;
+ struct strbuf buf = STRBUF_INIT;
+ char *dir = get_tmp_dir(__LINE__);
+ int err;
+
+ err = reftable_new_stack(&st, dir, &opts);
+ EXPECT_ERR(err);
+
+ write_n_ref_tables(st, 3);
+ EXPECT(st->merged->stack_len == 3);
+
+ /* Lock one of the tables that we're about to compact. */
+ strbuf_reset(&buf);
+ strbuf_addf(&buf, "%s/%s.lock", dir, st->readers[1]->name);
+ write_file_buf(buf.buf, "", 0);
+
+ /*
+ * Compaction is expected to fail given that we were not able to
+ * compact all tables.
+ */
+ err = reftable_stack_compact_all(st, NULL);
+ EXPECT(err == REFTABLE_LOCK_ERROR);
+ EXPECT(st->stats.failures == 1);
+ EXPECT(st->merged->stack_len == 3);
+
+ reftable_stack_destroy(st);
+ strbuf_release(&buf);
+ clear_dir(dir);
+}
+
static void test_reftable_stack_compaction_concurrent(void)
{
struct reftable_write_options opts = { 0 };
struct reftable_stack *st1 = NULL, *st2 = NULL;
char *dir = get_tmp_dir(__LINE__);
- int err, i;
- int N = 3;
+ int err;
err = reftable_new_stack(&st1, dir, &opts);
EXPECT_ERR(err);
-
- for (i = 0; i < N; i++) {
- char name[100];
- struct reftable_ref_record ref = {
- .refname = name,
- .update_index = reftable_stack_next_update_index(st1),
- .value_type = REFTABLE_REF_SYMREF,
- .value.symref = (char *) "master",
- };
- snprintf(name, sizeof(name), "branch%04d", i);
-
- err = reftable_stack_add(st1, &write_test_ref, &ref);
- EXPECT_ERR(err);
- }
+ write_n_ref_tables(st1, 3);
err = reftable_new_stack(&st2, dir, &opts);
EXPECT_ERR(err);
@@ -965,25 +1055,11 @@ static void test_reftable_stack_compaction_concurrent_clean(void)
struct reftable_write_options opts = { 0 };
struct reftable_stack *st1 = NULL, *st2 = NULL, *st3 = NULL;
char *dir = get_tmp_dir(__LINE__);
- int err, i;
- int N = 3;
+ int err;
err = reftable_new_stack(&st1, dir, &opts);
EXPECT_ERR(err);
-
- for (i = 0; i < N; i++) {
- char name[100];
- struct reftable_ref_record ref = {
- .refname = name,
- .update_index = reftable_stack_next_update_index(st1),
- .value_type = REFTABLE_REF_SYMREF,
- .value.symref = (char *) "master",
- };
- snprintf(name, sizeof(name), "branch%04d", i);
-
- err = reftable_stack_add(st1, &write_test_ref, &ref);
- EXPECT_ERR(err);
- }
+ write_n_ref_tables(st1, 3);
err = reftable_new_stack(&st2, dir, &opts);
EXPECT_ERR(err);
@@ -1016,9 +1092,11 @@ int stack_test_main(int argc, const char *argv[])
RUN_TEST(test_reftable_stack_add);
RUN_TEST(test_reftable_stack_add_one);
RUN_TEST(test_reftable_stack_auto_compaction);
+ RUN_TEST(test_reftable_stack_auto_compaction_with_locked_tables);
RUN_TEST(test_reftable_stack_add_performs_auto_compaction);
RUN_TEST(test_reftable_stack_compaction_concurrent);
RUN_TEST(test_reftable_stack_compaction_concurrent_clean);
+ RUN_TEST(test_reftable_stack_compaction_with_locked_tables);
RUN_TEST(test_reftable_stack_hash_id);
RUN_TEST(test_reftable_stack_lock_failure);
RUN_TEST(test_reftable_stack_log_normalize);
diff --git a/remote.c b/remote.c
index f43cf5e7a4..7d5b8f750d 100644
--- a/remote.c
+++ b/remote.c
@@ -499,6 +499,7 @@ static void alias_all_urls(struct remote_state *remote_state)
if (alias)
strvec_replace(&remote_state->remotes[i]->pushurl,
j, alias);
+ free(alias);
}
add_pushurl_aliases = remote_state->remotes[i]->pushurl.nr == 0;
for (j = 0; j < remote_state->remotes[i]->url.nr; j++) {
@@ -512,6 +513,7 @@ static void alias_all_urls(struct remote_state *remote_state)
if (alias)
strvec_replace(&remote_state->remotes[i]->url,
j, alias);
+ free(alias);
}
}
}
@@ -2354,7 +2356,7 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb,
return 1;
}
-static int one_local_ref(const char *refname, const struct object_id *oid,
+static int one_local_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED,
void *cb_data)
{
@@ -2439,7 +2441,7 @@ struct stale_heads_info {
struct refspec *rs;
};
-static int get_stale_heads_cb(const char *refname, const struct object_id *oid,
+static int get_stale_heads_cb(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flags, void *cb_data)
{
struct stale_heads_info *info = cb_data;
diff --git a/replace-object.c b/replace-object.c
index 59252d565e..9a3cdd809a 100644
--- a/replace-object.c
+++ b/replace-object.c
@@ -9,6 +9,7 @@
#include "commit.h"
static int register_replace_ref(const char *refname,
+ const char *referent UNUSED,
const struct object_id *oid,
int flag UNUSED,
void *cb_data)
diff --git a/rerere.c b/rerere.c
index 525ed6cc1e..d01e98bf65 100644
--- a/rerere.c
+++ b/rerere.c
@@ -1208,8 +1208,10 @@ void rerere_gc(struct repository *r, struct string_list *rr)
if (setup_rerere(r, rr, 0) < 0)
return;
- git_config_get_expiry_in_days("gc.rerereresolved", &cutoff_resolve, now);
- git_config_get_expiry_in_days("gc.rerereunresolved", &cutoff_noresolve, now);
+ repo_config_get_expiry_in_days(the_repository, "gc.rerereresolved",
+ &cutoff_resolve, now);
+ repo_config_get_expiry_in_days(the_repository, "gc.rerereunresolved",
+ &cutoff_noresolve, now);
git_config(git_default_config, NULL);
dir = opendir(git_path("rr-cache"));
if (!dir)
diff --git a/reset.c b/reset.c
index 9550dea03d..b22b1be792 100644
--- a/reset.c
+++ b/reset.c
@@ -79,7 +79,7 @@ static int update_refs(const struct reset_head_opts *opts,
reflog_head);
}
if (!ret && run_hook)
- run_hooks_l("post-checkout",
+ run_hooks_l(the_repository, "post-checkout",
oid_to_hex(head ? head : null_oid()),
oid_to_hex(oid), "1", NULL);
strbuf_release(&msg);
diff --git a/revision.c b/revision.c
index 1c0192f522..ac94f8d429 100644
--- a/revision.c
+++ b/revision.c
@@ -1648,7 +1648,7 @@ struct all_refs_cb {
struct worktree *wt;
};
-static int handle_one_ref(const char *path, const struct object_id *oid,
+static int handle_one_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED,
void *cb_data)
{
@@ -1872,7 +1872,7 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)
continue; /* current index already taken care of */
if (read_index_from(&istate,
- worktree_git_path(wt, "index"),
+ worktree_git_path(the_repository, wt, "index"),
get_worktree_git_dir(wt)) > 0)
do_add_index_objects_to_pending(revs, &istate, flags);
discard_index(&istate);
diff --git a/sequencer.c b/sequencer.c
index 0291920f0b..e592df0f51 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -303,6 +303,7 @@ static int git_sequencer_config(const char *k, const char *v,
}
if (!strcmp(k, "commit.gpgsign")) {
+ free(opts->gpg_sign);
opts->gpg_sign = git_config_bool(k, v) ? xstrdup("") : NULL;
return 0;
}
@@ -1316,7 +1317,7 @@ static int run_rewrite_hook(const struct object_id *oldoid,
struct child_process proc = CHILD_PROCESS_INIT;
int code;
struct strbuf sb = STRBUF_INIT;
- const char *hook_path = find_hook("post-rewrite");
+ const char *hook_path = find_hook(the_repository, "post-rewrite");
if (!hook_path)
return 0;
@@ -1614,7 +1615,7 @@ static int try_to_commit(struct repository *r,
}
}
- if (hook_exists("prepare-commit-msg")) {
+ if (hook_exists(r, "prepare-commit-msg")) {
res = run_prepare_commit_msg_hook(r, msg, hook_commit);
if (res)
goto out;
@@ -5149,7 +5150,7 @@ cleanup_head_ref:
hook_opt.path_to_stdin = rebase_path_rewritten_list();
strvec_push(&hook_opt.args, "rebase");
- run_hooks_opt("post-rewrite", &hook_opt);
+ run_hooks_opt(r, "post-rewrite", &hook_opt);
}
apply_autostash(rebase_path_autostash());
@@ -5489,8 +5490,10 @@ int sequencer_pick_revisions(struct repository *r,
int i, res;
assert(opts->revs);
- if (read_and_refresh_cache(r, opts))
- return -1;
+ if (read_and_refresh_cache(r, opts)) {
+ res = -1;
+ goto out;
+ }
for (i = 0; i < opts->revs->pending.nr; i++) {
struct object_id oid;
@@ -5505,11 +5508,14 @@ int sequencer_pick_revisions(struct repository *r,
enum object_type type = oid_object_info(r,
&oid,
NULL);
- return error(_("%s: can't cherry-pick a %s"),
- name, type_name(type));
+ res = error(_("%s: can't cherry-pick a %s"),
+ name, type_name(type));
+ goto out;
}
- } else
- return error(_("%s: bad revision"), name);
+ } else {
+ res = error(_("%s: bad revision"), name);
+ goto out;
+ }
}
/*
@@ -5524,14 +5530,23 @@ int sequencer_pick_revisions(struct repository *r,
opts->revs->no_walk &&
!opts->revs->cmdline.rev->flags) {
struct commit *cmit;
- if (prepare_revision_walk(opts->revs))
- return error(_("revision walk setup failed"));
+
+ if (prepare_revision_walk(opts->revs)) {
+ res = error(_("revision walk setup failed"));
+ goto out;
+ }
+
cmit = get_revision(opts->revs);
- if (!cmit)
- return error(_("empty commit set passed"));
+ if (!cmit) {
+ res = error(_("empty commit set passed"));
+ goto out;
+ }
+
if (get_revision(opts->revs))
BUG("unexpected extra commit from walk");
- return single_pick(r, cmit, opts);
+
+ res = single_pick(r, cmit, opts);
+ goto out;
}
/*
@@ -5541,16 +5556,30 @@ int sequencer_pick_revisions(struct repository *r,
*/
if (walk_revs_populate_todo(&todo_list, opts) ||
- create_seq_dir(r) < 0)
- return -1;
- if (repo_get_oid(r, "HEAD", &oid) && (opts->action == REPLAY_REVERT))
- return error(_("can't revert as initial commit"));
- if (save_head(oid_to_hex(&oid)))
- return -1;
- if (save_opts(opts))
- return -1;
+ create_seq_dir(r) < 0) {
+ res = -1;
+ goto out;
+ }
+
+ if (repo_get_oid(r, "HEAD", &oid) && (opts->action == REPLAY_REVERT)) {
+ res = error(_("can't revert as initial commit"));
+ goto out;
+ }
+
+ if (save_head(oid_to_hex(&oid))) {
+ res = -1;
+ goto out;
+ }
+
+ if (save_opts(opts)) {
+ res = -1;
+ goto out;
+ }
+
update_abort_safety_file();
res = pick_commits(r, &todo_list, opts);
+
+out:
todo_list_release(&todo_list);
return res;
}
diff --git a/server-info.c b/server-info.c
index f61296a60d..1508fa6f82 100644
--- a/server-info.c
+++ b/server-info.c
@@ -147,7 +147,7 @@ out:
return ret;
}
-static int add_info_ref(const char *path, const struct object_id *oid,
+static int add_info_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED,
void *cb_data)
{
diff --git a/setup.c b/setup.c
index dd2251f655..2e11542a1f 100644
--- a/setup.c
+++ b/setup.c
@@ -1215,7 +1215,7 @@ static int canonicalize_ceiling_entry(struct string_list_item *item,
}
struct safe_directory_data {
- const char *path;
+ char *path;
int is_safe;
};
@@ -1235,17 +1235,45 @@ static int safe_directory_cb(const char *key, const char *value,
char *allowed = NULL;
if (!git_config_pathname(&allowed, key, value)) {
- const char *check = allowed ? allowed : value;
- if (ends_with(check, "/*")) {
- size_t len = strlen(check);
- if (!fspathncmp(check, data->path, len - 1))
+ char *normalized = NULL;
+
+ /*
+ * Setting safe.directory to a non-absolute path
+ * makes little sense---it won't be relative to
+ * the configuration file the item is defined in.
+ * Except for ".", which means "if we are at the top
+ * level of a repository, then it is OK", which is
+ * slightly tighter than "*" that allows discovery.
+ */
+ if (!is_absolute_path(allowed) && strcmp(allowed, ".")) {
+ warning(_("safe.directory '%s' not absolute"),
+ allowed);
+ goto next;
+ }
+
+ /*
+ * A .gitconfig in $HOME may be shared across
+ * different machines and safe.directory entries
+ * may or may not exist as paths on all of these
+ * machines. In other words, it is not a warning
+ * worthy event when there is no such path on this
+ * machine---the entry may be useful elsewhere.
+ */
+ normalized = real_pathdup(allowed, 0);
+ if (!normalized)
+ goto next;
+
+ if (ends_with(normalized, "/*")) {
+ size_t len = strlen(normalized);
+ if (!fspathncmp(normalized, data->path, len - 1))
data->is_safe = 1;
- } else if (!fspathcmp(data->path, check)) {
+ } else if (!fspathcmp(data->path, normalized)) {
data->is_safe = 1;
}
- }
- if (allowed != value)
+ next:
+ free(normalized);
free(allowed);
+ }
}
return 0;
@@ -1263,9 +1291,7 @@ static int ensure_valid_ownership(const char *gitfile,
const char *worktree, const char *gitdir,
struct strbuf *report)
{
- struct safe_directory_data data = {
- .path = worktree ? worktree : gitdir
- };
+ struct safe_directory_data data = { 0 };
if (!git_env_bool("GIT_TEST_ASSUME_DIFFERENT_OWNER", 0) &&
(!gitfile || is_path_owned_by_current_user(gitfile, report)) &&
@@ -1274,12 +1300,22 @@ static int ensure_valid_ownership(const char *gitfile,
return 1;
/*
+ * normalize the data.path for comparison with normalized paths
+ * that come from the configuration file. The path is unsafe
+ * if it cannot be normalized.
+ */
+ data.path = real_pathdup(worktree ? worktree : gitdir, 0);
+ if (!data.path)
+ return 0;
+
+ /*
* data.path is the "path" that identifies the repository and it is
* constant regardless of what failed above. data.is_safe should be
* initialized to false, and might be changed by the callback.
*/
git_protected_config(safe_directory_cb, &data);
+ free(data.path);
return data.is_safe;
}
diff --git a/shallow.c b/shallow.c
index 31a6ca40fe..b8cd051e3b 100644
--- a/shallow.c
+++ b/shallow.c
@@ -612,6 +612,7 @@ static void paint_down(struct paint_info *info, const struct object_id *oid,
}
static int mark_uninteresting(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flags UNUSED,
void *cb_data UNUSED)
@@ -727,6 +728,7 @@ struct commit_array {
};
static int add_ref(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flags UNUSED,
void *cb_data)
diff --git a/sideband.c b/sideband.c
index 5d8907151f..5b6b872a1c 100644
--- a/sideband.c
+++ b/sideband.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "color.h"
#include "config.h"
diff --git a/submodule-config.c b/submodule-config.c
index 9b0bb0b9f4..c8f2bb2bdd 100644
--- a/submodule-config.c
+++ b/submodule-config.c
@@ -899,27 +899,25 @@ static void traverse_tree_submodules(struct repository *r,
{
struct tree_desc tree;
struct submodule_tree_entry *st_entry;
- struct name_entry *name_entry;
+ struct name_entry name_entry;
char *tree_path = NULL;
- name_entry = xmalloc(sizeof(*name_entry));
-
fill_tree_descriptor(r, &tree, treeish_name);
- while (tree_entry(&tree, name_entry)) {
+ while (tree_entry(&tree, &name_entry)) {
if (prefix)
tree_path =
- mkpathdup("%s/%s", prefix, name_entry->path);
+ mkpathdup("%s/%s", prefix, name_entry.path);
else
- tree_path = xstrdup(name_entry->path);
+ tree_path = xstrdup(name_entry.path);
- if (S_ISGITLINK(name_entry->mode) &&
+ if (S_ISGITLINK(name_entry.mode) &&
is_tree_submodule_active(r, root_tree, tree_path)) {
ALLOC_GROW(out->entries, out->entry_nr + 1,
out->entry_alloc);
st_entry = &out->entries[out->entry_nr++];
st_entry->name_entry = xmalloc(sizeof(*st_entry->name_entry));
- *st_entry->name_entry = *name_entry;
+ *st_entry->name_entry = name_entry;
st_entry->submodule =
submodule_from_path(r, root_tree, tree_path);
st_entry->repo = xmalloc(sizeof(*st_entry->repo));
@@ -927,9 +925,9 @@ static void traverse_tree_submodules(struct repository *r,
root_tree))
FREE_AND_NULL(st_entry->repo);
- } else if (S_ISDIR(name_entry->mode))
+ } else if (S_ISDIR(name_entry.mode))
traverse_tree_submodules(r, root_tree, tree_path,
- &name_entry->oid, out);
+ &name_entry.oid, out);
free(tree_path);
}
}
diff --git a/submodule.c b/submodule.c
index ab99a30253..97516b0fec 100644
--- a/submodule.c
+++ b/submodule.c
@@ -159,7 +159,7 @@ int remove_path_from_gitmodules(const char *path)
}
strbuf_addstr(&sect, "submodule.");
strbuf_addstr(&sect, submodule->name);
- if (git_config_rename_section_in_file(GITMODULES_FILE, sect.buf, NULL) < 0) {
+ if (repo_config_rename_section_in_file(the_repository, GITMODULES_FILE, sect.buf, NULL) < 0) {
/* Maybe the user already did that, don't error out here */
warning(_("Could not remove .gitmodules entry for %s"), path);
strbuf_release(&sect);
@@ -953,6 +953,7 @@ static void free_submodules_data(struct string_list *submodules)
}
static int has_remote(const char *refname UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flags UNUSED, void *cb_data UNUSED)
{
@@ -1273,6 +1274,7 @@ int push_unpushed_submodules(struct repository *r,
}
static int append_oid_to_array(const char *ref UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flags UNUSED, void *data)
{
@@ -1496,7 +1498,7 @@ static const struct submodule *get_non_gitmodules_submodule(const char *path)
return (const struct submodule *) ret;
}
-static void fetch_task_release(struct fetch_task *p)
+static void fetch_task_free(struct fetch_task *p)
{
if (p->free_sub)
free((void*)p->sub);
@@ -1508,6 +1510,7 @@ static void fetch_task_release(struct fetch_task *p)
FREE_AND_NULL(p->repo);
strvec_clear(&p->git_args);
+ free(p);
}
static struct repository *get_submodule_repo_for(struct repository *r,
@@ -1576,8 +1579,7 @@ static struct fetch_task *fetch_task_create(struct submodule_parallel_fetch *spf
return task;
cleanup:
- fetch_task_release(task);
- free(task);
+ fetch_task_free(task);
return NULL;
}
@@ -1607,8 +1609,7 @@ get_fetch_task_from_index(struct submodule_parallel_fetch *spf,
} else {
struct strbuf empty_submodule_path = STRBUF_INIT;
- fetch_task_release(task);
- free(task);
+ fetch_task_free(task);
/*
* An empty directory is normal,
@@ -1654,8 +1655,7 @@ get_fetch_task_from_changed(struct submodule_parallel_fetch *spf,
cs_data->path,
repo_find_unique_abbrev(the_repository, cs_data->super_oid, DEFAULT_ABBREV));
- fetch_task_release(task);
- free(task);
+ fetch_task_free(task);
continue;
}
@@ -1763,7 +1763,7 @@ static int fetch_start_failure(struct strbuf *err UNUSED,
spf->result = 1;
- fetch_task_release(task);
+ fetch_task_free(task);
return 0;
}
@@ -1828,8 +1828,7 @@ static int fetch_finish(int retvalue, struct strbuf *err UNUSED,
}
out:
- fetch_task_release(task);
-
+ fetch_task_free(task);
return 0;
}
@@ -1883,6 +1882,7 @@ int fetch_submodules(struct repository *r,
strvec_clear(&spf.args);
out:
free_submodules_data(&spf.changed_submodule_names);
+ string_list_clear(&spf.seen_submodule_names, 0);
return spf.result;
}
diff --git a/t/README b/t/README
index 724ee58195..44c02d8129 100644
--- a/t/README
+++ b/t/README
@@ -445,9 +445,9 @@ GIT_TEST_MULTI_PACK_INDEX=<boolean>, when true, forces the multi-pack-
index to be written after every 'git repack' command, and overrides the
'core.multiPackIndex' setting to true.
-GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=<boolean>, when true, sets the
-'--bitmap' option on all invocations of 'git multi-pack-index write',
-and ignores pack-objects' '--write-bitmap-index'.
+GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=<boolean>, when true, sets
+the '--incremental' option on all invocations of 'git multi-pack-index
+write'.
GIT_TEST_SIDEBAND_ALL=<boolean>, when true, overrides the
'uploadpack.allowSidebandAll' setting to true, and when false, forces
diff --git a/t/helper/test-advise.c b/t/helper/test-advise.c
index 8a3fd0009a..6967c8e25c 100644
--- a/t/helper/test-advise.c
+++ b/t/helper/test-advise.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "advice.h"
#include "config.h"
diff --git a/t/helper/test-config.c b/t/helper/test-config.c
index ed444ca4c2..e193079ed5 100644
--- a/t/helper/test-config.c
+++ b/t/helper/test-config.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "config.h"
#include "setup.h"
diff --git a/t/helper/test-example-tap.c b/t/helper/test-example-tap.c
index d072ad559f..914af88e0a 100644
--- a/t/helper/test-example-tap.c
+++ b/t/helper/test-example-tap.c
@@ -72,6 +72,8 @@ static void t_empty(void)
int cmd__example_tap(int argc, const char **argv)
{
+ check(1);
+
test_res = TEST(check_res = check_int(1, ==, 1), "passing test");
TEST(t_res(1), "passing test and assertion return 1");
test_res = TEST(check_res = check_int(1, ==, 2), "failing test");
@@ -92,5 +94,38 @@ int cmd__example_tap(int argc, const char **argv)
test_res = TEST(t_empty(), "test with no checks");
TEST(check_int(test_res, ==, 0), "test with no checks returns 0");
+ if_test ("if_test passing test")
+ check_int(1, ==, 1);
+ if_test ("if_test failing test")
+ check_int(1, ==, 2);
+ if_test ("if_test passing TEST_TODO()")
+ TEST_TODO(check(0));
+ if_test ("if_test failing TEST_TODO()")
+ TEST_TODO(check(1));
+ if_test ("if_test test_skip()") {
+ check(0);
+ test_skip("missing prerequisite");
+ check(1);
+ }
+ if_test ("if_test test_skip() inside TEST_TODO()")
+ TEST_TODO((test_skip("missing prerequisite"), 1));
+ if_test ("if_test TEST_TODO() after failing check") {
+ check(0);
+ TEST_TODO(check(0));
+ }
+ if_test ("if_test failing check after TEST_TODO()") {
+ check(1);
+ TEST_TODO(check(0));
+ check(0);
+ }
+ if_test ("if_test messages from failing string and char comparison") {
+ check_str("\thello\\", "there\"\n");
+ check_str("NULL", NULL);
+ check_char('a', ==, '\n');
+ check_char('\\', ==, '\'');
+ }
+ if_test ("if_test test with no checks")
+ ; /* nothing */
+
return test_done();
}
diff --git a/t/helper/test-hashmap.c b/t/helper/test-hashmap.c
index 2912899558..195e6278be 100644
--- a/t/helper/test-hashmap.c
+++ b/t/helper/test-hashmap.c
@@ -12,11 +12,6 @@ struct test_entry
char key[FLEX_ARRAY];
};
-static const char *get_value(const struct test_entry *e)
-{
- return e->key + strlen(e->key) + 1;
-}
-
static int test_entry_cmp(const void *cmp_data,
const struct hashmap_entry *eptr,
const struct hashmap_entry *entry_or_key,
@@ -141,30 +136,16 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
/*
* Read stdin line by line and print result of commands to stdout:
*
- * hash key -> strhash(key) memhash(key) strihash(key) memihash(key)
- * put key value -> NULL / old value
- * get key -> NULL / value
- * remove key -> NULL / old value
- * iterate -> key1 value1\nkey2 value2\n...
- * size -> tablesize numentries
- *
* perfhashmap method rounds -> test hashmap.[ch] performance
*/
int cmd__hashmap(int argc, const char **argv)
{
struct string_list parts = STRING_LIST_INIT_NODUP;
struct strbuf line = STRBUF_INIT;
- int icase;
- struct hashmap map = HASHMAP_INIT(test_entry_cmp, &icase);
-
- /* init hash map */
- icase = argc > 1 && !strcmp("ignorecase", argv[1]);
/* process commands from stdin */
while (strbuf_getline(&line, stdin) != EOF) {
char *cmd, *p1, *p2;
- unsigned int hash = 0;
- struct test_entry *entry;
/* break line into command and up to two parameters */
string_list_setlen(&parts, 0);
@@ -180,84 +161,8 @@ int cmd__hashmap(int argc, const char **argv)
cmd = parts.items[0].string;
p1 = parts.nr >= 1 ? parts.items[1].string : NULL;
p2 = parts.nr >= 2 ? parts.items[2].string : NULL;
- if (p1)
- hash = icase ? strihash(p1) : strhash(p1);
-
- if (!strcmp("add", cmd) && p1 && p2) {
-
- /* create entry with key = p1, value = p2 */
- entry = alloc_test_entry(hash, p1, p2);
-
- /* add to hashmap */
- hashmap_add(&map, &entry->ent);
-
- } else if (!strcmp("put", cmd) && p1 && p2) {
-
- /* create entry with key = p1, value = p2 */
- entry = alloc_test_entry(hash, p1, p2);
-
- /* add / replace entry */
- entry = hashmap_put_entry(&map, entry, ent);
-
- /* print and free replaced entry, if any */
- puts(entry ? get_value(entry) : "NULL");
- free(entry);
-
- } else if (!strcmp("get", cmd) && p1) {
- /* lookup entry in hashmap */
- entry = hashmap_get_entry_from_hash(&map, hash, p1,
- struct test_entry, ent);
-
- /* print result */
- if (!entry)
- puts("NULL");
- hashmap_for_each_entry_from(&map, entry, ent)
- puts(get_value(entry));
-
- } else if (!strcmp("remove", cmd) && p1) {
-
- /* setup static key */
- struct hashmap_entry key;
- struct hashmap_entry *rm;
- hashmap_entry_init(&key, hash);
-
- /* remove entry from hashmap */
- rm = hashmap_remove(&map, &key, p1);
- entry = rm ? container_of(rm, struct test_entry, ent)
- : NULL;
-
- /* print result and free entry*/
- puts(entry ? get_value(entry) : "NULL");
- free(entry);
-
- } else if (!strcmp("iterate", cmd)) {
- struct hashmap_iter iter;
-
- hashmap_for_each_entry(&map, &iter, entry,
- ent /* member name */)
- printf("%s %s\n", entry->key, get_value(entry));
-
- } else if (!strcmp("size", cmd)) {
-
- /* print table sizes */
- printf("%u %u\n", map.tablesize,
- hashmap_get_size(&map));
-
- } else if (!strcmp("intern", cmd) && p1) {
-
- /* test that strintern works */
- const char *i1 = strintern(p1);
- const char *i2 = strintern(p1);
- if (strcmp(i1, p1))
- printf("strintern(%s) returns %s\n", p1, i1);
- else if (i1 == p1)
- printf("strintern(%s) returns input pointer\n", p1);
- else if (i1 != i2)
- printf("strintern(%s) != strintern(%s)", i1, i2);
- else
- printf("%s\n", i1);
- } else if (!strcmp("perfhashmap", cmd) && p1 && p2) {
+ if (!strcmp("perfhashmap", cmd) && p1 && p2) {
perf_hashmap(atoi(p1), atoi(p2));
@@ -270,6 +175,5 @@ int cmd__hashmap(int argc, const char **argv)
string_list_clear(&parts, 0);
strbuf_release(&line);
- hashmap_clear_and_free(&map, struct test_entry, ent);
return 0;
}
diff --git a/t/helper/test-read-midx.c b/t/helper/test-read-midx.c
index 83effc2b5f..69757e94fc 100644
--- a/t/helper/test-read-midx.c
+++ b/t/helper/test-read-midx.c
@@ -9,8 +9,10 @@
#include "packfile.h"
#include "setup.h"
#include "gettext.h"
+#include "pack-revindex.h"
-static int read_midx_file(const char *object_dir, int show_objects)
+static int read_midx_file(const char *object_dir, const char *checksum,
+ int show_objects)
{
uint32_t i;
struct multi_pack_index *m;
@@ -21,6 +23,13 @@ static int read_midx_file(const char *object_dir, int show_objects)
if (!m)
return 1;
+ if (checksum) {
+ while (m && strcmp(hash_to_hex(get_midx_checksum(m)), checksum))
+ m = m->base_midx;
+ if (!m)
+ return 1;
+ }
+
printf("header: %08x %d %d %d %d\n",
m->signature,
m->version,
@@ -54,7 +63,8 @@ static int read_midx_file(const char *object_dir, int show_objects)
struct pack_entry e;
for (i = 0; i < m->num_objects; i++) {
- nth_midxed_object_oid(&oid, m, i);
+ nth_midxed_object_oid(&oid, m,
+ i + m->num_objects_in_base);
fill_midx_entry(the_repository, &oid, &e, m);
printf("%s %"PRIu64"\t%s\n",
@@ -111,7 +121,7 @@ static int read_midx_bitmapped_packs(const char *object_dir)
if (!midx)
return 1;
- for (i = 0; i < midx->num_packs; i++) {
+ for (i = 0; i < midx->num_packs + midx->num_packs_in_base; i++) {
if (nth_bitmapped_pack(the_repository, midx, &pack, i) < 0)
return 1;
@@ -127,16 +137,16 @@ static int read_midx_bitmapped_packs(const char *object_dir)
int cmd__read_midx(int argc, const char **argv)
{
- if (!(argc == 2 || argc == 3))
- usage("read-midx [--show-objects|--checksum|--preferred-pack|--bitmap] <object-dir>");
+ if (!(argc == 2 || argc == 3 || argc == 4))
+ usage("read-midx [--show-objects|--checksum|--preferred-pack|--bitmap] <object-dir> <checksum>");
if (!strcmp(argv[1], "--show-objects"))
- return read_midx_file(argv[2], 1);
+ return read_midx_file(argv[2], argv[3], 1);
else if (!strcmp(argv[1], "--checksum"))
return read_midx_checksum(argv[2]);
else if (!strcmp(argv[1], "--preferred-pack"))
return read_midx_preferred_pack(argv[2]);
else if (!strcmp(argv[1], "--bitmap"))
return read_midx_bitmapped_packs(argv[2]);
- return read_midx_file(argv[1], 0);
+ return read_midx_file(argv[1], argv[2], 0);
}
diff --git a/t/helper/test-ref-store.c b/t/helper/test-ref-store.c
index 637b8b294e..65346dee55 100644
--- a/t/helper/test-ref-store.c
+++ b/t/helper/test-ref-store.c
@@ -156,7 +156,7 @@ static int cmd_rename_ref(struct ref_store *refs, const char **argv)
return refs_rename_ref(refs, oldref, newref, logmsg);
}
-static int each_ref(const char *refname, const struct object_id *oid,
+static int each_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flags, void *cb_data UNUSED)
{
printf("%s %s 0x%x\n", oid_to_hex(oid), refname, flags);
diff --git a/t/helper/test-reftable.c b/t/helper/test-reftable.c
index 623cf3f0f5..ded28ee5fb 100644
--- a/t/helper/test-reftable.c
+++ b/t/helper/test-reftable.c
@@ -6,7 +6,6 @@ int cmd__reftable(int argc, const char **argv)
{
/* test from simple to complex. */
block_test_main(argc, argv);
- readwrite_test_main(argc, argv);
stack_test_main(argc, argv);
return 0;
}
diff --git a/t/helper/test-userdiff.c b/t/helper/test-userdiff.c
index 0ce31ce59f..94c48ababb 100644
--- a/t/helper/test-userdiff.c
+++ b/t/helper/test-userdiff.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "test-tool.h"
#include "setup.h"
#include "userdiff.h"
diff --git a/t/lib-bitmap.sh b/t/lib-bitmap.sh
index f595937094..62aa6744a6 100644
--- a/t/lib-bitmap.sh
+++ b/t/lib-bitmap.sh
@@ -1,6 +1,8 @@
# Helpers for scripts testing bitmap functionality; see t5310 for
# example usage.
+. "$TEST_DIRECTORY"/lib-midx.sh
+
objdir=.git/objects
midx=$objdir/pack/multi-pack-index
@@ -264,10 +266,6 @@ have_delta () {
test_cmp expect actual
}
-midx_checksum () {
- test-tool read-midx --checksum "$1"
-}
-
# midx_pack_source <obj>
midx_pack_source () {
test-tool read-midx --show-objects .git/objects | grep "^$1 " | cut -f2
diff --git a/t/lib-midx.sh b/t/lib-midx.sh
index 1261994744..e38c609604 100644
--- a/t/lib-midx.sh
+++ b/t/lib-midx.sh
@@ -6,3 +6,31 @@ test_midx_consistent () {
test_cmp expect actual &&
git multi-pack-index --object-dir=$1 verify
}
+
+midx_checksum () {
+ test-tool read-midx --checksum "$1"
+}
+
+midx_git_two_modes () {
+ git -c core.multiPackIndex=false $1 >expect &&
+ git -c core.multiPackIndex=true $1 >actual &&
+ if [ "$2" = "sorted" ]
+ then
+ sort <expect >expect.sorted &&
+ mv expect.sorted expect &&
+ sort <actual >actual.sorted &&
+ mv actual.sorted actual
+ fi &&
+ test_cmp expect actual
+}
+
+compare_results_with_midx () {
+ MSG=$1
+ test_expect_success "check normal git operations: $MSG" '
+ midx_git_two_modes "rev-list --objects --all" &&
+ midx_git_two_modes "log --raw" &&
+ midx_git_two_modes "count-objects --verbose" &&
+ midx_git_two_modes "cat-file --batch-all-objects --batch-check" &&
+ midx_git_two_modes "cat-file --batch-all-objects --batch-check --unordered" sorted
+ '
+}
diff --git a/t/t0011-hashmap.sh b/t/t0011-hashmap.sh
deleted file mode 100755
index 46e74ad107..0000000000
--- a/t/t0011-hashmap.sh
+++ /dev/null
@@ -1,260 +0,0 @@
-#!/bin/sh
-
-test_description='test hashmap and string hash functions'
-
-TEST_PASSES_SANITIZE_LEAK=true
-. ./test-lib.sh
-
-test_hashmap() {
- echo "$1" | test-tool hashmap $3 > actual &&
- echo "$2" > expect &&
- test_cmp expect actual
-}
-
-test_expect_success 'put' '
-
-test_hashmap "put key1 value1
-put key2 value2
-put fooBarFrotz value3
-put foobarfrotz value4
-size" "NULL
-NULL
-NULL
-NULL
-64 4"
-
-'
-
-test_expect_success 'put (case insensitive)' '
-
-test_hashmap "put key1 value1
-put key2 value2
-put fooBarFrotz value3
-size" "NULL
-NULL
-NULL
-64 3" ignorecase
-
-'
-
-test_expect_success 'replace' '
-
-test_hashmap "put key1 value1
-put key1 value2
-put fooBarFrotz value3
-put fooBarFrotz value4
-size" "NULL
-value1
-NULL
-value3
-64 2"
-
-'
-
-test_expect_success 'replace (case insensitive)' '
-
-test_hashmap "put key1 value1
-put Key1 value2
-put fooBarFrotz value3
-put foobarfrotz value4
-size" "NULL
-value1
-NULL
-value3
-64 2" ignorecase
-
-'
-
-test_expect_success 'get' '
-
-test_hashmap "put key1 value1
-put key2 value2
-put fooBarFrotz value3
-put foobarfrotz value4
-get key1
-get key2
-get fooBarFrotz
-get notInMap" "NULL
-NULL
-NULL
-NULL
-value1
-value2
-value3
-NULL"
-
-'
-
-test_expect_success 'get (case insensitive)' '
-
-test_hashmap "put key1 value1
-put key2 value2
-put fooBarFrotz value3
-get Key1
-get keY2
-get foobarfrotz
-get notInMap" "NULL
-NULL
-NULL
-value1
-value2
-value3
-NULL" ignorecase
-
-'
-
-test_expect_success 'add' '
-
-test_hashmap "add key1 value1
-add key1 value2
-add fooBarFrotz value3
-add fooBarFrotz value4
-get key1
-get fooBarFrotz
-get notInMap" "value2
-value1
-value4
-value3
-NULL"
-
-'
-
-test_expect_success 'add (case insensitive)' '
-
-test_hashmap "add key1 value1
-add Key1 value2
-add fooBarFrotz value3
-add foobarfrotz value4
-get key1
-get Foobarfrotz
-get notInMap" "value2
-value1
-value4
-value3
-NULL" ignorecase
-
-'
-
-test_expect_success 'remove' '
-
-test_hashmap "put key1 value1
-put key2 value2
-put fooBarFrotz value3
-remove key1
-remove key2
-remove notInMap
-size" "NULL
-NULL
-NULL
-value1
-value2
-NULL
-64 1"
-
-'
-
-test_expect_success 'remove (case insensitive)' '
-
-test_hashmap "put key1 value1
-put key2 value2
-put fooBarFrotz value3
-remove Key1
-remove keY2
-remove notInMap
-size" "NULL
-NULL
-NULL
-value1
-value2
-NULL
-64 1" ignorecase
-
-'
-
-test_expect_success 'iterate' '
- test-tool hashmap >actual.raw <<-\EOF &&
- put key1 value1
- put key2 value2
- put fooBarFrotz value3
- iterate
- EOF
-
- cat >expect <<-\EOF &&
- NULL
- NULL
- NULL
- fooBarFrotz value3
- key1 value1
- key2 value2
- EOF
-
- sort <actual.raw >actual &&
- test_cmp expect actual
-'
-
-test_expect_success 'iterate (case insensitive)' '
- test-tool hashmap ignorecase >actual.raw <<-\EOF &&
- put key1 value1
- put key2 value2
- put fooBarFrotz value3
- iterate
- EOF
-
- cat >expect <<-\EOF &&
- NULL
- NULL
- NULL
- fooBarFrotz value3
- key1 value1
- key2 value2
- EOF
-
- sort <actual.raw >actual &&
- test_cmp expect actual
-'
-
-test_expect_success 'grow / shrink' '
-
- rm -f in &&
- rm -f expect &&
- for n in $(test_seq 51)
- do
- echo put key$n value$n >> in &&
- echo NULL >> expect || return 1
- done &&
- echo size >> in &&
- echo 64 51 >> expect &&
- echo put key52 value52 >> in &&
- echo NULL >> expect &&
- echo size >> in &&
- echo 256 52 >> expect &&
- for n in $(test_seq 12)
- do
- echo remove key$n >> in &&
- echo value$n >> expect || return 1
- done &&
- echo size >> in &&
- echo 256 40 >> expect &&
- echo remove key40 >> in &&
- echo value40 >> expect &&
- echo size >> in &&
- echo 64 39 >> expect &&
- test-tool hashmap <in >out &&
- test_cmp expect out
-
-'
-
-test_expect_success 'string interning' '
-
-test_hashmap "intern value1
-intern Value1
-intern value2
-intern value2
-" "value1
-Value1
-value2
-value2"
-
-'
-
-test_done
diff --git a/t/t0033-safe-directory.sh b/t/t0033-safe-directory.sh
index 5fe61f1291..e97a84764f 100755
--- a/t/t0033-safe-directory.sh
+++ b/t/t0033-safe-directory.sh
@@ -119,4 +119,182 @@ test_expect_success 'local clone of unowned repo accepted in safe directory' '
test_path_is_dir target
'
+test_expect_success SYMLINKS 'checked paths are normalized' '
+ test_when_finished "rm -rf repository; rm -f repo" &&
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global --unset-all safe.directory
+ ) &&
+ git init repository &&
+ ln -s repository repo &&
+ (
+ cd repository &&
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ test_commit sample
+ ) &&
+
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global safe.directory "$(pwd)/repository"
+ ) &&
+ git -C repository for-each-ref &&
+ git -C repository/ for-each-ref &&
+ git -C repo for-each-ref &&
+ git -C repo/ for-each-ref &&
+ test_must_fail git -C repository/.git for-each-ref &&
+ test_must_fail git -C repository/.git/ for-each-ref &&
+ test_must_fail git -C repo/.git for-each-ref &&
+ test_must_fail git -C repo/.git/ for-each-ref
+'
+
+test_expect_success SYMLINKS 'checked leading paths are normalized' '
+ test_when_finished "rm -rf repository; rm -f repo" &&
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global --unset-all safe.directory
+ ) &&
+ mkdir -p repository &&
+ git init repository/s &&
+ ln -s repository repo &&
+ (
+ cd repository/s &&
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ test_commit sample
+ ) &&
+
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global safe.directory "$(pwd)/repository/*"
+ ) &&
+ git -C repository/s for-each-ref &&
+ git -C repository/s/ for-each-ref &&
+ git -C repo/s for-each-ref &&
+ git -C repo/s/ for-each-ref &&
+ git -C repository/s/.git for-each-ref &&
+ git -C repository/s/.git/ for-each-ref &&
+ git -C repo/s/.git for-each-ref &&
+ git -C repo/s/.git/ for-each-ref
+'
+
+test_expect_success SYMLINKS 'configured paths are normalized' '
+ test_when_finished "rm -rf repository; rm -f repo" &&
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global --unset-all safe.directory
+ ) &&
+ git init repository &&
+ ln -s repository repo &&
+ (
+ cd repository &&
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ test_commit sample
+ ) &&
+
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global safe.directory "$(pwd)/repo"
+ ) &&
+ git -C repository for-each-ref &&
+ git -C repository/ for-each-ref &&
+ git -C repo for-each-ref &&
+ git -C repo/ for-each-ref &&
+ test_must_fail git -C repository/.git for-each-ref &&
+ test_must_fail git -C repository/.git/ for-each-ref &&
+ test_must_fail git -C repo/.git for-each-ref &&
+ test_must_fail git -C repo/.git/ for-each-ref
+'
+
+test_expect_success SYMLINKS 'configured leading paths are normalized' '
+ test_when_finished "rm -rf repository; rm -f repo" &&
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global --unset-all safe.directory
+ ) &&
+ mkdir -p repository &&
+ git init repository/s &&
+ ln -s repository repo &&
+ (
+ cd repository/s &&
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ test_commit sample
+ ) &&
+
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global safe.directory "$(pwd)/repo/*"
+ ) &&
+ git -C repository/s for-each-ref &&
+ git -C repository/s/ for-each-ref &&
+ git -C repository/s/.git for-each-ref &&
+ git -C repository/s/.git/ for-each-ref &&
+ git -C repo/s for-each-ref &&
+ git -C repo/s/ for-each-ref &&
+ git -C repo/s/.git for-each-ref &&
+ git -C repo/s/.git/ for-each-ref
+'
+
+test_expect_success 'safe.directory set to a dot' '
+ test_when_finished "rm -rf repository" &&
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global --unset-all safe.directory
+ ) &&
+ mkdir -p repository/subdir &&
+ git init repository &&
+ (
+ cd repository &&
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ test_commit sample
+ ) &&
+
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global safe.directory "."
+ ) &&
+ git -C repository for-each-ref &&
+ git -C repository/ for-each-ref &&
+ git -C repository/.git for-each-ref &&
+ git -C repository/.git/ for-each-ref &&
+
+ # What is allowed is repository/subdir but the repository
+ # path is repository.
+ test_must_fail git -C repository/subdir for-each-ref &&
+
+ # Likewise, repository .git/refs is allowed with "." but
+ # repository/.git that is accessed is not allowed.
+ test_must_fail git -C repository/.git/refs for-each-ref
+'
+
+test_expect_success 'safe.directory set to asterisk' '
+ test_when_finished "rm -rf repository" &&
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global --unset-all safe.directory
+ ) &&
+ mkdir -p repository/subdir &&
+ git init repository &&
+ (
+ cd repository &&
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ test_commit sample
+ ) &&
+
+ (
+ sane_unset GIT_TEST_ASSUME_DIFFERENT_OWNER &&
+ git config --global safe.directory "*"
+ ) &&
+ # these are trivial
+ git -C repository for-each-ref &&
+ git -C repository/ for-each-ref &&
+ git -C repository/.git for-each-ref &&
+ git -C repository/.git/ for-each-ref &&
+
+ # With "*", everything is allowed, and the repository is
+ # discovered, which is different behaviour from "." above.
+ git -C repository/subdir for-each-ref &&
+
+ # Likewise.
+ git -C repository/.git/refs for-each-ref
+'
+
test_done
diff --git a/t/t0080-unit-test-output.sh b/t/t0080-unit-test-output.sh
index 7bbb065d58..3c369c88e2 100755
--- a/t/t0080-unit-test-output.sh
+++ b/t/t0080-unit-test-output.sh
@@ -5,23 +5,24 @@ test_description='Test the output of the unit test framework'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
-test_expect_success 'TAP output from unit tests' '
+test_expect_success 'TAP output from unit tests' - <<\EOT
cat >expect <<-EOF &&
+ # BUG: check outside of test at t/helper/test-example-tap.c:75
ok 1 - passing test
ok 2 - passing test and assertion return 1
- # check "1 == 2" failed at t/helper/test-example-tap.c:77
+ # check "1 == 2" failed at t/helper/test-example-tap.c:79
# left: 1
# right: 2
not ok 3 - failing test
ok 4 - failing test and assertion return 0
not ok 5 - passing TEST_TODO() # TODO
ok 6 - passing TEST_TODO() returns 1
- # todo check ${SQ}check(x)${SQ} succeeded at t/helper/test-example-tap.c:26
+ # todo check 'check(x)' succeeded at t/helper/test-example-tap.c:26
not ok 7 - failing TEST_TODO()
ok 8 - failing TEST_TODO() returns 0
# check "0" failed at t/helper/test-example-tap.c:31
# skipping test - missing prerequisite
- # skipping check ${SQ}1${SQ} at t/helper/test-example-tap.c:33
+ # skipping check '1' at t/helper/test-example-tap.c:33
ok 9 - test_skip() # SKIP
ok 10 - skipped test returns 1
# skipping test - missing prerequisite
@@ -39,21 +40,54 @@ test_expect_success 'TAP output from unit tests' '
# check "!strcmp("NULL", NULL)" failed at t/helper/test-example-tap.c:63
# left: "NULL"
# right: NULL
- # check "${SQ}a${SQ} == ${SQ}\n${SQ}" failed at t/helper/test-example-tap.c:64
- # left: ${SQ}a${SQ}
- # right: ${SQ}\012${SQ}
- # check "${SQ}\\\\${SQ} == ${SQ}\\${SQ}${SQ}" failed at t/helper/test-example-tap.c:65
- # left: ${SQ}\\\\${SQ}
- # right: ${SQ}\\${SQ}${SQ}
+ # check "'a' == '\n'" failed at t/helper/test-example-tap.c:64
+ # left: 'a'
+ # right: '\012'
+ # check "'\\\\' == '\\''" failed at t/helper/test-example-tap.c:65
+ # left: '\\\\'
+ # right: '\\''
not ok 17 - messages from failing string and char comparison
- # BUG: test has no checks at t/helper/test-example-tap.c:92
+ # BUG: test has no checks at t/helper/test-example-tap.c:94
not ok 18 - test with no checks
ok 19 - test with no checks returns 0
- 1..19
+ ok 20 - if_test passing test
+ # check "1 == 2" failed at t/helper/test-example-tap.c:100
+ # left: 1
+ # right: 2
+ not ok 21 - if_test failing test
+ not ok 22 - if_test passing TEST_TODO() # TODO
+ # todo check 'check(1)' succeeded at t/helper/test-example-tap.c:104
+ not ok 23 - if_test failing TEST_TODO()
+ # check "0" failed at t/helper/test-example-tap.c:106
+ # skipping test - missing prerequisite
+ # skipping check '1' at t/helper/test-example-tap.c:108
+ ok 24 - if_test test_skip() # SKIP
+ # skipping test - missing prerequisite
+ ok 25 - if_test test_skip() inside TEST_TODO() # SKIP
+ # check "0" failed at t/helper/test-example-tap.c:113
+ not ok 26 - if_test TEST_TODO() after failing check
+ # check "0" failed at t/helper/test-example-tap.c:119
+ not ok 27 - if_test failing check after TEST_TODO()
+ # check "!strcmp("\thello\\\\", "there\"\n")" failed at t/helper/test-example-tap.c:122
+ # left: "\011hello\\\\"
+ # right: "there\"\012"
+ # check "!strcmp("NULL", NULL)" failed at t/helper/test-example-tap.c:123
+ # left: "NULL"
+ # right: NULL
+ # check "'a' == '\n'" failed at t/helper/test-example-tap.c:124
+ # left: 'a'
+ # right: '\012'
+ # check "'\\\\' == '\\''" failed at t/helper/test-example-tap.c:125
+ # left: '\\\\'
+ # right: '\\''
+ not ok 28 - if_test messages from failing string and char comparison
+ # BUG: test has no checks at t/helper/test-example-tap.c:127
+ not ok 29 - if_test test with no checks
+ 1..29
EOF
! test-tool example-tap >actual &&
test_cmp expect actual
-'
+EOT
test_done
diff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh
index c312657a12..b9adc94aab 100755
--- a/t/t0210-trace2-normal.sh
+++ b/t/t0210-trace2-normal.sh
@@ -2,7 +2,7 @@
test_description='test trace2 facility (normal target)'
-TEST_PASSES_SANITIZE_LEAK=false
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Turn off any inherited trace2 settings for this test.
diff --git a/t/t0410-partial-clone.sh b/t/t0410-partial-clone.sh
index 2c30c86e7b..34bdb3ab1f 100755
--- a/t/t0410-partial-clone.sh
+++ b/t/t0410-partial-clone.sh
@@ -5,8 +5,6 @@ test_description='partial clone'
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-terminal.sh
-# missing promisor objects cause repacks which write bitmaps to fail
-GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
# When enabled, some commands will write commit-graphs. This causes fsck
# to fail when delete_object() is called because fsck will attempt to
# verify the out-of-sync commit graph.
diff --git a/t/t0602-reffiles-fsck.sh b/t/t0602-reffiles-fsck.sh
new file mode 100755
index 0000000000..71a4d1a5ae
--- /dev/null
+++ b/t/t0602-reffiles-fsck.sh
@@ -0,0 +1,92 @@
+#!/bin/sh
+
+test_description='Test reffiles backend consistency check'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+GIT_TEST_DEFAULT_REF_FORMAT=files
+export GIT_TEST_DEFAULT_REF_FORMAT
+TEST_PASSES_SANITIZE_LEAK=true
+
+. ./test-lib.sh
+
+test_expect_success 'ref name should be checked' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ branch_dir_prefix=.git/refs/heads &&
+ tag_dir_prefix=.git/refs/tags &&
+ cd repo &&
+
+ git commit --allow-empty -m initial &&
+ git checkout -b branch-1 &&
+ git tag tag-1 &&
+ git commit --allow-empty -m second &&
+ git checkout -b branch-2 &&
+ git tag tag-2 &&
+ git tag multi_hierarchy/tag-2 &&
+
+ cp $branch_dir_prefix/branch-1 $branch_dir_prefix/.branch-1 &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ error: refs/heads/.branch-1: badRefName: invalid refname format
+ EOF
+ rm $branch_dir_prefix/.branch-1 &&
+ test_cmp expect err &&
+
+ cp $branch_dir_prefix/branch-1 $branch_dir_prefix/@ &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ error: refs/heads/@: badRefName: invalid refname format
+ EOF
+ rm $branch_dir_prefix/@ &&
+ test_cmp expect err &&
+
+ cp $tag_dir_prefix/multi_hierarchy/tag-2 $tag_dir_prefix/multi_hierarchy/@ &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ error: refs/tags/multi_hierarchy/@: badRefName: invalid refname format
+ EOF
+ rm $tag_dir_prefix/multi_hierarchy/@ &&
+ test_cmp expect err &&
+
+ cp $tag_dir_prefix/tag-1 $tag_dir_prefix/tag-1.lock &&
+ git refs verify 2>err &&
+ rm $tag_dir_prefix/tag-1.lock &&
+ test_must_be_empty err &&
+
+ cp $tag_dir_prefix/tag-1 $tag_dir_prefix/.lock &&
+ test_must_fail git refs verify 2>err &&
+ cat >expect <<-EOF &&
+ error: refs/tags/.lock: badRefName: invalid refname format
+ EOF
+ rm $tag_dir_prefix/.lock &&
+ test_cmp expect err
+'
+
+test_expect_success 'ref name check should be adapted into fsck messages' '
+ test_when_finished "rm -rf repo" &&
+ git init repo &&
+ branch_dir_prefix=.git/refs/heads &&
+ tag_dir_prefix=.git/refs/tags &&
+ cd repo &&
+ git commit --allow-empty -m initial &&
+ git checkout -b branch-1 &&
+ git tag tag-1 &&
+ git commit --allow-empty -m second &&
+ git checkout -b branch-2 &&
+ git tag tag-2 &&
+
+ cp $branch_dir_prefix/branch-1 $branch_dir_prefix/.branch-1 &&
+ git -c fsck.badRefName=warn refs verify 2>err &&
+ cat >expect <<-EOF &&
+ warning: refs/heads/.branch-1: badRefName: invalid refname format
+ EOF
+ rm $branch_dir_prefix/.branch-1 &&
+ test_cmp expect err &&
+
+ cp $branch_dir_prefix/branch-1 $branch_dir_prefix/@ &&
+ git -c fsck.badRefName=ignore refs verify 2>err &&
+ test_must_be_empty err
+'
+
+test_done
diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh
index b06c46999d..37510c2b2a 100755
--- a/t/t0610-reftable-basics.sh
+++ b/t/t0610-reftable-basics.sh
@@ -478,19 +478,26 @@ test_expect_success "$command: auto compaction" '
test_oid blob17_2 | git hash-object -w --stdin &&
- # Lock all tables write some refs. Auto-compaction will be
- # unable to compact tables and thus fails gracefully, leaving
- # the stack in a sub-optimal state.
- ls .git/reftable/*.ref |
+ # Lock all tables, write some refs. Auto-compaction will be
+ # unable to compact tables and thus fails gracefully,
+ # compacting only those tables which are not locked.
+ ls .git/reftable/*.ref | sort |
while read table
do
- touch "$table.lock" || exit 1
+ touch "$table.lock" &&
+ basename "$table" >>tables.expect || exit 1
done &&
+ test_line_count = 2 .git/reftable/tables.list &&
git branch B &&
git branch C &&
- rm .git/reftable/*.lock &&
- test_line_count = 4 .git/reftable/tables.list &&
+ # The new tables are auto-compacted, but the locked tables are
+ # left intact.
+ test_line_count = 3 .git/reftable/tables.list &&
+ head -n 2 .git/reftable/tables.list >tables.head &&
+ test_cmp tables.expect tables.head &&
+
+ rm .git/reftable/*.lock &&
git $command --auto &&
test_line_count = 1 .git/reftable/tables.list
)
diff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh
index 88c524f655..48a1550371 100755
--- a/t/t1001-read-tree-m-2way.sh
+++ b/t/t1001-read-tree-m-2way.sh
@@ -397,7 +397,7 @@ test_expect_success 'a/b vs a, plus c/d case setup.' '
test_expect_success 'a/b vs a, plus c/d case test.' '
read_tree_u_must_succeed -u -m "$treeH" "$treeM" &&
- git ls-files --stage | tee >treeMcheck.out &&
+ git ls-files --stage >treeMcheck.out &&
test_cmp treeM.out treeMcheck.out
'
diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh
index ff9bf213aa..d36cd7c086 100755
--- a/t/t1006-cat-file.sh
+++ b/t/t1006-cat-file.sh
@@ -2,6 +2,7 @@
test_description='git cat-file'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_cmdmode_usage () {
diff --git a/t/t1050-large.sh b/t/t1050-large.sh
index c71932b024..ed638f6644 100755
--- a/t/t1050-large.sh
+++ b/t/t1050-large.sh
@@ -3,6 +3,7 @@
test_description='adding and checking out large blobs'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'core.bigFileThreshold must be non-negative' '
diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh
index 8a456b1142..280cbf3e03 100755
--- a/t/t1450-fsck.sh
+++ b/t/t1450-fsck.sh
@@ -6,6 +6,7 @@ test_description='git fsck random collection of tests
* (main) A
'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t1601-index-bogus.sh b/t/t1601-index-bogus.sh
index 4171f1e141..5dcc101882 100755
--- a/t/t1601-index-bogus.sh
+++ b/t/t1601-index-bogus.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='test handling of bogus index entries'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'create tree with null sha1' '
diff --git a/t/t3206-range-diff.sh b/t/t3206-range-diff.sh
index 973e20254b..86010931ab 100755
--- a/t/t3206-range-diff.sh
+++ b/t/t3206-range-diff.sh
@@ -534,9 +534,9 @@ test_expect_success 'dual-coloring' '
for prev in topic main..topic
do
test_expect_success "format-patch --range-diff=$prev" '
+ test_when_finished "rm -f 000?-*" &&
git format-patch --cover-letter --range-diff=$prev \
main..unmodified >actual &&
- test_when_finished "rm 000?-*" &&
test_line_count = 5 actual &&
test_grep "^Range-diff:$" 0000-* &&
grep "= 1: .* s/5/A" 0000-* &&
@@ -561,32 +561,32 @@ test_expect_success "explicit --no-cover-letter defeats implied --cover-letter"
'
test_expect_success 'format-patch --range-diff as commentary' '
+ test_when_finished "rm -f 0001-*" &&
git format-patch --range-diff=HEAD~1 HEAD~1 >actual &&
- test_when_finished "rm 0001-*" &&
test_line_count = 1 actual &&
test_grep "^Range-diff:$" 0001-* &&
grep "> 1: .* new message" 0001-*
'
test_expect_success 'format-patch --range-diff reroll-count with a non-integer' '
+ test_when_finished "rm -f v2.9-0001-*" &&
git format-patch --range-diff=HEAD~1 -v2.9 HEAD~1 >actual &&
- test_when_finished "rm v2.9-0001-*" &&
test_line_count = 1 actual &&
test_grep "^Range-diff:$" v2.9-0001-* &&
grep "> 1: .* new message" v2.9-0001-*
'
test_expect_success 'format-patch --range-diff reroll-count with a integer' '
+ test_when_finished "rm -f v2-0001-*" &&
git format-patch --range-diff=HEAD~1 -v2 HEAD~1 >actual &&
- test_when_finished "rm v2-0001-*" &&
test_line_count = 1 actual &&
test_grep "^Range-diff ..* v1:$" v2-0001-* &&
grep "> 1: .* new message" v2-0001-*
'
test_expect_success 'format-patch --range-diff with v0' '
+ test_when_finished "rm -f v0-0001-*" &&
git format-patch --range-diff=HEAD~1 -v0 HEAD~1 >actual &&
- test_when_finished "rm v0-0001-*" &&
test_line_count = 1 actual &&
test_grep "^Range-diff:$" v0-0001-* &&
grep "> 1: .* new message" v0-0001-*
@@ -607,9 +607,9 @@ test_expect_success 'basic with modified format.pretty without "commit "' '
'
test_expect_success 'range-diff compares notes by default' '
+ test_when_finished "git notes remove topic unmodified || :" &&
git notes add -m "topic note" topic &&
git notes add -m "unmodified note" unmodified &&
- test_when_finished git notes remove topic unmodified &&
git range-diff --no-color main..topic main..unmodified \
>actual &&
sed s/Z/\ /g >expect <<-EOF &&
@@ -631,9 +631,9 @@ test_expect_success 'range-diff compares notes by default' '
'
test_expect_success 'range-diff with --no-notes' '
+ test_when_finished "git notes remove topic unmodified || :" &&
git notes add -m "topic note" topic &&
git notes add -m "unmodified note" unmodified &&
- test_when_finished git notes remove topic unmodified &&
git range-diff --no-color --no-notes main..topic main..unmodified \
>actual &&
cat >expect <<-EOF &&
@@ -646,12 +646,12 @@ test_expect_success 'range-diff with --no-notes' '
'
test_expect_success 'range-diff with multiple --notes' '
+ test_when_finished "git notes --ref=note1 remove topic unmodified || :" &&
git notes --ref=note1 add -m "topic note1" topic &&
git notes --ref=note1 add -m "unmodified note1" unmodified &&
- test_when_finished git notes --ref=note1 remove topic unmodified &&
+ test_when_finished "git notes --ref=note2 remove topic unmodified || :" &&
git notes --ref=note2 add -m "topic note2" topic &&
git notes --ref=note2 add -m "unmodified note2" unmodified &&
- test_when_finished git notes --ref=note2 remove topic unmodified &&
git range-diff --no-color --notes=note1 --notes=note2 main..topic main..unmodified \
>actual &&
sed s/Z/\ /g >expect <<-EOF &&
@@ -679,12 +679,12 @@ test_expect_success 'range-diff with multiple --notes' '
# `range-diff` should act like `log` with regards to notes
test_expect_success 'range-diff with --notes=custom does not show default notes' '
+ test_when_finished "git notes remove topic unmodified || :" &&
git notes add -m "topic note" topic &&
git notes add -m "unmodified note" unmodified &&
+ test_when_finished "git notes --ref=custom remove topic unmodified || :" &&
git notes --ref=custom add -m "topic note" topic &&
git notes --ref=custom add -m "unmodified note" unmodified &&
- test_when_finished git notes remove topic unmodified &&
- test_when_finished git notes --ref=custom remove topic unmodified &&
git range-diff --notes=custom main..topic main..unmodified \
>actual &&
! grep "## Notes ##" actual &&
@@ -692,12 +692,12 @@ test_expect_success 'range-diff with --notes=custom does not show default notes'
'
test_expect_success 'format-patch --range-diff does not compare notes by default' '
+ test_when_finished "git notes remove topic unmodified || :" &&
git notes add -m "topic note" topic &&
git notes add -m "unmodified note" unmodified &&
- test_when_finished git notes remove topic unmodified &&
+ test_when_finished "rm -f 000?-*" &&
git format-patch --cover-letter --range-diff=$prev \
main..unmodified >actual &&
- test_when_finished "rm 000?-*" &&
test_line_count = 5 actual &&
test_grep "^Range-diff:$" 0000-* &&
grep "= 1: .* s/5/A" 0000-* &&
@@ -709,26 +709,26 @@ test_expect_success 'format-patch --range-diff does not compare notes by default
'
test_expect_success 'format-patch --notes=custom --range-diff only compares custom notes' '
+ test_when_finished "git notes remove topic unmodified || :" &&
git notes add -m "topic note" topic &&
- git notes --ref=custom add -m "topic note (custom)" topic &&
git notes add -m "unmodified note" unmodified &&
+ test_when_finished "git notes --ref=custom remove topic unmodified || :" &&
+ git notes --ref=custom add -m "topic note (custom)" topic &&
git notes --ref=custom add -m "unmodified note (custom)" unmodified &&
- test_when_finished git notes remove topic unmodified &&
- test_when_finished git notes --ref=custom remove topic unmodified &&
+ test_when_finished "rm -f 000?-*" &&
git format-patch --notes=custom --cover-letter --range-diff=$prev \
main..unmodified >actual &&
- test_when_finished "rm 000?-*" &&
grep "## Notes (custom) ##" 0000-* &&
! grep "## Notes ##" 0000-*
'
test_expect_success 'format-patch --range-diff with --no-notes' '
+ test_when_finished "git notes remove topic unmodified || :" &&
git notes add -m "topic note" topic &&
git notes add -m "unmodified note" unmodified &&
- test_when_finished git notes remove topic unmodified &&
+ test_when_finished "rm -f 000?-*" &&
git format-patch --no-notes --cover-letter --range-diff=$prev \
main..unmodified >actual &&
- test_when_finished "rm 000?-*" &&
test_line_count = 5 actual &&
test_grep "^Range-diff:$" 0000-* &&
grep "= 1: .* s/5/A" 0000-* &&
@@ -740,12 +740,12 @@ test_expect_success 'format-patch --range-diff with --no-notes' '
'
test_expect_success 'format-patch --range-diff with --notes' '
+ test_when_finished "git notes remove topic unmodified || :" &&
git notes add -m "topic note" topic &&
git notes add -m "unmodified note" unmodified &&
- test_when_finished git notes remove topic unmodified &&
+ test_when_finished "rm -f 000?-*" &&
git format-patch --notes --cover-letter --range-diff=$prev \
main..unmodified >actual &&
- test_when_finished "rm 000?-*" &&
test_line_count = 5 actual &&
test_grep "^Range-diff:$" 0000-* &&
grep "= 1: .* s/5/A" 0000-* &&
@@ -768,13 +768,13 @@ test_expect_success 'format-patch --range-diff with --notes' '
'
test_expect_success 'format-patch --range-diff with format.notes config' '
+ test_when_finished "git notes remove topic unmodified || :" &&
git notes add -m "topic note" topic &&
git notes add -m "unmodified note" unmodified &&
- test_when_finished git notes remove topic unmodified &&
test_config format.notes true &&
+ test_when_finished "rm -f 000?-*" &&
git format-patch --cover-letter --range-diff=$prev \
main..unmodified >actual &&
- test_when_finished "rm 000?-*" &&
test_line_count = 5 actual &&
test_grep "^Range-diff:$" 0000-* &&
grep "= 1: .* s/5/A" 0000-* &&
@@ -797,15 +797,15 @@ test_expect_success 'format-patch --range-diff with format.notes config' '
'
test_expect_success 'format-patch --range-diff with multiple notes' '
+ test_when_finished "git notes --ref=note1 remove topic unmodified || :" &&
git notes --ref=note1 add -m "topic note1" topic &&
git notes --ref=note1 add -m "unmodified note1" unmodified &&
- test_when_finished git notes --ref=note1 remove topic unmodified &&
+ test_when_finished "git notes --ref=note2 remove topic unmodified || :" &&
git notes --ref=note2 add -m "topic note2" topic &&
git notes --ref=note2 add -m "unmodified note2" unmodified &&
- test_when_finished git notes --ref=note2 remove topic unmodified &&
+ test_when_finished "rm -f 000?-*" &&
git format-patch --notes=note1 --notes=note2 --cover-letter --range-diff=$prev \
main..unmodified >actual &&
- test_when_finished "rm 000?-*" &&
test_line_count = 5 actual &&
test_grep "^Range-diff:$" 0000-* &&
grep "= 1: .* s/5/A" 0000-* &&
diff --git a/t/t3310-notes-merge-manual-resolve.sh b/t/t3310-notes-merge-manual-resolve.sh
index 597df5ebc0..04866b89be 100755
--- a/t/t3310-notes-merge-manual-resolve.sh
+++ b/t/t3310-notes-merge-manual-resolve.sh
@@ -5,6 +5,7 @@
test_description='Test notes merging with manual conflict resolution'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Set up a notes merge scenario with different kinds of conflicts
diff --git a/t/t3311-notes-merge-fanout.sh b/t/t3311-notes-merge-fanout.sh
index 5b675417e9..ce4144db0f 100755
--- a/t/t3311-notes-merge-fanout.sh
+++ b/t/t3311-notes-merge-fanout.sh
@@ -5,6 +5,7 @@
test_description='Test notes merging at various fanout levels'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
verify_notes () {
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index f92baad138..f171af3061 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -26,6 +26,7 @@ Initial setup:
touch file "conflict".
'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-rebase.sh
diff --git a/t/t3435-rebase-gpg-sign.sh b/t/t3435-rebase-gpg-sign.sh
index 6aa2aeb628..6e329fea7c 100755
--- a/t/t3435-rebase-gpg-sign.sh
+++ b/t/t3435-rebase-gpg-sign.sh
@@ -8,6 +8,7 @@ test_description='test rebase --[no-]gpg-sign'
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-rebase.sh"
. "$TEST_DIRECTORY/lib-gpg.sh"
diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh
index f3947b400a..10e9c91dbb 100755
--- a/t/t3507-cherry-pick-conflict.sh
+++ b/t/t3507-cherry-pick-conflict.sh
@@ -13,6 +13,7 @@ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_CREATE_REPO_NO_TEMPLATE=1
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
pristine_detach () {
diff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh
index 7eb52b12ed..93c725bac3 100755
--- a/t/t3510-cherry-pick-sequence.sh
+++ b/t/t3510-cherry-pick-sequence.sh
@@ -12,6 +12,7 @@ test_description='Test cherry-pick continuation features
'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# Repeat first match 10 times
diff --git a/t/t3705-add-sparse-checkout.sh b/t/t3705-add-sparse-checkout.sh
index 2bade9e804..6ae45a788d 100755
--- a/t/t3705-add-sparse-checkout.sh
+++ b/t/t3705-add-sparse-checkout.sh
@@ -2,6 +2,7 @@
test_description='git add in sparse checked out working trees'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
SPARSE_ENTRY_BLOB=""
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index 3855d68dbc..87d248d034 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -8,6 +8,7 @@ test_description='Various diff formatting options'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-diff.sh
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 884f83fb8a..1c46e963e4 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -8,6 +8,7 @@ test_description='various format-patch tests'
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/t4018-diff-funcname.sh b/t/t4018-diff-funcname.sh
index e026fac1f4..8128c30e7f 100755
--- a/t/t4018-diff-funcname.sh
+++ b/t/t4018-diff-funcname.sh
@@ -5,6 +5,7 @@
test_description='Test custom diff function name patterns'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t4030-diff-textconv.sh b/t/t4030-diff-textconv.sh
index a39a626664..29f6d610c2 100755
--- a/t/t4030-diff-textconv.sh
+++ b/t/t4030-diff-textconv.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='diff.*.textconv tests'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
find_diff() {
diff --git a/t/t4042-diff-textconv-caching.sh b/t/t4042-diff-textconv-caching.sh
index 8ebfa3c1be..a179205394 100755
--- a/t/t4042-diff-textconv-caching.sh
+++ b/t/t4042-diff-textconv-caching.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='test textconv caching'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
cat >helper <<'EOF'
diff --git a/t/t4048-diff-combined-binary.sh b/t/t4048-diff-combined-binary.sh
index 0260cf64f5..f399484bce 100755
--- a/t/t4048-diff-combined-binary.sh
+++ b/t/t4048-diff-combined-binary.sh
@@ -4,6 +4,7 @@ test_description='combined and merge diff handle binary files and textconv'
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 binary merge conflict' '
diff --git a/t/t4064-diff-oidfind.sh b/t/t4064-diff-oidfind.sh
index 6d8c8986fc..846f285f77 100755
--- a/t/t4064-diff-oidfind.sh
+++ b/t/t4064-diff-oidfind.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='test finding specific blobs in the revision walking'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup ' '
diff --git a/t/t4065-diff-anchored.sh b/t/t4065-diff-anchored.sh
index b3f510f040..647537c12e 100755
--- a/t/t4065-diff-anchored.sh
+++ b/t/t4065-diff-anchored.sh
@@ -2,6 +2,7 @@
test_description='anchored diff algorithm'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success '--anchored' '
diff --git a/t/t4068-diff-symmetric-merge-base.sh b/t/t4068-diff-symmetric-merge-base.sh
index eff63c16b0..4d6565e728 100755
--- a/t/t4068-diff-symmetric-merge-base.sh
+++ b/t/t4068-diff-symmetric-merge-base.sh
@@ -5,6 +5,7 @@ test_description='behavior of diff with symmetric-diff setups 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
# build these situations:
diff --git a/t/t4069-remerge-diff.sh b/t/t4069-remerge-diff.sh
index 07323ebafe..df342850a0 100755
--- a/t/t4069-remerge-diff.sh
+++ b/t/t4069-remerge-diff.sh
@@ -2,6 +2,7 @@
test_description='remerge-diff handling'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
# This test is ort-specific
@@ -110,6 +111,41 @@ test_expect_success 'can filter out additional headers with pickaxe' '
test_must_be_empty actual
'
+test_expect_success 'remerge-diff also works for git-diff-tree' '
+ # With a clean merge
+ git diff-tree -r -p --remerge-diff --no-commit-id bc_resolution >actual &&
+ test_must_be_empty actual &&
+
+ # With both a resolved conflict and an unrelated change
+ cat <<-EOF >tmp &&
+ diff --git a/numbers b/numbers
+ remerge CONFLICT (content): Merge conflict in numbers
+ index a1fb731..6875544 100644
+ --- a/numbers
+ +++ b/numbers
+ @@ -1,13 +1,9 @@
+ 1
+ 2
+ -<<<<<<< b0ed5cb (change_a)
+ -three
+ -=======
+ -tres
+ ->>>>>>> 6cd3f82 (change_b)
+ +drei
+ 4
+ 5
+ 6
+ 7
+ -eight
+ +acht
+ 9
+ EOF
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >expect &&
+ git diff-tree -r -p --remerge-diff --no-commit-id ab_resolution >tmp &&
+ sed -e "s/[0-9a-f]\{7,\}/HASH/g" tmp >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'setup non-content conflicts' '
git switch --orphan base &&
diff --git a/t/t4108-apply-threeway.sh b/t/t4108-apply-threeway.sh
index c558282bc0..3211e1e65f 100755
--- a/t/t4108-apply-threeway.sh
+++ b/t/t4108-apply-threeway.sh
@@ -5,6 +5,7 @@ test_description='git apply --3way'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
print_sanitized_conflicted_diff () {
diff --git a/t/t4129-apply-samemode.sh b/t/t4129-apply-samemode.sh
index d9a1084b5e..87ffd2b8e1 100755
--- a/t/t4129-apply-samemode.sh
+++ b/t/t4129-apply-samemode.sh
@@ -153,8 +153,8 @@ test_expect_success POSIXPERM 'patch mode for new file is canonicalized' '
test_expect_success POSIXPERM 'patch mode for deleted file is canonicalized' '
test_when_finished "git reset --hard" &&
echo content >non-canon &&
- git add non-canon &&
chmod 666 non-canon &&
+ git add non-canon &&
cat >patch <<-\EOF &&
diff --git a/non-canon b/non-canon
diff --git a/t/t4209-log-pickaxe.sh b/t/t4209-log-pickaxe.sh
index 64e1623733..b42fdc54fc 100755
--- a/t/t4209-log-pickaxe.sh
+++ b/t/t4209-log-pickaxe.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='log --grep/--author/--regexp-ignore-case/-S/-G'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_log () {
diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh
index d7fd71360e..a6de7c5764 100755
--- a/t/t5310-pack-bitmaps.sh
+++ b/t/t5310-pack-bitmaps.sh
@@ -5,10 +5,6 @@ test_description='exercise basic bitmap functionality'
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-bitmap.sh
-# t5310 deals only with single-pack bitmaps, so don't write MIDX bitmaps in
-# their place.
-GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
-
# Likewise, allow individual tests to control whether or not they use
# the boundary-based traversal.
sane_unset GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL
diff --git a/t/t5313-pack-bounds-checks.sh b/t/t5313-pack-bounds-checks.sh
index ceaa6700a2..86fc73f9fb 100755
--- a/t/t5313-pack-bounds-checks.sh
+++ b/t/t5313-pack-bounds-checks.sh
@@ -7,11 +7,11 @@ TEST_PASSES_SANITIZE_LEAK=true
clear_base () {
test_when_finished 'restore_base' &&
- rm -f $base
+ rm -r -f $base
}
restore_base () {
- cp base-backup/* .git/objects/pack/
+ cp -r base-backup/* .git/objects/pack/
}
do_pack () {
@@ -64,9 +64,9 @@ test_expect_success 'set up base packfile and variables' '
git commit -m base &&
git repack -ad &&
base=$(echo .git/objects/pack/*) &&
- chmod +w $base &&
+ chmod -R +w $base &&
mkdir base-backup &&
- cp $base base-backup/ &&
+ cp -r $base base-backup/ &&
object=$(git rev-parse HEAD:file)
'
diff --git a/t/t5319-multi-pack-index.sh b/t/t5319-multi-pack-index.sh
index ace5ac3b61..ce1b58c732 100755
--- a/t/t5319-multi-pack-index.sh
+++ b/t/t5319-multi-pack-index.sh
@@ -3,8 +3,11 @@
test_description='multi-pack-indexes'
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-chunk.sh
+. "$TEST_DIRECTORY"/lib-midx.sh
GIT_TEST_MULTI_PACK_INDEX=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
objdir=.git/objects
HASH_LEN=$(test_oid rawsz)
@@ -107,30 +110,6 @@ test_expect_success 'write midx with one v1 pack' '
midx_read_expect 1 18 4 $objdir
'
-midx_git_two_modes () {
- git -c core.multiPackIndex=false $1 >expect &&
- git -c core.multiPackIndex=true $1 >actual &&
- if [ "$2" = "sorted" ]
- then
- sort <expect >expect.sorted &&
- mv expect.sorted expect &&
- sort <actual >actual.sorted &&
- mv actual.sorted actual
- fi &&
- test_cmp expect actual
-}
-
-compare_results_with_midx () {
- MSG=$1
- test_expect_success "check normal git operations: $MSG" '
- midx_git_two_modes "rev-list --objects --all" &&
- midx_git_two_modes "log --raw" &&
- midx_git_two_modes "count-objects --verbose" &&
- midx_git_two_modes "cat-file --batch-all-objects --batch-check" &&
- midx_git_two_modes "cat-file --batch-all-objects --batch-check --unordered" sorted
- '
-}
-
test_expect_success 'write midx with one v2 pack' '
git pack-objects --index-version=2,0x40 $objdir/pack/test <obj-list &&
git multi-pack-index --object-dir=$objdir write &&
@@ -600,8 +579,7 @@ test_expect_success 'repack preserves multi-pack-index when creating packs' '
compare_results_with_midx "after repack"
test_expect_success 'multi-pack-index and pack-bitmap' '
- GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
- git -c repack.writeBitmaps=true repack -ad &&
+ git -c repack.writeBitmaps=true repack -ad &&
git multi-pack-index write &&
git rev-list --test-bitmap HEAD
'
diff --git a/t/t5326-multi-pack-bitmaps.sh b/t/t5326-multi-pack-bitmaps.sh
index 916da389b6..832b92619c 100755
--- a/t/t5326-multi-pack-bitmaps.sh
+++ b/t/t5326-multi-pack-bitmaps.sh
@@ -4,10 +4,10 @@ test_description='exercise basic multi-pack bitmap functionality'
. ./test-lib.sh
. "${TEST_DIRECTORY}/lib-bitmap.sh"
-# We'll be writing our own midx and bitmaps, so avoid getting confused by the
+# We'll be writing our own MIDX, so avoid getting confused by the
# automatic ones.
GIT_TEST_MULTI_PACK_INDEX=0
-GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
# This test exercise multi-pack bitmap functionality where the object order is
# stored and read from a special chunk within the MIDX, so use the default
diff --git a/t/t5327-multi-pack-bitmaps-rev.sh b/t/t5327-multi-pack-bitmaps-rev.sh
index e65e311cd7..9cac03a94b 100755
--- a/t/t5327-multi-pack-bitmaps-rev.sh
+++ b/t/t5327-multi-pack-bitmaps-rev.sh
@@ -5,10 +5,10 @@ test_description='exercise basic multi-pack bitmap functionality (.rev files)'
. ./test-lib.sh
. "${TEST_DIRECTORY}/lib-bitmap.sh"
-# We'll be writing our own midx and bitmaps, so avoid getting confused by the
-# automatic ones.
+# We'll be writing our own MIDX, so avoid getting confused by the automatic
+# ones.
GIT_TEST_MULTI_PACK_INDEX=0
-GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
# Unlike t5326, this test exercise multi-pack bitmap functionality where the
# object order is stored in a separate .rev file.
diff --git a/t/t5332-multi-pack-reuse.sh b/t/t5332-multi-pack-reuse.sh
index ed823f37bc..941e73d354 100755
--- a/t/t5332-multi-pack-reuse.sh
+++ b/t/t5332-multi-pack-reuse.sh
@@ -6,6 +6,8 @@ TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-bitmap.sh
+GIT_TEST_MULTI_PACK_INDEX=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
objdir=.git/objects
packdir=$objdir/pack
diff --git a/t/t5334-incremental-multi-pack-index.sh b/t/t5334-incremental-multi-pack-index.sh
new file mode 100755
index 0000000000..c3b08acc73
--- /dev/null
+++ b/t/t5334-incremental-multi-pack-index.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+test_description='incremental multi-pack-index'
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-midx.sh
+
+GIT_TEST_MULTI_PACK_INDEX=0
+export GIT_TEST_MULTI_PACK_INDEX
+
+objdir=.git/objects
+packdir=$objdir/pack
+midxdir=$packdir/multi-pack-index.d
+midx_chain=$midxdir/multi-pack-index-chain
+
+test_expect_success 'convert non-incremental MIDX to incremental' '
+ test_commit base &&
+ git repack -ad &&
+ git multi-pack-index write &&
+
+ test_path_is_file $packdir/multi-pack-index &&
+ old_hash="$(midx_checksum $objdir)" &&
+
+ test_commit other &&
+ git repack -d &&
+ git multi-pack-index write --incremental &&
+
+ test_path_is_missing $packdir/multi-pack-index &&
+ test_path_is_file $midx_chain &&
+ test_line_count = 2 $midx_chain &&
+ grep $old_hash $midx_chain
+'
+
+compare_results_with_midx 'incremental MIDX'
+
+test_expect_success 'convert incremental to non-incremental' '
+ test_commit squash &&
+ git repack -d &&
+ git multi-pack-index write &&
+
+ test_path_is_file $packdir/multi-pack-index &&
+ test_dir_is_empty $midxdir
+'
+
+compare_results_with_midx 'non-incremental MIDX conversion'
+
+test_done
diff --git a/t/t5509-fetch-push-namespaces.sh b/t/t5509-fetch-push-namespaces.sh
index 31553b48df..05090feaf9 100755
--- a/t/t5509-fetch-push-namespaces.sh
+++ b/t/t5509-fetch-push-namespaces.sh
@@ -4,6 +4,7 @@ test_description='fetch/push involving ref namespaces'
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/t5523-push-upstream.sh b/t/t5523-push-upstream.sh
index 1f859ade16..4ad36a31e1 100755
--- a/t/t5523-push-upstream.sh
+++ b/t/t5523-push-upstream.sh
@@ -124,14 +124,14 @@ test_expect_success TTY 'push --no-progress suppresses progress' '
test_expect_success TTY 'quiet push' '
ensure_fresh_upstream &&
- test_terminal git push --quiet --no-progress upstream main 2>&1 | tee output &&
+ test_terminal git push --quiet --no-progress upstream main >output 2>&1 &&
test_must_be_empty output
'
test_expect_success TTY 'quiet push -u' '
ensure_fresh_upstream &&
- test_terminal git push --quiet -u --no-progress upstream main 2>&1 | tee output &&
+ test_terminal git push --quiet -u --no-progress upstream main >output 2>&1 &&
test_must_be_empty output
'
diff --git a/t/t5572-pull-submodule.sh b/t/t5572-pull-submodule.sh
index 51744521f7..916e58c166 100755
--- a/t/t5572-pull-submodule.sh
+++ b/t/t5572-pull-submodule.sh
@@ -5,6 +5,7 @@ test_description='pull can handle submodules'
GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1
export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-submodule-update.sh
diff --git a/t/t5802-connect-helper.sh b/t/t5802-connect-helper.sh
index c6c2661878..dd3e6235cd 100755
--- a/t/t5802-connect-helper.sh
+++ b/t/t5802-connect-helper.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='ext::cmd remote "connect" helper'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success setup '
diff --git a/t/t5814-proto-disable-ext.sh b/t/t5814-proto-disable-ext.sh
index 9d6f7dfa2c..6fe1a98b2a 100755
--- a/t/t5814-proto-disable-ext.sh
+++ b/t/t5814-proto-disable-ext.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='test disabling of remote-helper paths in clone/fetch'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY/lib-proto-disable.sh"
diff --git a/t/t5815-submodule-protos.sh b/t/t5815-submodule-protos.sh
index 4d5956cc18..fe899ee82d 100755
--- a/t/t5815-submodule-protos.sh
+++ b/t/t5815-submodule-protos.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='test protocol filtering with submodules'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-proto-disable.sh
diff --git a/t/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh
index fe75a06572..34b5cd62c2 100755
--- a/t/t6020-bundle-misc.sh
+++ b/t/t6020-bundle-misc.sh
@@ -652,4 +652,36 @@ test_expect_success 'send a bundle to standard output' '
test_cmp expect actual
'
+test_expect_success 'unbundle outside of a repository' '
+ git bundle create some.bundle HEAD &&
+ echo "fatal: Need a repository to unbundle." >expect &&
+ nongit test_must_fail git bundle unbundle "$(pwd)/some.bundle" 2>err &&
+ test_cmp expect err
+'
+
+test_expect_success 'list-heads outside of a repository' '
+ git bundle create some.bundle HEAD &&
+ cat >expect <<-EOF &&
+ $(git rev-parse HEAD) HEAD
+ EOF
+ nongit git bundle list-heads "$(pwd)/some.bundle" >actual &&
+ test_cmp expect actual
+'
+
+for hash in sha1 sha256
+do
+ test_expect_success "list-heads with bundle using $hash" '
+ test_when_finished "rm -rf hash" &&
+ git init --object-format=$hash hash &&
+ test_commit -C hash initial &&
+ git -C hash bundle create hash.bundle HEAD &&
+
+ cat >expect <<-EOF &&
+ $(git -C hash rev-parse HEAD) HEAD
+ EOF
+ git bundle list-heads hash/hash.bundle >actual &&
+ test_cmp expect actual
+ '
+done
+
test_done
diff --git a/t/t6421-merge-partial-clone.sh b/t/t6421-merge-partial-clone.sh
index b99f29ef9b..30349a466e 100755
--- a/t/t6421-merge-partial-clone.sh
+++ b/t/t6421-merge-partial-clone.sh
@@ -26,6 +26,7 @@ test_description="limiting blob downloads when merging with partial clones"
# underscore notation is to differentiate different
# files that might be renamed into each other's paths.)
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-merge.sh
diff --git a/t/t6428-merge-conflicts-sparse.sh b/t/t6428-merge-conflicts-sparse.sh
index 9919c3fa7c..8a79bc2e92 100755
--- a/t/t6428-merge-conflicts-sparse.sh
+++ b/t/t6428-merge-conflicts-sparse.sh
@@ -22,6 +22,7 @@ test_description="merge cases"
# underscore notation is to differentiate different
# files that might be renamed into each other's paths.)
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-merge.sh
diff --git a/t/t7004-tag.sh b/t/t7004-tag.sh
index fa6336edf9..b1316e62f4 100755
--- a/t/t7004-tag.sh
+++ b/t/t7004-tag.sh
@@ -61,8 +61,9 @@ test_expect_success 'sort tags, ignore case' '
)
'
-test_expect_success 'looking for a tag in an empty tree should fail' \
- '! (tag_exists mytag)'
+test_expect_success 'looking for a tag in an empty tree should fail' '
+ ! (tag_exists mytag)
+'
test_expect_success 'creating a tag in an empty tree should fail' '
test_must_fail git tag mynotag &&
@@ -129,10 +130,10 @@ test_expect_success 'listing all tags if one exists should succeed' '
git tag
'
-cat >expect <<EOF
-mytag
-EOF
test_expect_success 'Multiple -l or --list options are equivalent to one -l option' '
+ cat >expect <<-\EOF &&
+ mytag
+ EOF
git tag -l -l >actual &&
test_cmp expect actual &&
git tag --list --list >actual &&
@@ -148,32 +149,33 @@ test_expect_success 'listing all tags if one exists should output that tag' '
# pattern matching:
-test_expect_success 'listing a tag using a matching pattern should succeed' \
- 'git tag -l mytag'
+test_expect_success 'listing a tag using a matching pattern should succeed' '
+ git tag -l mytag
+'
-test_expect_success 'listing a tag with --ignore-case' \
- 'test $(git tag -l --ignore-case MYTAG) = mytag'
+test_expect_success 'listing a tag with --ignore-case' '
+ test $(git tag -l --ignore-case MYTAG) = mytag
+'
-test_expect_success \
- 'listing a tag using a matching pattern should output that tag' \
- 'test $(git tag -l mytag) = mytag'
+test_expect_success 'listing a tag using a matching pattern should output that tag' '
+ test $(git tag -l mytag) = mytag
+'
-test_expect_success \
- 'listing tags using a non-matching pattern should succeed' \
- 'git tag -l xxx'
+test_expect_success 'listing tags using a non-matching pattern should succeed' '
+ git tag -l xxx
+'
-test_expect_success \
- 'listing tags using a non-matching pattern should output nothing' \
- 'test $(git tag -l xxx | wc -l) -eq 0'
+test_expect_success 'listing tags using a non-matching pattern should output nothing' '
+ test $(git tag -l xxx | wc -l) -eq 0
+'
# special cases for creating tags:
-test_expect_success \
- 'trying to create a tag with the name of one existing should fail' \
- 'test_must_fail git tag mytag'
+test_expect_success 'trying to create a tag with the name of one existing should fail' '
+ test_must_fail git tag mytag
+'
-test_expect_success \
- 'trying to create a tag with a non-valid name should fail' '
+test_expect_success 'trying to create a tag with a non-valid name should fail' '
test $(git tag -l | wc -l) -eq 1 &&
test_must_fail git tag "" &&
test_must_fail git tag .othertag &&
@@ -207,19 +209,19 @@ test_expect_success 'trying to delete an unknown tag should fail' '
test_must_fail git tag -d unknown-tag
'
-cat >expect <<EOF
-myhead
-mytag
-EOF
-test_expect_success \
- 'trying to delete tags without params should succeed and do nothing' '
- git tag -l > actual && test_cmp expect actual &&
+test_expect_success 'trying to delete tags without params should succeed and do nothing' '
+ cat >expect <<-\EOF &&
+ myhead
+ mytag
+ EOF
+ git tag -l >actual &&
+ test_cmp expect actual &&
git tag -d &&
- git tag -l > actual && test_cmp expect actual
+ git tag -l >actual &&
+ test_cmp expect actual
'
-test_expect_success \
- 'deleting two existing tags in one command should succeed' '
+test_expect_success 'deleting two existing tags in one command should succeed' '
tag_exists mytag &&
tag_exists myhead &&
git tag -d mytag myhead &&
@@ -227,15 +229,13 @@ test_expect_success \
! tag_exists myhead
'
-test_expect_success \
- 'creating a tag with the name of another deleted one should succeed' '
+test_expect_success 'creating a tag with the name of another deleted one should succeed' '
! tag_exists mytag &&
git tag mytag &&
tag_exists mytag
'
-test_expect_success \
- 'trying to delete two tags, existing and not, should fail in the 2nd' '
+test_expect_success 'trying to delete two tags, existing and not, should fail in the 2nd' '
tag_exists mytag &&
! tag_exists nonexistingtag &&
test_must_fail git tag -d mytag nonexistingtag &&
@@ -243,23 +243,24 @@ test_expect_success \
! tag_exists nonexistingtag
'
-test_expect_success 'trying to delete an already deleted tag should fail' \
- 'test_must_fail git tag -d mytag'
+test_expect_success 'trying to delete an already deleted tag should fail' '
+ test_must_fail git tag -d mytag
+'
# listing various tags with pattern matching:
-cat >expect <<EOF
-a1
-aa1
-cba
-t210
-t211
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-EOF
test_expect_success 'listing all tags should print them ordered' '
+ cat >expect <<-\EOF &&
+ a1
+ aa1
+ cba
+ t210
+ t211
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ EOF
git tag v1.0.1 &&
git tag t211 &&
git tag aa1 &&
@@ -269,91 +270,89 @@ test_expect_success 'listing all tags should print them ordered' '
git tag a1 &&
git tag v1.0 &&
git tag t210 &&
- git tag -l > actual &&
+ git tag -l >actual &&
test_cmp expect actual &&
- git tag > actual &&
+ git tag >actual &&
test_cmp expect actual
'
-cat >expect <<EOF
-a1
-aa1
-cba
-EOF
-test_expect_success \
- 'listing tags with substring as pattern must print those matching' '
+test_expect_success 'listing tags with substring as pattern must print those matching' '
+ cat >expect <<-\EOF &&
+ a1
+ aa1
+ cba
+ EOF
rm *a* &&
- git tag -l "*a*" > current &&
+ git tag -l "*a*" >current &&
test_cmp expect current
'
-cat >expect <<EOF
-v0.2.1
-v1.0.1
-EOF
-test_expect_success \
- 'listing tags with a suffix as pattern must print those matching' '
- git tag -l "*.1" > actual &&
+test_expect_success 'listing tags with a suffix as pattern must print those matching' '
+ cat >expect <<-\EOF &&
+ v0.2.1
+ v1.0.1
+ EOF
+ git tag -l "*.1" >actual &&
test_cmp expect actual
'
-cat >expect <<EOF
-t210
-t211
-EOF
-test_expect_success \
- 'listing tags with a prefix as pattern must print those matching' '
- git tag -l "t21*" > actual &&
+test_expect_success 'listing tags with a prefix as pattern must print those matching' '
+ cat >expect <<-\EOF &&
+ t210
+ t211
+ EOF
+ git tag -l "t21*" >actual &&
test_cmp expect actual
'
-cat >expect <<EOF
-a1
-EOF
-test_expect_success \
- 'listing tags using a name as pattern must print that one matching' '
- git tag -l a1 > actual &&
+test_expect_success 'listing tags using a name as pattern must print that one matching' '
+ cat >expect <<-\EOF &&
+ a1
+ EOF
+ git tag -l a1 >actual &&
test_cmp expect actual
'
-cat >expect <<EOF
-v1.0
-EOF
-test_expect_success \
- 'listing tags using a name as pattern must print that one matching' '
- git tag -l v1.0 > actual &&
+test_expect_success 'listing tags using a name as pattern must print that one matching' '
+ cat >expect <<-\EOF &&
+ v1.0
+ EOF
+ git tag -l v1.0 >actual &&
test_cmp expect actual
'
-cat >expect <<EOF
-v1.0.1
-v1.1.3
-EOF
-test_expect_success \
- 'listing tags with ? in the pattern should print those matching' '
- git tag -l "v1.?.?" > actual &&
+test_expect_success 'listing tags with ? in the pattern should print those matching' '
+ cat >expect <<-\EOF &&
+ v1.0.1
+ v1.1.3
+ EOF
+ git tag -l "v1.?.?" >actual &&
test_cmp expect actual
'
-test_expect_success \
- 'listing tags using v.* should print nothing because none have v.' '
- git tag -l "v.*" > actual &&
+test_expect_success 'listing tags using v.* should print nothing because none have v.' '
+ git tag -l "v.*" >actual &&
test_must_be_empty actual
'
-cat >expect <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-EOF
-test_expect_success \
- 'listing tags using v* should print only those having v' '
- git tag -l "v*" > actual &&
+test_expect_success 'listing tags using v* should print only those having v' '
+ cat >expect <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ EOF
+ git tag -l "v*" >actual &&
test_cmp expect actual
'
test_expect_success 'tag -l can accept multiple patterns' '
+ cat >expect <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ EOF
git tag -l "v1*" "v0*" >actual &&
test_cmp expect actual
'
@@ -367,16 +366,22 @@ test_expect_success 'tag -l can accept multiple patterns' '
# out if we're going to break this long-documented form of taking
# multiple patterns.
test_expect_success 'tag -l <pattern> -l <pattern> works, as our buggy documentation previously suggested' '
+ cat >expect <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ EOF
git tag -l "v1*" -l "v0*" >actual &&
test_cmp expect actual
'
test_expect_success 'listing tags in column' '
COLUMNS=41 git tag -l --column=row >actual &&
- cat >expected <<\EOF &&
-a1 aa1 cba t210 t211
-v0.2.1 v1.0 v1.0.1 v1.1.3
-EOF
+ cat >expected <<-\EOF &&
+ a1 aa1 cba t210 t211
+ v0.2.1 v1.0 v1.0.1 v1.1.3
+ EOF
test_cmp expected actual
'
@@ -384,10 +389,10 @@ test_expect_success 'listing tags in column with column.*' '
test_config column.tag row &&
test_config column.ui dense &&
COLUMNS=40 git tag -l >actual &&
- cat >expected <<\EOF &&
-a1 aa1 cba t210 t211
-v0.2.1 v1.0 v1.0.1 v1.1.3
-EOF
+ cat >expected <<-\EOF &&
+ a1 aa1 cba t210 t211
+ v0.2.1 v1.0 v1.0.1 v1.1.3
+ EOF
test_cmp expected actual
'
@@ -398,39 +403,39 @@ test_expect_success 'listing tag with -n --column should fail' '
test_expect_success 'listing tags -n in column with column.ui ignored' '
test_config column.ui "row dense" &&
COLUMNS=40 git tag -l -n >actual &&
- cat >expected <<\EOF &&
-a1 Foo
-aa1 Foo
-cba Foo
-t210 Foo
-t211 Foo
-v0.2.1 Foo
-v1.0 Foo
-v1.0.1 Foo
-v1.1.3 Foo
-EOF
+ cat >expected <<-\EOF &&
+ a1 Foo
+ aa1 Foo
+ cba Foo
+ t210 Foo
+ t211 Foo
+ v0.2.1 Foo
+ v1.0 Foo
+ v1.0.1 Foo
+ v1.1.3 Foo
+ EOF
test_cmp expected actual
'
# creating and verifying lightweight tags:
-test_expect_success \
- 'a non-annotated tag created without parameters should point to HEAD' '
+test_expect_success 'a non-annotated tag created without parameters should point to HEAD' '
git tag non-annotated-tag &&
test $(git cat-file -t non-annotated-tag) = commit &&
test $(git rev-parse non-annotated-tag) = $(git rev-parse HEAD)
'
-test_expect_success 'trying to verify an unknown tag should fail' \
- 'test_must_fail git tag -v unknown-tag'
+test_expect_success 'trying to verify an unknown tag should fail' '
+ test_must_fail git tag -v unknown-tag
+'
-test_expect_success \
- 'trying to verify a non-annotated and non-signed tag should fail' \
- 'test_must_fail git tag -v non-annotated-tag'
+test_expect_success 'trying to verify a non-annotated and non-signed tag should fail' '
+ test_must_fail git tag -v non-annotated-tag
+'
-test_expect_success \
- 'trying to verify many non-annotated or unknown tags, should fail' \
- 'test_must_fail git tag -v unknown-tag1 non-annotated-tag unknown-tag2'
+test_expect_success 'trying to verify many non-annotated or unknown tags, should fail' '
+ test_must_fail git tag -v unknown-tag1 non-annotated-tag unknown-tag2
+'
# creating annotated tags:
@@ -449,83 +454,78 @@ tagger C O Mitter <committer@example.com> $4 -0700
EOF
}
-commit=$(git rev-parse HEAD)
-time=$test_tick
-
-get_tag_header annotated-tag $commit commit $time >expect
-echo "A message" >>expect
-test_expect_success \
- 'creating an annotated tag with -m message should succeed' '
+test_expect_success 'creating an annotated tag with -m message should succeed' '
+ commit=$(git rev-parse HEAD) &&
+ time=$test_tick &&
+ get_tag_header annotated-tag $commit commit $time >expect &&
+ echo "A message" >>expect &&
git tag -m "A message" annotated-tag &&
get_tag_msg annotated-tag >actual &&
test_cmp expect actual
'
-get_tag_header annotated-tag-edit $commit commit $time >expect
-echo "An edited message" >>expect
test_expect_success 'set up editor' '
write_script fakeeditor <<-\EOF
sed -e "s/A message/An edited message/g" <"$1" >"$1-"
mv "$1-" "$1"
EOF
'
-test_expect_success \
- 'creating an annotated tag with -m message --edit should succeed' '
+
+test_expect_success 'creating an annotated tag with -m message --edit should succeed' '
+ get_tag_header annotated-tag-edit $commit commit $time >expect &&
+ echo "An edited message" >>expect &&
GIT_EDITOR=./fakeeditor git tag -m "A message" --edit annotated-tag-edit &&
get_tag_msg annotated-tag-edit >actual &&
test_cmp expect actual
'
-cat >msgfile <<EOF
-Another message
-in a file.
-EOF
-get_tag_header file-annotated-tag $commit commit $time >expect
-cat msgfile >>expect
-test_expect_success \
- 'creating an annotated tag with -F messagefile should succeed' '
+test_expect_success 'creating an annotated tag with -F messagefile should succeed' '
+ cat >msgfile <<-\EOF &&
+ Another message
+ in a file.
+ EOF
+ get_tag_header file-annotated-tag $commit commit $time >expect &&
+ cat msgfile >>expect &&
git tag -F msgfile file-annotated-tag &&
get_tag_msg file-annotated-tag >actual &&
test_cmp expect actual
'
-get_tag_header file-annotated-tag-edit $commit commit $time >expect
-sed -e "s/Another message/Another edited message/g" msgfile >>expect
test_expect_success 'set up editor' '
write_script fakeeditor <<-\EOF
sed -e "s/Another message/Another edited message/g" <"$1" >"$1-"
mv "$1-" "$1"
EOF
'
-test_expect_success \
- 'creating an annotated tag with -F messagefile --edit should succeed' '
+
+test_expect_success 'creating an annotated tag with -F messagefile --edit should succeed' '
+ get_tag_header file-annotated-tag-edit $commit commit $time >expect &&
+ sed -e "s/Another message/Another edited message/g" msgfile >>expect &&
GIT_EDITOR=./fakeeditor git tag -F msgfile --edit file-annotated-tag-edit &&
get_tag_msg file-annotated-tag-edit >actual &&
test_cmp expect actual
'
-cat >inputmsg <<EOF
-A message from the
-standard input
-EOF
-get_tag_header stdin-annotated-tag $commit commit $time >expect
-cat inputmsg >>expect
test_expect_success 'creating an annotated tag with -F - should succeed' '
+ cat >inputmsg <<-\EOF &&
+ A message from the
+ standard input
+ EOF
+ get_tag_header stdin-annotated-tag $commit commit $time >expect &&
+ cat inputmsg >>expect &&
git tag -F - stdin-annotated-tag <inputmsg &&
get_tag_msg stdin-annotated-tag >actual &&
test_cmp expect actual
'
-test_expect_success \
- 'trying to create a tag with a non-existing -F file should fail' '
+test_expect_success 'trying to create a tag with a non-existing -F file should fail' '
! test -f nonexistingfile &&
! tag_exists notag &&
test_must_fail git tag -F nonexistingfile notag &&
! tag_exists notag
'
-test_expect_success \
- 'trying to create tags giving both -m or -F options should fail' '
+test_expect_success 'trying to create tags giving both -m or -F options should fail' '
echo "message file 1" >msgfile1 &&
! tag_exists msgtag &&
test_must_fail git tag -m "message 1" -F msgfile1 msgtag &&
@@ -539,67 +539,61 @@ test_expect_success \
# blank and empty messages:
-get_tag_header empty-annotated-tag $commit commit $time >expect
-test_expect_success \
- 'creating a tag with an empty -m message should succeed' '
+test_expect_success 'creating a tag with an empty -m message should succeed' '
+ get_tag_header empty-annotated-tag $commit commit $time >expect &&
git tag -m "" empty-annotated-tag &&
get_tag_msg empty-annotated-tag >actual &&
test_cmp expect actual
'
->emptyfile
-get_tag_header emptyfile-annotated-tag $commit commit $time >expect
-test_expect_success \
- 'creating a tag with an empty -F messagefile should succeed' '
+test_expect_success 'creating a tag with an empty -F messagefile should succeed' '
+ >emptyfile &&
+ get_tag_header emptyfile-annotated-tag $commit commit $time >expect &&
git tag -F emptyfile emptyfile-annotated-tag &&
get_tag_msg emptyfile-annotated-tag >actual &&
test_cmp expect actual
'
-printf '\n\n \n\t\nLeading blank lines\n' >blanksfile
-printf '\n\t \t \nRepeated blank lines\n' >>blanksfile
-printf '\n\n\nTrailing spaces \t \n' >>blanksfile
-printf '\nTrailing blank lines\n\n\t \n\n' >>blanksfile
-get_tag_header blanks-annotated-tag $commit commit $time >expect
-cat >>expect <<EOF
-Leading blank lines
+test_expect_success 'extra blanks in the message for an annotated tag should be removed' '
+ printf "\n\n \n\t\nLeading blank lines\n" >blanksfile &&
+ printf "\n\t \t \nRepeated blank lines\n" >>blanksfile &&
+ printf "\n\n\nTrailing spaces \t \n" >>blanksfile &&
+ printf "\nTrailing blank lines\n\n\t \n\n" >>blanksfile &&
+ get_tag_header blanks-annotated-tag $commit commit $time >expect &&
+ cat >>expect <<-\EOF &&
+ Leading blank lines
-Repeated blank lines
+ Repeated blank lines
-Trailing spaces
+ Trailing spaces
-Trailing blank lines
-EOF
-test_expect_success \
- 'extra blanks in the message for an annotated tag should be removed' '
+ Trailing blank lines
+ EOF
git tag -F blanksfile blanks-annotated-tag &&
get_tag_msg blanks-annotated-tag >actual &&
test_cmp expect actual
'
-get_tag_header blank-annotated-tag $commit commit $time >expect
-test_expect_success \
- 'creating a tag with blank -m message with spaces should succeed' '
+test_expect_success 'creating a tag with blank -m message with spaces should succeed' '
+ get_tag_header blank-annotated-tag $commit commit $time >expect &&
git tag -m " " blank-annotated-tag &&
get_tag_msg blank-annotated-tag >actual &&
test_cmp expect actual
'
-echo ' ' >blankfile
-echo '' >>blankfile
-echo ' ' >>blankfile
-get_tag_header blankfile-annotated-tag $commit commit $time >expect
-test_expect_success \
- 'creating a tag with blank -F messagefile with spaces should succeed' '
+test_expect_success 'creating a tag with blank -F messagefile with spaces should succeed' '
+ echo " " >blankfile &&
+ echo "" >>blankfile &&
+ echo " " >>blankfile &&
+ get_tag_header blankfile-annotated-tag $commit commit $time >expect &&
git tag -F blankfile blankfile-annotated-tag &&
get_tag_msg blankfile-annotated-tag >actual &&
test_cmp expect actual
'
-printf ' ' >blanknonlfile
-get_tag_header blanknonlfile-annotated-tag $commit commit $time >expect
-test_expect_success \
- 'creating a tag with -F file of spaces and no newline should succeed' '
+test_expect_success 'creating a tag with -F file of spaces and no newline should succeed' '
+ printf " " >blanknonlfile &&
+ get_tag_header blanknonlfile-annotated-tag $commit commit $time >expect &&
git tag -F blanknonlfile blanknonlfile-annotated-tag &&
get_tag_msg blanknonlfile-annotated-tag >actual &&
test_cmp expect actual
@@ -607,62 +601,58 @@ test_expect_success \
# messages with commented lines:
-cat >commentsfile <<EOF
-# A comment
+test_expect_success 'creating a tag using a -F messagefile with #comments should succeed' '
+ cat >commentsfile <<-\EOF &&
+ # A comment
-############
-The message.
-############
-One line.
+ ############
+ The message.
+ ############
+ One line.
-# commented lines
-# commented lines
+ # commented lines
+ # commented lines
-Another line.
-# comments
+ Another line.
+ # comments
-Last line.
-EOF
-get_tag_header comments-annotated-tag $commit commit $time >expect
-cat >>expect <<EOF
-The message.
-One line.
+ Last line.
+ EOF
+ get_tag_header comments-annotated-tag $commit commit $time >expect &&
+ cat >>expect <<-\EOF &&
+ The message.
+ One line.
-Another line.
+ Another line.
-Last line.
-EOF
-test_expect_success \
- 'creating a tag using a -F messagefile with #comments should succeed' '
+ Last line.
+ EOF
git tag -F commentsfile comments-annotated-tag &&
get_tag_msg comments-annotated-tag >actual &&
test_cmp expect actual
'
-get_tag_header comment-annotated-tag $commit commit $time >expect
-test_expect_success \
- 'creating a tag with a #comment in the -m message should succeed' '
+test_expect_success 'creating a tag with a #comment in the -m message should succeed' '
+ get_tag_header comment-annotated-tag $commit commit $time >expect &&
git tag -m "#comment" comment-annotated-tag &&
get_tag_msg comment-annotated-tag >actual &&
test_cmp expect actual
'
-echo '#comment' >commentfile
-echo '' >>commentfile
-echo '####' >>commentfile
-get_tag_header commentfile-annotated-tag $commit commit $time >expect
-test_expect_success \
- 'creating a tag with #comments in the -F messagefile should succeed' '
+test_expect_success 'creating a tag with #comments in the -F messagefile should succeed' '
+ echo "#comment" >commentfile &&
+ echo "" >>commentfile &&
+ echo "####" >>commentfile &&
+ get_tag_header commentfile-annotated-tag $commit commit $time >expect &&
git tag -F commentfile commentfile-annotated-tag &&
get_tag_msg commentfile-annotated-tag >actual &&
test_cmp expect actual
'
-printf '#comment' >commentnonlfile
-get_tag_header commentnonlfile-annotated-tag $commit commit $time >expect
-test_expect_success \
- 'creating a tag with a file of #comment and no newline should succeed' '
+test_expect_success 'creating a tag with a file of #comment and no newline should succeed' '
+ printf "#comment" >commentnonlfile &&
+ get_tag_header commentnonlfile-annotated-tag $commit commit $time >expect &&
git tag -F commentnonlfile commentnonlfile-annotated-tag &&
get_tag_msg commentnonlfile-annotated-tag >actual &&
test_cmp expect actual
@@ -779,8 +769,7 @@ test_expect_success 'bad editor causes panic when only --trailer is given' '
# listing messages for annotated non-signed tags:
-test_expect_success \
- 'listing the one-line message of a non-signed tag should succeed' '
+test_expect_success 'listing the one-line message of a non-signed tag should succeed' '
git tag -m "A msg" tag-one-line &&
echo "tag-one-line" >expect &&
@@ -819,8 +808,7 @@ test_expect_success 'The -n 100 invocation means -n --list 100, not -n100' '
test_cmp expect actual
'
-test_expect_success \
- 'listing the zero-lines message of a non-signed tag should succeed' '
+test_expect_success 'listing the zero-lines message of a non-signed tag should succeed' '
git tag -m "" tag-zero-lines &&
echo "tag-zero-lines" >expect &&
@@ -844,11 +832,10 @@ test_expect_success \
test_cmp expect actual
'
-echo 'tag line one' >annotagmsg
-echo 'tag line two' >>annotagmsg
-echo 'tag line three' >>annotagmsg
-test_expect_success \
- 'listing many message lines of a non-signed tag should succeed' '
+test_expect_success 'listing many message lines of a non-signed tag should succeed' '
+ echo "tag line one" >annotagmsg &&
+ echo "tag line two" >>annotagmsg &&
+ echo "tag line three" >>annotagmsg &&
git tag -F annotagmsg tag-lines &&
echo "tag-lines" >expect &&
@@ -936,40 +923,37 @@ test_expect_success 'git tag --format with ahead-behind' '
# trying to verify annotated non-signed tags:
-test_expect_success GPG \
- 'trying to verify an annotated non-signed tag should fail' '
+test_expect_success GPG 'trying to verify an annotated non-signed tag should fail' '
tag_exists annotated-tag &&
test_must_fail git tag -v annotated-tag
'
-test_expect_success GPG \
- 'trying to verify a file-annotated non-signed tag should fail' '
+test_expect_success GPG 'trying to verify a file-annotated non-signed tag should fail' '
tag_exists file-annotated-tag &&
test_must_fail git tag -v file-annotated-tag
'
-test_expect_success GPG \
- 'trying to verify two annotated non-signed tags should fail' '
+test_expect_success GPG 'trying to verify two annotated non-signed tags should fail' '
tag_exists annotated-tag file-annotated-tag &&
test_must_fail git tag -v annotated-tag file-annotated-tag
'
# creating and verifying signed tags:
-get_tag_header signed-tag $commit commit $time >expect
-echo 'A signed tag message' >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG 'creating a signed tag with -m message should succeed' '
+ get_tag_header signed-tag $commit commit $time >expect &&
+ echo "A signed tag message" >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -m "A signed tag message" signed-tag &&
get_tag_msg signed-tag >actual &&
test_cmp expect actual
'
-get_tag_header u-signed-tag $commit commit $time >expect
-echo 'Another message' >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG 'sign with a given key id' '
+ get_tag_header u-signed-tag $commit commit $time >expect &&
+ echo "Another message" >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -u committer@example.com -m "Another message" u-signed-tag &&
get_tag_msg u-signed-tag >actual &&
test_cmp expect actual
@@ -989,137 +973,128 @@ test_expect_success GPG 'sign with an unknown id (2)' '
'
-cat >fakeeditor <<'EOF'
-#!/bin/sh
-test -n "$1" && exec >"$1"
-echo A signed tag message
-echo from a fake editor.
-EOF
-chmod +x fakeeditor
-
-get_tag_header implied-sign $commit commit $time >expect
-./fakeeditor >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG '-u implies signed tag' '
+ write_script fakeeditor <<-\EOF &&
+ test -n "$1" && exec >"$1"
+ echo A signed tag message
+ echo from a fake editor.
+ EOF
+
+ get_tag_header implied-sign $commit commit $time >expect &&
+ ./fakeeditor >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
GIT_EDITOR=./fakeeditor git tag -u CDDE430D implied-sign &&
get_tag_msg implied-sign >actual &&
test_cmp expect actual
'
-cat >sigmsgfile <<EOF
-Another signed tag
-message in a file.
-EOF
-get_tag_header file-signed-tag $commit commit $time >expect
-cat sigmsgfile >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with -F messagefile should succeed' '
+test_expect_success GPG 'creating a signed tag with -F messagefile should succeed' '
+ cat >sigmsgfile <<-\EOF &&
+ Another signed tag
+ message in a file.
+ EOF
+ get_tag_header file-signed-tag $commit commit $time >expect &&
+ cat sigmsgfile >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -F sigmsgfile file-signed-tag &&
get_tag_msg file-signed-tag >actual &&
test_cmp expect actual
'
-cat >siginputmsg <<EOF
-A signed tag message from
-the standard input
-EOF
-get_tag_header stdin-signed-tag $commit commit $time >expect
-cat siginputmsg >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG 'creating a signed tag with -F - should succeed' '
+ cat >siginputmsg <<-\EOF &&
+ A signed tag message from
+ the standard input
+ EOF
+ get_tag_header stdin-signed-tag $commit commit $time >expect &&
+ cat siginputmsg >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -F - stdin-signed-tag <siginputmsg &&
get_tag_msg stdin-signed-tag >actual &&
test_cmp expect actual
'
-get_tag_header implied-annotate $commit commit $time >expect
-./fakeeditor >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG '-s implies annotated tag' '
+ get_tag_header implied-annotate $commit commit $time >expect &&
+ ./fakeeditor >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
GIT_EDITOR=./fakeeditor git tag -s implied-annotate &&
get_tag_msg implied-annotate >actual &&
test_cmp expect actual
'
-get_tag_header forcesignannotated-implied-sign $commit commit $time >expect
-echo "A message" >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'git tag -s implied if configured with tag.forcesignannotated' \
- 'test_config tag.forcesignannotated true &&
+test_expect_success GPG 'git tag -s implied if configured with tag.forcesignannotated' '
+ get_tag_header forcesignannotated-implied-sign $commit commit $time >expect &&
+ echo "A message" >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
+ test_config tag.forcesignannotated true &&
git tag -m "A message" forcesignannotated-implied-sign &&
get_tag_msg forcesignannotated-implied-sign >actual &&
test_cmp expect actual
'
-test_expect_success GPG \
- 'lightweight with no message when configured with tag.forcesignannotated' \
- 'test_config tag.forcesignannotated true &&
+test_expect_success GPG 'lightweight with no message when configured with tag.forcesignannotated' '
+ test_config tag.forcesignannotated true &&
git tag forcesignannotated-lightweight &&
tag_exists forcesignannotated-lightweight &&
test_must_fail git tag -v forcesignannotated-no-message
'
-get_tag_header forcesignannotated-annotate $commit commit $time >expect
-echo "A message" >>expect
-test_expect_success GPG \
- 'git tag -a disable configured tag.forcesignannotated' \
- 'test_config tag.forcesignannotated true &&
+test_expect_success GPG 'git tag -a disable configured tag.forcesignannotated' '
+ get_tag_header forcesignannotated-annotate $commit commit $time >expect &&
+ echo "A message" >>expect &&
+ test_config tag.forcesignannotated true &&
git tag -a -m "A message" forcesignannotated-annotate &&
get_tag_msg forcesignannotated-annotate >actual &&
test_cmp expect actual &&
test_must_fail git tag -v forcesignannotated-annotate
'
-get_tag_header forcesignannotated-disabled $commit commit $time >expect
-echo "A message" >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'git tag --sign enable GPG sign' \
- 'test_config tag.forcesignannotated false &&
+test_expect_success GPG 'git tag --sign enable GPG sign' '
+ get_tag_header forcesignannotated-disabled $commit commit $time >expect &&
+ echo "A message" >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
+ test_config tag.forcesignannotated false &&
git tag --sign -m "A message" forcesignannotated-disabled &&
get_tag_msg forcesignannotated-disabled >actual &&
test_cmp expect actual
'
-get_tag_header gpgsign-enabled $commit commit $time >expect
-echo "A message" >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'git tag configured tag.gpgsign enables GPG sign' \
- 'test_config tag.gpgsign true &&
+test_expect_success GPG 'git tag configured tag.gpgsign enables GPG sign' '
+ get_tag_header gpgsign-enabled $commit commit $time >expect &&
+ echo "A message" >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
+ test_config tag.gpgsign true &&
git tag -m "A message" gpgsign-enabled &&
get_tag_msg gpgsign-enabled>actual &&
test_cmp expect actual
'
-get_tag_header no-sign $commit commit $time >expect
-echo "A message" >>expect
-test_expect_success GPG \
- 'git tag --no-sign configured tag.gpgsign skip GPG sign' \
- 'test_config tag.gpgsign true &&
+test_expect_success GPG 'git tag --no-sign configured tag.gpgsign skip GPG sign' '
+ get_tag_header no-sign $commit commit $time >expect &&
+ echo "A message" >>expect &&
+ test_config tag.gpgsign true &&
git tag -a --no-sign -m "A message" no-sign &&
get_tag_msg no-sign>actual &&
test_cmp expect actual
'
-test_expect_success GPG \
- 'trying to create a signed tag with non-existing -F file should fail' '
+test_expect_success GPG 'trying to create a signed tag with non-existing -F file should fail' '
! test -f nonexistingfile &&
! tag_exists nosigtag &&
test_must_fail git tag -s -F nonexistingfile nosigtag &&
! tag_exists nosigtag
'
-test_expect_success GPG 'verifying a signed tag should succeed' \
- 'git tag -v signed-tag'
+test_expect_success GPG 'verifying a signed tag should succeed' '
+ git tag -v signed-tag
+'
-test_expect_success GPG 'verifying two signed tags in one command should succeed' \
- 'git tag -v signed-tag file-signed-tag'
+test_expect_success GPG 'verifying two signed tags in one command should succeed' '
+ git tag -v signed-tag file-signed-tag
+'
-test_expect_success GPG \
- 'verifying many signed and non-signed tags should fail' '
+test_expect_success GPG 'verifying many signed and non-signed tags should fail' '
test_must_fail git tag -v signed-tag annotated-tag &&
test_must_fail git tag -v file-annotated-tag file-signed-tag &&
test_must_fail git tag -v annotated-tag \
@@ -1150,78 +1125,72 @@ test_expect_success GPG 'verifying a forged tag with --format should fail silent
# blank and empty messages for signed tags:
-get_tag_header empty-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with an empty -m message should succeed' '
+test_expect_success GPG 'creating a signed tag with an empty -m message should succeed' '
+ get_tag_header empty-signed-tag $commit commit $time >expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -m "" empty-signed-tag &&
get_tag_msg empty-signed-tag >actual &&
test_cmp expect actual &&
git tag -v empty-signed-tag
'
->sigemptyfile
-get_tag_header emptyfile-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with an empty -F messagefile should succeed' '
+test_expect_success GPG 'creating a signed tag with an empty -F messagefile should succeed' '
+ >sigemptyfile &&
+ get_tag_header emptyfile-signed-tag $commit commit $time >expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -F sigemptyfile emptyfile-signed-tag &&
get_tag_msg emptyfile-signed-tag >actual &&
test_cmp expect actual &&
git tag -v emptyfile-signed-tag
'
-printf '\n\n \n\t\nLeading blank lines\n' > sigblanksfile
-printf '\n\t \t \nRepeated blank lines\n' >>sigblanksfile
-printf '\n\n\nTrailing spaces \t \n' >>sigblanksfile
-printf '\nTrailing blank lines\n\n\t \n\n' >>sigblanksfile
-get_tag_header blanks-signed-tag $commit commit $time >expect
-cat >>expect <<EOF
-Leading blank lines
+test_expect_success GPG 'extra blanks in the message for a signed tag should be removed' '
+ printf "\n\n \n\t\nLeading blank lines\n" >sigblanksfile &&
+ printf "\n\t \t \nRepeated blank lines\n" >>sigblanksfile &&
+ printf "\n\n\nTrailing spaces \t \n" >>sigblanksfile &&
+ printf "\nTrailing blank lines\n\n\t \n\n" >>sigblanksfile &&
+ get_tag_header blanks-signed-tag $commit commit $time >expect &&
+ cat >>expect <<-\EOF &&
+ Leading blank lines
-Repeated blank lines
+ Repeated blank lines
-Trailing spaces
+ Trailing spaces
-Trailing blank lines
-EOF
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'extra blanks in the message for a signed tag should be removed' '
+ Trailing blank lines
+ EOF
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -F sigblanksfile blanks-signed-tag &&
get_tag_msg blanks-signed-tag >actual &&
test_cmp expect actual &&
git tag -v blanks-signed-tag
'
-get_tag_header blank-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with a blank -m message should succeed' '
+test_expect_success GPG 'creating a signed tag with a blank -m message should succeed' '
+ get_tag_header blank-signed-tag $commit commit $time >expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -m " " blank-signed-tag &&
get_tag_msg blank-signed-tag >actual &&
test_cmp expect actual &&
git tag -v blank-signed-tag
'
-echo ' ' >sigblankfile
-echo '' >>sigblankfile
-echo ' ' >>sigblankfile
-get_tag_header blankfile-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with blank -F file with spaces should succeed' '
+test_expect_success GPG 'creating a signed tag with blank -F file with spaces should succeed' '
+ echo " " >sigblankfile &&
+ echo "" >>sigblankfile &&
+ echo " " >>sigblankfile &&
+ get_tag_header blankfile-signed-tag $commit commit $time >expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -F sigblankfile blankfile-signed-tag &&
get_tag_msg blankfile-signed-tag >actual &&
test_cmp expect actual &&
git tag -v blankfile-signed-tag
'
-printf ' ' >sigblanknonlfile
-get_tag_header blanknonlfile-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with spaces and no newline should succeed' '
+test_expect_success GPG 'creating a signed tag with spaces and no newline should succeed' '
+ printf " " >sigblanknonlfile &&
+ get_tag_header blanknonlfile-signed-tag $commit commit $time >expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -F sigblanknonlfile blanknonlfile-signed-tag &&
get_tag_msg blanknonlfile-signed-tag >actual &&
test_cmp expect actual &&
@@ -1241,69 +1210,65 @@ test_expect_success GPG 'signed tag with embedded PGP message' '
# messages with commented lines for signed tags:
-cat >sigcommentsfile <<EOF
-# A comment
+test_expect_success GPG 'creating a signed tag with a -F file with #comments should succeed' '
+ cat >sigcommentsfile <<-\EOF &&
+ # A comment
-############
-The message.
-############
-One line.
+ ############
+ The message.
+ ############
+ One line.
-# commented lines
-# commented lines
+ # commented lines
+ # commented lines
-Another line.
-# comments
+ Another line.
+ # comments
-Last line.
-EOF
-get_tag_header comments-signed-tag $commit commit $time >expect
-cat >>expect <<EOF
-The message.
-One line.
+ Last line.
+ EOF
+ get_tag_header comments-signed-tag $commit commit $time >expect &&
+ cat >>expect <<-\EOF &&
+ The message.
+ One line.
-Another line.
+ Another line.
-Last line.
-EOF
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with a -F file with #comments should succeed' '
+ Last line.
+ EOF
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -F sigcommentsfile comments-signed-tag &&
get_tag_msg comments-signed-tag >actual &&
test_cmp expect actual &&
git tag -v comments-signed-tag
'
-get_tag_header comment-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with #commented -m message should succeed' '
+test_expect_success GPG 'creating a signed tag with #commented -m message should succeed' '
+ get_tag_header comment-signed-tag $commit commit $time >expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -m "#comment" comment-signed-tag &&
get_tag_msg comment-signed-tag >actual &&
test_cmp expect actual &&
git tag -v comment-signed-tag
'
-echo '#comment' >sigcommentfile
-echo '' >>sigcommentfile
-echo '####' >>sigcommentfile
-get_tag_header commentfile-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with #commented -F messagefile should succeed' '
+test_expect_success GPG 'creating a signed tag with #commented -F messagefile should succeed' '
+ echo "#comment" >sigcommentfile &&
+ echo "" >>sigcommentfile &&
+ echo "####" >>sigcommentfile &&
+ get_tag_header commentfile-signed-tag $commit commit $time >expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -F sigcommentfile commentfile-signed-tag &&
get_tag_msg commentfile-signed-tag >actual &&
test_cmp expect actual &&
git tag -v commentfile-signed-tag
'
-printf '#comment' >sigcommentnonlfile
-get_tag_header commentnonlfile-signed-tag $commit commit $time >expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag with a #comment and no newline should succeed' '
+test_expect_success GPG 'creating a signed tag with a #comment and no newline should succeed' '
+ printf "#comment" >sigcommentnonlfile &&
+ get_tag_header commentnonlfile-signed-tag $commit commit $time >expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -F sigcommentnonlfile commentnonlfile-signed-tag &&
get_tag_msg commentnonlfile-signed-tag >actual &&
test_cmp expect actual &&
@@ -1312,8 +1277,7 @@ test_expect_success GPG \
# listing messages for signed tags:
-test_expect_success GPG \
- 'listing the one-line message of a signed tag should succeed' '
+test_expect_success GPG 'listing the one-line message of a signed tag should succeed' '
git tag -s -m "A message line signed" stag-one-line &&
echo "stag-one-line" >expect &&
@@ -1337,8 +1301,7 @@ test_expect_success GPG \
test_cmp expect actual
'
-test_expect_success GPG \
- 'listing the zero-lines message of a signed tag should succeed' '
+test_expect_success GPG 'listing the zero-lines message of a signed tag should succeed' '
git tag -s -m "" stag-zero-lines &&
echo "stag-zero-lines" >expect &&
@@ -1362,11 +1325,10 @@ test_expect_success GPG \
test_cmp expect actual
'
-echo 'stag line one' >sigtagmsg
-echo 'stag line two' >>sigtagmsg
-echo 'stag line three' >>sigtagmsg
-test_expect_success GPG \
- 'listing many message lines of a signed tag should succeed' '
+test_expect_success GPG 'listing many message lines of a signed tag should succeed' '
+ echo "stag line one" >sigtagmsg &&
+ echo "stag line two" >>sigtagmsg &&
+ echo "stag line three" >>sigtagmsg &&
git tag -s -F sigtagmsg stag-lines &&
echo "stag-lines" >expect &&
@@ -1408,74 +1370,64 @@ test_expect_success GPG \
# tags pointing to objects different from commits:
-tree=$(git rev-parse HEAD^{tree})
-blob=$(git rev-parse HEAD:foo)
-tag=$(git rev-parse signed-tag 2>/dev/null)
-
-get_tag_header tree-signed-tag $tree tree $time >expect
-echo "A message for a tree" >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag pointing to a tree should succeed' '
+test_expect_success GPG 'creating a signed tag pointing to a tree should succeed' '
+ tree=$(git rev-parse HEAD^{tree}) &&
+ get_tag_header tree-signed-tag $tree tree $time >expect &&
+ echo "A message for a tree" >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -m "A message for a tree" tree-signed-tag HEAD^{tree} &&
get_tag_msg tree-signed-tag >actual &&
test_cmp expect actual
'
-get_tag_header blob-signed-tag $blob blob $time >expect
-echo "A message for a blob" >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag pointing to a blob should succeed' '
+test_expect_success GPG 'creating a signed tag pointing to a blob should succeed' '
+ blob=$(git rev-parse HEAD:foo) &&
+ get_tag_header blob-signed-tag $blob blob $time >expect &&
+ echo "A message for a blob" >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -m "A message for a blob" blob-signed-tag HEAD:foo &&
get_tag_msg blob-signed-tag >actual &&
test_cmp expect actual
'
-get_tag_header tag-signed-tag $tag tag $time >expect
-echo "A message for another tag" >>expect
-echo '-----BEGIN PGP SIGNATURE-----' >>expect
-test_expect_success GPG \
- 'creating a signed tag pointing to another tag should succeed' '
+test_expect_success GPG 'creating a signed tag pointing to another tag should succeed' '
+ tag=$(git rev-parse signed-tag 2>/dev/null) &&
+ get_tag_header tag-signed-tag $tag tag $time >expect &&
+ echo "A message for another tag" >>expect &&
+ echo "-----BEGIN PGP SIGNATURE-----" >>expect &&
git tag -s -m "A message for another tag" tag-signed-tag signed-tag &&
get_tag_msg tag-signed-tag >actual &&
test_cmp expect actual
'
# usage with rfc1991 signatures
-get_tag_header rfc1991-signed-tag $commit commit $time >expect
-echo "RFC1991 signed tag" >>expect
-echo '-----BEGIN PGP MESSAGE-----' >>expect
-test_expect_success GPG,RFC1991 \
- 'creating a signed tag with rfc1991' '
+
+test_expect_success GPG,RFC1991 'creating a signed tag with rfc1991' '
+ get_tag_header rfc1991-signed-tag $commit commit $time >expect &&
+ echo "RFC1991 signed tag" >>expect &&
+ echo "-----BEGIN PGP MESSAGE-----" >>expect &&
echo "rfc1991" >gpghome/gpg.conf &&
git tag -s -m "RFC1991 signed tag" rfc1991-signed-tag $commit &&
get_tag_msg rfc1991-signed-tag >actual &&
test_cmp expect actual
'
-cat >fakeeditor <<'EOF'
-#!/bin/sh
-cp "$1" actual
-EOF
-chmod +x fakeeditor
-
-test_expect_success GPG,RFC1991 \
- 'reediting a signed tag body omits signature' '
+test_expect_success GPG,RFC1991 'reediting a signed tag body omits signature' '
+ write_script fakeeditor <<-\EOF &&
+ cp "$1" actual
+ EOF
echo "rfc1991" >gpghome/gpg.conf &&
echo "RFC1991 signed tag" >expect &&
GIT_EDITOR=./fakeeditor git tag -f -s rfc1991-signed-tag $commit &&
test_cmp expect actual
'
-test_expect_success GPG,RFC1991 \
- 'verifying rfc1991 signature' '
+test_expect_success GPG,RFC1991 'verifying rfc1991 signature' '
echo "rfc1991" >gpghome/gpg.conf &&
git tag -v rfc1991-signed-tag
'
-test_expect_success GPG,RFC1991 \
- 'list tag with rfc1991 signature' '
+test_expect_success GPG,RFC1991 'list tag with rfc1991 signature' '
echo "rfc1991" >gpghome/gpg.conf &&
echo "rfc1991-signed-tag RFC1991 signed tag" >expect &&
git tag -l -n1 rfc1991-signed-tag >actual &&
@@ -1486,15 +1438,12 @@ test_expect_success GPG,RFC1991 \
test_cmp expect actual
'
-rm -f gpghome/gpg.conf
-
-test_expect_success GPG,RFC1991 \
- 'verifying rfc1991 signature without --rfc1991' '
+test_expect_success GPG,RFC1991 'verifying rfc1991 signature without --rfc1991' '
+ rm -f gpghome/gpg.conf &&
git tag -v rfc1991-signed-tag
'
-test_expect_success GPG,RFC1991 \
- 'list tag with rfc1991 signature without --rfc1991' '
+test_expect_success GPG,RFC1991 'list tag with rfc1991 signature without --rfc1991' '
echo "rfc1991-signed-tag RFC1991 signed tag" >expect &&
git tag -l -n1 rfc1991-signed-tag >actual &&
test_cmp expect actual &&
@@ -1504,24 +1453,23 @@ test_expect_success GPG,RFC1991 \
test_cmp expect actual
'
-test_expect_success GPG,RFC1991 \
- 'reediting a signed tag body omits signature' '
+test_expect_success GPG,RFC1991 'reediting a signed tag body omits signature' '
echo "RFC1991 signed tag" >expect &&
GIT_EDITOR=./fakeeditor git tag -f -s rfc1991-signed-tag $commit &&
test_cmp expect actual
'
# try to sign with bad user.signingkey
-test_expect_success GPG \
- 'git tag -s fails if gpg is misconfigured (bad key)' \
- 'test_config user.signingkey BobTheMouse &&
- test_must_fail git tag -s -m tail tag-gpg-failure'
+test_expect_success GPG 'git tag -s fails if gpg is misconfigured (bad key)' '
+ test_config user.signingkey BobTheMouse &&
+ test_must_fail git tag -s -m tail tag-gpg-failure
+'
# try to produce invalid signature
-test_expect_success GPG \
- 'git tag -s fails if gpg is misconfigured (bad signature format)' \
- 'test_config gpg.program echo &&
- test_must_fail git tag -s -m tail tag-gpg-failure'
+test_expect_success GPG 'git tag -s fails if gpg is misconfigured (bad signature format)' '
+ test_config gpg.program echo &&
+ test_must_fail git tag -s -m tail tag-gpg-failure
+'
# try to produce invalid signature
test_expect_success GPG 'git verifies tag is valid with double signature' '
@@ -1542,34 +1490,32 @@ test_expect_success GPG 'git verifies tag is valid with double signature' '
'
# try to sign with bad user.signingkey
-test_expect_success GPGSM \
- 'git tag -s fails if gpgsm is misconfigured (bad key)' \
- 'test_config user.signingkey BobTheMouse &&
- test_config gpg.format x509 &&
- test_must_fail git tag -s -m tail tag-gpg-failure'
+test_expect_success GPGSM 'git tag -s fails if gpgsm is misconfigured (bad key)' '
+ test_config user.signingkey BobTheMouse &&
+ test_config gpg.format x509 &&
+ test_must_fail git tag -s -m tail tag-gpg-failure
+'
# try to produce invalid signature
-test_expect_success GPGSM \
- 'git tag -s fails if gpgsm is misconfigured (bad signature format)' \
- 'test_config gpg.x509.program echo &&
- test_config gpg.format x509 &&
- test_must_fail git tag -s -m tail tag-gpg-failure'
+test_expect_success GPGSM 'git tag -s fails if gpgsm is misconfigured (bad signature format)' '
+ test_config gpg.x509.program echo &&
+ test_config gpg.format x509 &&
+ test_must_fail git tag -s -m tail tag-gpg-failure
+'
# try to verify without gpg:
-rm -rf gpghome
-test_expect_success GPG \
- 'verify signed tag fails when public key is not present' \
- 'test_must_fail git tag -v signed-tag'
+test_expect_success GPG 'verify signed tag fails when public key is not present' '
+ rm -rf gpghome &&
+ test_must_fail git tag -v signed-tag
+'
-test_expect_success \
- 'git tag -a fails if tag annotation is empty' '
+test_expect_success 'git tag -a fails if tag annotation is empty' '
! (GIT_EDITOR=cat git tag -a initial-comment)
'
-test_expect_success \
- 'message in editor has initial comment' '
- ! (GIT_EDITOR=cat git tag -a initial-comment > actual)
+test_expect_success 'message in editor has initial comment' '
+ ! (GIT_EDITOR=cat git tag -a initial-comment >actual)
'
test_expect_success 'message in editor has initial comment: first line' '
@@ -1579,17 +1525,15 @@ test_expect_success 'message in editor has initial comment: first line' '
test_cmp first.expect first.actual
'
-test_expect_success \
- 'message in editor has initial comment: remainder' '
+test_expect_success 'message in editor has initial comment: remainder' '
# remove commented lines from the remainder -- should be empty
sed -e 1d -e "/^#/d" <actual >rest.actual &&
test_must_be_empty rest.actual
'
-get_tag_header reuse $commit commit $time >expect
-echo "An annotation to be reused" >> expect
-test_expect_success \
- 'overwriting an annotated tag should use its previous body' '
+test_expect_success 'overwriting an annotated tag should use its previous body' '
+ get_tag_header reuse $commit commit $time >expect &&
+ echo "An annotation to be reused" >>expect &&
git tag -a -m "An annotation to be reused" reuse &&
GIT_EDITOR=true git tag -f -a reuse &&
get_tag_msg reuse >actual &&
@@ -1618,192 +1562,202 @@ test_expect_success 'filename for the message is relative to cwd' '
# create a few more commits to test --contains
-hash1=$(git rev-parse HEAD)
-
test_expect_success 'creating second commit and tag' '
+ hash1=$(git rev-parse HEAD) &&
echo foo-2.0 >foo &&
git add foo &&
git commit -m second &&
git tag v2.0
'
-hash2=$(git rev-parse HEAD)
-
test_expect_success 'creating third commit without tag' '
+ hash2=$(git rev-parse HEAD) &&
echo foo-dev >foo &&
git add foo &&
git commit -m third
'
-hash3=$(git rev-parse HEAD)
-
# simple linear checks of --continue
-cat > expected <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-v2.0
-EOF
-
-test_expect_success 'checking that first commit is in all tags (hash)' "
+test_expect_success 'checking that first commit is in all tags (hash)' '
+ hash3=$(git rev-parse HEAD) &&
+ cat >expected <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ v2.0
+ EOF
git tag -l --contains $hash1 v* >actual &&
test_cmp expected actual
-"
+'
# other ways of specifying the commit
-test_expect_success 'checking that first commit is in all tags (tag)' "
+test_expect_success 'checking that first commit is in all tags (tag)' '
+ cat >expected <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ v2.0
+ EOF
git tag -l --contains v1.0 v* >actual &&
test_cmp expected actual
-"
+'
-test_expect_success 'checking that first commit is in all tags (relative)' "
+test_expect_success 'checking that first commit is in all tags (relative)' '
+ cat >expected <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ v2.0
+ EOF
git tag -l --contains HEAD~2 v* >actual &&
test_cmp expected actual
-"
+'
# All the --contains tests above, but with --no-contains
-test_expect_success 'checking that first commit is not listed in any tag with --no-contains (hash)' "
+test_expect_success 'checking that first commit is not listed in any tag with --no-contains (hash)' '
git tag -l --no-contains $hash1 v* >actual &&
test_must_be_empty actual
-"
+'
-test_expect_success 'checking that first commit is in all tags (tag)' "
+test_expect_success 'checking that first commit is in all tags (tag)' '
git tag -l --no-contains v1.0 v* >actual &&
test_must_be_empty actual
-"
+'
-test_expect_success 'checking that first commit is in all tags (relative)' "
+test_expect_success 'checking that first commit is in all tags (relative)' '
git tag -l --no-contains HEAD~2 v* >actual &&
test_must_be_empty actual
-"
-
-cat > expected <<EOF
-v2.0
-EOF
+'
-test_expect_success 'checking that second commit only has one tag' "
+test_expect_success 'checking that second commit only has one tag' '
+ cat >expected <<-\EOF &&
+ v2.0
+ EOF
git tag -l --contains $hash2 v* >actual &&
test_cmp expected actual
-"
-
-cat > expected <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-EOF
+'
-test_expect_success 'inverse of the last test, with --no-contains' "
+test_expect_success 'inverse of the last test, with --no-contains' '
+ cat >expected <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ EOF
git tag -l --no-contains $hash2 v* >actual &&
test_cmp expected actual
-"
+'
-test_expect_success 'checking that third commit has no tags' "
+test_expect_success 'checking that third commit has no tags' '
git tag -l --contains $hash3 v* >actual &&
test_must_be_empty actual
-"
-
-cat > expected <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-v2.0
-EOF
+'
-test_expect_success 'conversely --no-contains on the third commit lists all tags' "
+test_expect_success 'conversely --no-contains on the third commit lists all tags' '
+ cat >expected <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ v2.0
+ EOF
git tag -l --no-contains $hash3 v* >actual &&
test_cmp expected actual
-"
+'
# how about a simple merge?
test_expect_success 'creating simple branch' '
git branch stable v2.0 &&
git checkout stable &&
- echo foo-3.0 > foo &&
+ echo foo-3.0 >foo &&
git commit foo -m fourth &&
git tag v3.0
'
-hash4=$(git rev-parse HEAD)
-
-cat > expected <<EOF
-v3.0
-EOF
-
-test_expect_success 'checking that branch head only has one tag' "
+test_expect_success 'checking that branch head only has one tag' '
+ hash4=$(git rev-parse HEAD) &&
+ cat >expected <<-\EOF &&
+ v3.0
+ EOF
git tag -l --contains $hash4 v* >actual &&
test_cmp expected actual
-"
-
-cat > expected <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-v2.0
-EOF
+'
-test_expect_success 'checking that branch head with --no-contains lists all but one tag' "
+test_expect_success 'checking that branch head with --no-contains lists all but one tag' '
+ cat >expected <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ v2.0
+ EOF
git tag -l --no-contains $hash4 v* >actual &&
test_cmp expected actual
-"
+'
test_expect_success 'merging original branch into this branch' '
git merge --strategy=ours main &&
git tag v4.0
'
-cat > expected <<EOF
-v4.0
-EOF
-
-test_expect_success 'checking that original branch head has one tag now' "
+test_expect_success 'checking that original branch head has one tag now' '
+ cat >expected <<-\EOF &&
+ v4.0
+ EOF
git tag -l --contains $hash3 v* >actual &&
test_cmp expected actual
-"
-
-cat > expected <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-v2.0
-v3.0
-EOF
+'
-test_expect_success 'checking that original branch head with --no-contains lists all but one tag now' "
+test_expect_success 'checking that original branch head with --no-contains lists all but one tag now' '
+ cat >expected <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ v2.0
+ v3.0
+ EOF
git tag -l --no-contains $hash3 v* >actual &&
test_cmp expected actual
-"
-
-cat > expected <<EOF
-v0.2.1
-v1.0
-v1.0.1
-v1.1.3
-v2.0
-v3.0
-v4.0
-EOF
+'
-test_expect_success 'checking that initial commit is in all tags' "
+test_expect_success 'checking that initial commit is in all tags' '
+ cat >expected <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ v2.0
+ v3.0
+ v4.0
+ EOF
git tag -l --contains $hash1 v* >actual &&
test_cmp expected actual
-"
+'
test_expect_success 'checking that --contains can be used in non-list mode' '
+ cat >expected <<-\EOF &&
+ v0.2.1
+ v1.0
+ v1.0.1
+ v1.1.3
+ v2.0
+ v3.0
+ v4.0
+ EOF
git tag --contains $hash1 v* >actual &&
test_cmp expected actual
'
-test_expect_success 'checking that initial commit is in all tags with --no-contains' "
+test_expect_success 'checking that initial commit is in all tags with --no-contains' '
git tag -l --no-contains $hash1 v* >actual &&
test_must_be_empty actual
-"
+'
# mixing modes and options:
@@ -1840,16 +1794,16 @@ test_expect_success 'mixing incompatibles modes and options is forbidden' '
for option in --contains --with --no-contains --without --merged --no-merged --points-at
do
- test_expect_success "mixing incompatible modes with $option is forbidden" "
+ test_expect_success "mixing incompatible modes with $option is forbidden" '
test_must_fail git tag -d $option HEAD &&
test_must_fail git tag -d $option HEAD some-tag &&
test_must_fail git tag -v $option HEAD
- "
- test_expect_success "Doing 'git tag --list-like $option <commit> <pattern> is permitted" "
+ '
+ test_expect_success "Doing 'git tag --list-like $option <commit> <pattern> is permitted" '
git tag -n $option HEAD HEAD &&
git tag $option HEAD HEAD &&
git tag $option
- "
+ '
done
# check points-at
@@ -2225,7 +2179,7 @@ test_expect_success 'git tag -l with --format="%(rest)" must fail' '
test_must_fail git tag -l --format="%(rest)" "v1*"
'
-test_expect_success "set up color tests" '
+test_expect_success 'set up color tests' '
echo "<RED>v1.0<RESET>" >expect.color &&
echo "v1.0" >expect.bare &&
color_args="--format=%(color:red)%(refname:short) --list v1.0"
diff --git a/t/t7008-filter-branch-null-sha1.sh b/t/t7008-filter-branch-null-sha1.sh
index 93fbc92b8d..0ce8fd2c89 100755
--- a/t/t7008-filter-branch-null-sha1.sh
+++ b/t/t7008-filter-branch-null-sha1.sh
@@ -2,6 +2,7 @@
test_description='filter-branch removal of trees with null sha1'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup: base commits' '
diff --git a/t/t7030-verify-tag.sh b/t/t7030-verify-tag.sh
index 6f526c37c2..effa826744 100755
--- a/t/t7030-verify-tag.sh
+++ b/t/t7030-verify-tag.sh
@@ -4,6 +4,7 @@ test_description='signed tag tests'
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-gpg.sh"
diff --git a/t/t7418-submodule-sparse-gitmodules.sh b/t/t7418-submodule-sparse-gitmodules.sh
index dde11ecce8..e1d9bf2ee3 100755
--- a/t/t7418-submodule-sparse-gitmodules.sh
+++ b/t/t7418-submodule-sparse-gitmodules.sh
@@ -15,6 +15,7 @@ also by committing .gitmodules and then just removing it from the filesystem.
GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1
export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t7424-submodule-mixed-ref-formats.sh b/t/t7424-submodule-mixed-ref-formats.sh
new file mode 100755
index 0000000000..b43ef2ba67
--- /dev/null
+++ b/t/t7424-submodule-mixed-ref-formats.sh
@@ -0,0 +1,144 @@
+#!/bin/sh
+
+test_description='submodules handle mixed ref storage formats'
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+test_ref_format () {
+ echo "$2" >expect &&
+ git -C "$1" rev-parse --show-ref-format >actual &&
+ test_cmp expect actual
+}
+
+for OTHER_FORMAT in files reftable
+do
+ if test "$OTHER_FORMAT" = "$GIT_DEFAULT_REF_FORMAT"
+ then
+ continue
+ fi
+
+test_expect_success 'setup' '
+ git config set --global protocol.file.allow always &&
+ # Some tests migrate the ref storage format, which does not work with
+ # reflogs at the time of writing these tests.
+ git config set --global core.logAllRefUpdates false
+'
+
+test_expect_success 'add existing repository with different ref storage format' '
+ test_when_finished "rm -rf parent" &&
+
+ git init parent &&
+ (
+ cd parent &&
+ test_commit parent &&
+ git init --ref-format=$OTHER_FORMAT submodule &&
+ test_commit -C submodule submodule &&
+ git submodule add ./submodule
+ )
+'
+
+test_expect_success 'add submodules with different ref storage format' '
+ test_when_finished "rm -rf submodule upstream" &&
+
+ git init submodule &&
+ test_commit -C submodule submodule-initial &&
+ git init upstream &&
+ test_ref_format upstream "$GIT_DEFAULT_REF_FORMAT" &&
+ git -C upstream submodule add --ref-format="$OTHER_FORMAT" "file://$(pwd)/submodule" &&
+ test_ref_format upstream/submodule "$OTHER_FORMAT"
+'
+
+test_expect_success 'recursive clone propagates ref storage format' '
+ test_when_finished "rm -rf submodule upstream downstream" &&
+
+ git init submodule &&
+ test_commit -C submodule submodule-initial &&
+ git init upstream &&
+ git -C upstream submodule add "file://$(pwd)/submodule" &&
+ git -C upstream commit -am "add submodule" &&
+
+ # The upstream repository and its submodule should be using the default
+ # ref format.
+ test_ref_format upstream "$GIT_DEFAULT_REF_FORMAT" &&
+ test_ref_format upstream/submodule "$GIT_DEFAULT_REF_FORMAT" &&
+
+ # The cloned repositories should use the other ref format that we have
+ # specified via `--ref-format`. The option should propagate to cloned
+ # submodules.
+ git clone --ref-format=$OTHER_FORMAT --recurse-submodules \
+ upstream downstream &&
+ test_ref_format downstream "$OTHER_FORMAT" &&
+ test_ref_format downstream/submodule "$OTHER_FORMAT"
+'
+
+test_expect_success 'clone submodules with different ref storage format' '
+ test_when_finished "rm -rf submodule upstream downstream" &&
+
+ git init submodule &&
+ test_commit -C submodule submodule-initial &&
+ git init upstream &&
+ git -C upstream submodule add "file://$(pwd)/submodule" &&
+ git -C upstream commit -m "upstream submodule" &&
+
+ git clone --no-recurse-submodules "file://$(pwd)/upstream" downstream &&
+ test_ref_format downstream "$GIT_DEFAULT_REF_FORMAT" &&
+ git -C downstream submodule update --init --ref-format=$OTHER_FORMAT &&
+ test_ref_format downstream/submodule "$OTHER_FORMAT"
+'
+
+test_expect_success 'status with mixed submodule ref storages' '
+ test_when_finished "rm -rf submodule main" &&
+
+ git init submodule &&
+ test_commit -C submodule submodule-initial &&
+ git init main &&
+ git -C main submodule add "file://$(pwd)/submodule" &&
+ git -C main commit -m "add submodule" &&
+ git -C main/submodule refs migrate --ref-format=$OTHER_FORMAT &&
+
+ # The main repository should use the default ref format now, whereas
+ # the submodule should use the other format.
+ test_ref_format main "$GIT_DEFAULT_REF_FORMAT" &&
+ test_ref_format main/submodule "$OTHER_FORMAT" &&
+
+ cat >expect <<-EOF &&
+ $(git -C main/submodule rev-parse HEAD) submodule (submodule-initial)
+ EOF
+ git -C main submodule status >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'recursive pull with mixed formats' '
+ test_when_finished "rm -rf submodule upstream downstream" &&
+
+ # Set up the initial structure with an upstream repository that has a
+ # submodule, as well as a downstream clone of the upstream repository.
+ git init submodule &&
+ test_commit -C submodule submodule-initial &&
+ git init upstream &&
+ git -C upstream submodule add "file://$(pwd)/submodule" &&
+ git -C upstream commit -m "upstream submodule" &&
+
+ # Clone the upstream repository such that the main repo and its
+ # submodules have different formats.
+ git clone --no-recurse-submodules "file://$(pwd)/upstream" downstream &&
+ git -C downstream submodule update --init --ref-format=$OTHER_FORMAT &&
+ test_ref_format downstream "$GIT_DEFAULT_REF_FORMAT" &&
+ test_ref_format downstream/submodule "$OTHER_FORMAT" &&
+
+ # Update the upstream submodule as well as the owning repository such
+ # that we can do a recursive pull.
+ test_commit -C submodule submodule-update &&
+ git -C upstream/submodule pull &&
+ git -C upstream commit -am "update the submodule" &&
+
+ git -C downstream pull --recurse-submodules &&
+ git -C upstream/submodule rev-parse HEAD >expect &&
+ git -C downstream/submodule rev-parse HEAD >actual &&
+ test_cmp expect actual
+'
+
+done
+
+test_done
diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh
index 127efe99f8..be1188e736 100755
--- a/t/t7700-repack.sh
+++ b/t/t7700-repack.sh
@@ -7,6 +7,9 @@ test_description='git repack works correctly'
. "${TEST_DIRECTORY}/lib-midx.sh"
. "${TEST_DIRECTORY}/lib-terminal.sh"
+GIT_TEST_MULTI_PACK_INDEX=0
+GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=0
+
commit_and_pack () {
test_commit "$@" 1>&2 &&
incrpackid=$(git pack-objects --all --unpacked --incremental .git/objects/pack/pack </dev/null) &&
@@ -70,14 +73,13 @@ test_expect_success 'objects in packs marked .keep are not repacked' '
test_expect_success 'writing bitmaps via command-line can duplicate .keep objects' '
# build on $oid, $packid, and .keep state from previous
- GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 git repack -Adbl &&
+ git repack -Adbl &&
test_has_duplicate_object true
'
test_expect_success 'writing bitmaps via config can duplicate .keep objects' '
# build on $oid, $packid, and .keep state from previous
- GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
- git -c repack.writebitmaps=true repack -Adl &&
+ git -c repack.writebitmaps=true repack -Adl &&
test_has_duplicate_object true
'
@@ -118,7 +120,7 @@ test_expect_success '--local disables writing bitmaps when connected to alternat
(
cd member &&
test_commit "object" &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adl --write-bitmap-index 2>err &&
+ git repack -Adl --write-bitmap-index 2>err &&
cat >expect <<-EOF &&
warning: disabling bitmap writing, as some objects are not being packed
EOF
@@ -284,8 +286,7 @@ test_expect_success 'repacking fails when missing .pack actually means missing o
test_expect_success 'bitmaps are created by default in bare repos' '
git clone --bare .git bare.git &&
rm -f bare.git/objects/pack/*.bitmap &&
- GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
- git -C bare.git repack -ad &&
+ git -C bare.git repack -ad &&
bitmap=$(ls bare.git/objects/pack/*.bitmap) &&
test_path_is_file "$bitmap"
'
@@ -296,8 +297,7 @@ test_expect_success 'incremental repack does not complain' '
'
test_expect_success 'bitmaps can be disabled on bare repos' '
- GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
- git -c repack.writeBitmaps=false -C bare.git repack -ad &&
+ git -c repack.writeBitmaps=false -C bare.git repack -ad &&
bitmap=$(ls bare.git/objects/pack/*.bitmap || :) &&
test -z "$bitmap"
'
@@ -308,8 +308,7 @@ test_expect_success 'no bitmaps created if .keep files present' '
keep=${pack%.pack}.keep &&
test_when_finished "rm -f \"\$keep\"" &&
>"$keep" &&
- GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
- git -C bare.git repack -ad 2>stderr &&
+ git -C bare.git repack -ad 2>stderr &&
test_must_be_empty stderr &&
find bare.git/objects/pack/ -type f -name "*.bitmap" >actual &&
test_must_be_empty actual
@@ -320,8 +319,7 @@ test_expect_success 'auto-bitmaps do not complain if unavailable' '
blob=$(test-tool genrandom big $((1024*1024)) |
git -C bare.git hash-object -w --stdin) &&
git -C bare.git update-ref refs/tags/big $blob &&
- GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
- git -C bare.git repack -ad 2>stderr &&
+ git -C bare.git repack -ad 2>stderr &&
test_must_be_empty stderr &&
find bare.git/objects/pack -type f -name "*.bitmap" >actual &&
test_must_be_empty actual
@@ -342,9 +340,7 @@ test_expect_success 'repacking with a filter works' '
'
test_expect_success '--filter fails with --write-bitmap-index' '
- test_must_fail \
- env GIT_TEST_MULTI_PACK_INDEX_WRITE_BITMAP=0 \
- git -C bare.git repack -a -d --write-bitmap-index --filter=blob:none
+ test_must_fail git -C bare.git repack -a -d --write-bitmap-index --filter=blob:none
'
test_expect_success 'repacking with two filters works' '
@@ -540,11 +536,11 @@ test_expect_success 'setup for --write-midx tests' '
test_expect_success '--write-midx unchanged' '
(
cd midx &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack &&
+ git repack &&
test_path_is_missing $midx &&
test_path_is_missing $midx-*.bitmap &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack --write-midx &&
+ git repack --write-midx &&
test_path_is_file $midx &&
test_path_is_missing $midx-*.bitmap &&
@@ -557,7 +553,7 @@ test_expect_success '--write-midx with a new pack' '
cd midx &&
test_commit loose &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack --write-midx &&
+ git repack --write-midx &&
test_path_is_file $midx &&
test_path_is_missing $midx-*.bitmap &&
@@ -568,7 +564,7 @@ test_expect_success '--write-midx with a new pack' '
test_expect_success '--write-midx with -b' '
(
cd midx &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack -mb &&
+ git repack -mb &&
test_path_is_file $midx &&
test_path_is_file $midx-*.bitmap &&
@@ -581,7 +577,7 @@ test_expect_success '--write-midx with -d' '
cd midx &&
test_commit repack &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack -Ad --write-midx &&
+ git repack -Ad --write-midx &&
test_path_is_file $midx &&
test_path_is_missing $midx-*.bitmap &&
@@ -594,21 +590,21 @@ test_expect_success 'cleans up MIDX when appropriate' '
cd midx &&
test_commit repack-2 &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adb --write-midx &&
+ git repack -Adb --write-midx &&
checksum=$(midx_checksum $objdir) &&
test_path_is_file $midx &&
test_path_is_file $midx-$checksum.bitmap &&
test_commit repack-3 &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adb --write-midx &&
+ git repack -Adb --write-midx &&
test_path_is_file $midx &&
test_path_is_missing $midx-$checksum.bitmap &&
test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
test_commit repack-4 &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack -Adb &&
+ git repack -Adb &&
find $objdir/pack -type f -name "multi-pack-index*" >files &&
test_must_be_empty files
@@ -629,7 +625,6 @@ test_expect_success '--write-midx with preferred bitmap tips' '
git log --format="create refs/tags/%s/%s %H" HEAD >refs &&
git update-ref --stdin <refs &&
- GIT_TEST_MULTI_PACK_INDEX=0 \
git repack --write-midx --write-bitmap-index &&
test_path_is_file $midx &&
test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
@@ -721,13 +716,13 @@ test_expect_success '--write-midx removes stale pack-based bitmaps' '
(
cd repo &&
test_commit base &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack -Ab &&
+ git repack -Ab &&
pack_bitmap=$(ls $objdir/pack/pack-*.bitmap) &&
test_path_is_file "$pack_bitmap" &&
test_commit tip &&
- GIT_TEST_MULTI_PACK_INDEX=0 git repack -bm &&
+ git repack -bm &&
test_path_is_file $midx &&
test_path_is_file $midx-$(midx_checksum $objdir).bitmap &&
@@ -750,7 +745,6 @@ test_expect_success '--write-midx with --pack-kept-objects' '
keep="$objdir/pack/pack-$one.keep" &&
touch "$keep" &&
- GIT_TEST_MULTI_PACK_INDEX=0 \
git repack --write-midx --write-bitmap-index --geometric=2 -d \
--pack-kept-objects &&
diff --git a/t/t7817-grep-sparse-checkout.sh b/t/t7817-grep-sparse-checkout.sh
index eb59564565..0ba7817fb7 100755
--- a/t/t7817-grep-sparse-checkout.sh
+++ b/t/t7817-grep-sparse-checkout.sh
@@ -33,6 +33,7 @@ should leave the following structure in the working tree:
But note that sub2 should have the SKIP_WORKTREE bit set.
'
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup' '
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index 1e68426852..3b3c371740 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -7,6 +7,7 @@ test_description='test git fast-import utility'
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-diff.sh ;# test-lib chdir's into trash
diff --git a/t/t9304-fast-import-marks.sh b/t/t9304-fast-import-marks.sh
index 410a871c52..1f776a80f3 100755
--- a/t/t9304-fast-import-marks.sh
+++ b/t/t9304-fast-import-marks.sh
@@ -1,6 +1,8 @@
#!/bin/sh
test_description='test exotic situations with marks'
+
+TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_expect_success 'setup dump of basic history' '
diff --git a/t/t9351-fast-export-anonymize.sh b/t/t9351-fast-export-anonymize.sh
index 156a647484..c0d9d7be75 100755
--- a/t/t9351-fast-export-anonymize.sh
+++ b/t/t9351-fast-export-anonymize.sh
@@ -4,6 +4,7 @@ test_description='basic tests for fast-export --anonymize'
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 simple repo' '
diff --git a/t/unit-tests/t-ctype.c b/t/unit-tests/t-ctype.c
index d6ac1fe678..e28a7f50f9 100644
--- a/t/unit-tests/t-ctype.c
+++ b/t/unit-tests/t-ctype.c
@@ -4,15 +4,13 @@
size_t len = ARRAY_SIZE(string) - 1 + \
BUILD_ASSERT_OR_ZERO(ARRAY_SIZE(string) > 0) + \
BUILD_ASSERT_OR_ZERO(sizeof(string[0]) == sizeof(char)); \
- int skip = test__run_begin(); \
- if (!skip) { \
+ if_test (#class " works") { \
for (int i = 0; i < 256; i++) { \
if (!check_int(class(i), ==, !!memchr(string, i, len)))\
test_msg(" i: 0x%02x", i); \
} \
check(!class(EOF)); \
} \
- test__run_end(!skip, TEST_LOCATION(), #class " works"); \
} while (0)
#define DIGIT "0123456789"
diff --git a/t/unit-tests/t-example-decorate.c b/t/unit-tests/t-example-decorate.c
index a4a75db735..8bf0709c41 100644
--- a/t/unit-tests/t-example-decorate.c
+++ b/t/unit-tests/t-example-decorate.c
@@ -15,36 +15,29 @@ static void t_add(struct test_vars *vars)
{
void *ret = add_decoration(&vars->n, vars->one, &vars->decoration_a);
- if (!check(ret == NULL))
- test_msg("when adding a brand-new object, NULL should be returned");
+ check(ret == NULL);
ret = add_decoration(&vars->n, vars->two, NULL);
- if (!check(ret == NULL))
- test_msg("when adding a brand-new object, NULL should be returned");
+ check(ret == NULL);
}
static void t_readd(struct test_vars *vars)
{
void *ret = add_decoration(&vars->n, vars->one, NULL);
- if (!check(ret == &vars->decoration_a))
- test_msg("when readding an already existing object, existing decoration should be returned");
+ check(ret == &vars->decoration_a);
ret = add_decoration(&vars->n, vars->two, &vars->decoration_b);
- if (!check(ret == NULL))
- test_msg("when readding an already existing object, existing decoration should be returned");
+ check(ret == NULL);
}
static void t_lookup(struct test_vars *vars)
{
void *ret = lookup_decoration(&vars->n, vars->one);
- if (!check(ret == NULL))
- test_msg("lookup should return added declaration");
+ check(ret == NULL);
ret = lookup_decoration(&vars->n, vars->two);
- if (!check(ret == &vars->decoration_b))
- test_msg("lookup should return added declaration");
+ check(ret == &vars->decoration_b);
ret = lookup_decoration(&vars->n, vars->three);
- if (!check(ret == NULL))
- test_msg("lookup for unknown object should return NULL");
+ check(ret == NULL);
}
static void t_loop(struct test_vars *vars)
@@ -55,8 +48,7 @@ static void t_loop(struct test_vars *vars)
if (vars->n.entries[i].base)
objects_noticed++;
}
- if (!check_int(objects_noticed, ==, 2))
- test_msg("should have 2 objects");
+ check_int(objects_noticed, ==, 2);
}
int cmd_main(int argc UNUSED, const char **argv UNUSED)
diff --git a/t/unit-tests/t-hashmap.c b/t/unit-tests/t-hashmap.c
new file mode 100644
index 0000000000..09a48c2c4e
--- /dev/null
+++ b/t/unit-tests/t-hashmap.c
@@ -0,0 +1,361 @@
+#include "test-lib.h"
+#include "hashmap.h"
+#include "strbuf.h"
+
+struct test_entry {
+ int padding; /* hashmap entry no longer needs to be the first member */
+ struct hashmap_entry ent;
+ /* key and value as two \0-terminated strings */
+ char key[FLEX_ARRAY];
+};
+
+static int test_entry_cmp(const void *cmp_data,
+ const struct hashmap_entry *eptr,
+ const struct hashmap_entry *entry_or_key,
+ const void *keydata)
+{
+ const unsigned int ignore_case = cmp_data ? *((int *)cmp_data) : 0;
+ const struct test_entry *e1, *e2;
+ const char *key = keydata;
+
+ e1 = container_of(eptr, const struct test_entry, ent);
+ e2 = container_of(entry_or_key, const struct test_entry, ent);
+
+ if (ignore_case)
+ return strcasecmp(e1->key, key ? key : e2->key);
+ else
+ return strcmp(e1->key, key ? key : e2->key);
+}
+
+static const char *get_value(const struct test_entry *e)
+{
+ return e->key + strlen(e->key) + 1;
+}
+
+static struct test_entry *alloc_test_entry(const char *key, const char *value,
+ unsigned int ignore_case)
+{
+ size_t klen = strlen(key);
+ size_t vlen = strlen(value);
+ unsigned int hash = ignore_case ? strihash(key) : strhash(key);
+ struct test_entry *entry = xmalloc(st_add4(sizeof(*entry), klen, vlen, 2));
+
+ hashmap_entry_init(&entry->ent, hash);
+ memcpy(entry->key, key, klen + 1);
+ memcpy(entry->key + klen + 1, value, vlen + 1);
+ return entry;
+}
+
+static struct test_entry *get_test_entry(struct hashmap *map, const char *key,
+ unsigned int ignore_case)
+{
+ return hashmap_get_entry_from_hash(
+ map, ignore_case ? strihash(key) : strhash(key), key,
+ struct test_entry, ent);
+}
+
+static int key_val_contains(const char *key_val[][2], char seen[], size_t n,
+ struct test_entry *entry)
+{
+ for (size_t i = 0; i < n; i++) {
+ if (!strcmp(entry->key, key_val[i][0]) &&
+ !strcmp(get_value(entry), key_val[i][1])) {
+ if (seen[i])
+ return 2;
+ seen[i] = 1;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void setup(void (*f)(struct hashmap *map, unsigned int ignore_case),
+ unsigned int ignore_case)
+{
+ struct hashmap map = HASHMAP_INIT(test_entry_cmp, &ignore_case);
+
+ f(&map, ignore_case);
+ hashmap_clear_and_free(&map, struct test_entry, ent);
+}
+
+static void t_replace(struct hashmap *map, unsigned int ignore_case)
+{
+ struct test_entry *entry;
+
+ entry = alloc_test_entry("key1", "value1", ignore_case);
+ check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+
+ entry = alloc_test_entry(ignore_case ? "Key1" : "key1", "value2",
+ ignore_case);
+ entry = hashmap_put_entry(map, entry, ent);
+ if (check(entry != NULL))
+ check_str(get_value(entry), "value1");
+ free(entry);
+
+ entry = alloc_test_entry("fooBarFrotz", "value3", ignore_case);
+ check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+
+ entry = alloc_test_entry(ignore_case ? "FOObarFrotz" : "fooBarFrotz",
+ "value4", ignore_case);
+ entry = hashmap_put_entry(map, entry, ent);
+ if (check(entry != NULL))
+ check_str(get_value(entry), "value3");
+ free(entry);
+}
+
+static void t_get(struct hashmap *map, unsigned int ignore_case)
+{
+ struct test_entry *entry;
+ const char *key_val[][2] = { { "key1", "value1" },
+ { "key2", "value2" },
+ { "fooBarFrotz", "value3" },
+ { ignore_case ? "key4" : "foobarfrotz",
+ "value4" } };
+ const char *query[][2] = {
+ { ignore_case ? "Key1" : "key1", "value1" },
+ { ignore_case ? "keY2" : "key2", "value2" },
+ { ignore_case ? "FOObarFrotz" : "fooBarFrotz", "value3" },
+ { ignore_case ? "FOObarFrotz" : "foobarfrotz",
+ ignore_case ? "value3" : "value4" }
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
+ entry = alloc_test_entry(key_val[i][0], key_val[i][1],
+ ignore_case);
+ check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+ }
+
+ for (size_t i = 0; i < ARRAY_SIZE(query); i++) {
+ entry = get_test_entry(map, query[i][0], ignore_case);
+ if (check(entry != NULL))
+ check_str(get_value(entry), query[i][1]);
+ else
+ test_msg("query key: %s", query[i][0]);
+ }
+
+ check_pointer_eq(get_test_entry(map, "notInMap", ignore_case), NULL);
+ check_int(map->tablesize, ==, 64);
+ check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val));
+}
+
+static void t_add(struct hashmap *map, unsigned int ignore_case)
+{
+ struct test_entry *entry;
+ const char *key_val[][2] = {
+ { "key1", "value1" },
+ { ignore_case ? "Key1" : "key1", "value2" },
+ { "fooBarFrotz", "value3" },
+ { ignore_case ? "FOObarFrotz" : "fooBarFrotz", "value4" }
+ };
+ const char *query_keys[] = { "key1", ignore_case ? "FOObarFrotz" :
+ "fooBarFrotz" };
+ char seen[ARRAY_SIZE(key_val)] = { 0 };
+
+ for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
+ entry = alloc_test_entry(key_val[i][0], key_val[i][1], ignore_case);
+ hashmap_add(map, &entry->ent);
+ }
+
+ for (size_t i = 0; i < ARRAY_SIZE(query_keys); i++) {
+ int count = 0;
+ entry = hashmap_get_entry_from_hash(map,
+ ignore_case ? strihash(query_keys[i]) :
+ strhash(query_keys[i]),
+ query_keys[i], struct test_entry, ent);
+
+ hashmap_for_each_entry_from(map, entry, ent)
+ {
+ int ret;
+ if (!check_int((ret = key_val_contains(
+ key_val, seen,
+ ARRAY_SIZE(key_val), entry)),
+ ==, 0)) {
+ switch (ret) {
+ case 1:
+ test_msg("found entry was not given in the input\n"
+ " key: %s\n value: %s",
+ entry->key, get_value(entry));
+ break;
+ case 2:
+ test_msg("duplicate entry detected\n"
+ " key: %s\n value: %s",
+ entry->key, get_value(entry));
+ break;
+ }
+ } else {
+ count++;
+ }
+ }
+ check_int(count, ==, 2);
+ }
+
+ for (size_t i = 0; i < ARRAY_SIZE(seen); i++) {
+ if (!check_int(seen[i], ==, 1))
+ test_msg("following key-val pair was not iterated over:\n"
+ " key: %s\n value: %s",
+ key_val[i][0], key_val[i][1]);
+ }
+
+ check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val));
+ check_pointer_eq(get_test_entry(map, "notInMap", ignore_case), NULL);
+}
+
+static void t_remove(struct hashmap *map, unsigned int ignore_case)
+{
+ struct test_entry *entry, *removed;
+ const char *key_val[][2] = { { "key1", "value1" },
+ { "key2", "value2" },
+ { "fooBarFrotz", "value3" } };
+ const char *remove[][2] = { { ignore_case ? "Key1" : "key1", "value1" },
+ { ignore_case ? "keY2" : "key2", "value2" } };
+
+ for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
+ entry = alloc_test_entry(key_val[i][0], key_val[i][1], ignore_case);
+ check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+ }
+
+ for (size_t i = 0; i < ARRAY_SIZE(remove); i++) {
+ entry = alloc_test_entry(remove[i][0], "", ignore_case);
+ removed = hashmap_remove_entry(map, entry, ent, remove[i][0]);
+ if (check(removed != NULL))
+ check_str(get_value(removed), remove[i][1]);
+ free(entry);
+ free(removed);
+ }
+
+ entry = alloc_test_entry("notInMap", "", ignore_case);
+ check_pointer_eq(hashmap_remove_entry(map, entry, ent, "notInMap"), NULL);
+ free(entry);
+
+ check_int(map->tablesize, ==, 64);
+ check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val) - ARRAY_SIZE(remove));
+}
+
+static void t_iterate(struct hashmap *map, unsigned int ignore_case)
+{
+ struct test_entry *entry;
+ struct hashmap_iter iter;
+ const char *key_val[][2] = { { "key1", "value1" },
+ { "key2", "value2" },
+ { "fooBarFrotz", "value3" } };
+ char seen[ARRAY_SIZE(key_val)] = { 0 };
+
+ for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) {
+ entry = alloc_test_entry(key_val[i][0], key_val[i][1], ignore_case);
+ check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+ }
+
+ hashmap_for_each_entry(map, &iter, entry, ent /* member name */)
+ {
+ int ret;
+ if (!check_int((ret = key_val_contains(key_val, seen,
+ ARRAY_SIZE(key_val),
+ entry)), ==, 0)) {
+ switch (ret) {
+ case 1:
+ test_msg("found entry was not given in the input\n"
+ " key: %s\n value: %s",
+ entry->key, get_value(entry));
+ break;
+ case 2:
+ test_msg("duplicate entry detected\n"
+ " key: %s\n value: %s",
+ entry->key, get_value(entry));
+ break;
+ }
+ }
+ }
+
+ for (size_t i = 0; i < ARRAY_SIZE(seen); i++) {
+ if (!check_int(seen[i], ==, 1))
+ test_msg("following key-val pair was not iterated over:\n"
+ " key: %s\n value: %s",
+ key_val[i][0], key_val[i][1]);
+ }
+
+ check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val));
+}
+
+static void t_alloc(struct hashmap *map, unsigned int ignore_case)
+{
+ struct test_entry *entry, *removed;
+
+ for (int i = 1; i <= 51; i++) {
+ char *key = xstrfmt("key%d", i);
+ char *value = xstrfmt("value%d", i);
+ entry = alloc_test_entry(key, value, ignore_case);
+ check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+ free(key);
+ free(value);
+ }
+ check_int(map->tablesize, ==, 64);
+ check_int(hashmap_get_size(map), ==, 51);
+
+ entry = alloc_test_entry("key52", "value52", ignore_case);
+ check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL);
+ check_int(map->tablesize, ==, 256);
+ check_int(hashmap_get_size(map), ==, 52);
+
+ for (int i = 1; i <= 12; i++) {
+ char *key = xstrfmt("key%d", i);
+ char *value = xstrfmt("value%d", i);
+
+ entry = alloc_test_entry(key, "", ignore_case);
+ removed = hashmap_remove_entry(map, entry, ent, key);
+ if (check(removed != NULL))
+ check_str(value, get_value(removed));
+ free(key);
+ free(value);
+ free(entry);
+ free(removed);
+ }
+ check_int(map->tablesize, ==, 256);
+ check_int(hashmap_get_size(map), ==, 40);
+
+ entry = alloc_test_entry("key40", "", ignore_case);
+ removed = hashmap_remove_entry(map, entry, ent, "key40");
+ if (check(removed != NULL))
+ check_str("value40", get_value(removed));
+ check_int(map->tablesize, ==, 64);
+ check_int(hashmap_get_size(map), ==, 39);
+ free(entry);
+ free(removed);
+}
+
+static void t_intern(struct hashmap *map, unsigned int ignore_case)
+{
+ const char *values[] = { "value1", "Value1", "value2", "value2" };
+
+ for (size_t i = 0; i < ARRAY_SIZE(values); i++) {
+ const char *i1 = strintern(values[i]);
+ const char *i2 = strintern(values[i]);
+
+ if (!check(!strcmp(i1, values[i])))
+ test_msg("strintern(%s) returns %s\n", values[i], i1);
+ else if (!check(i1 != values[i]))
+ test_msg("strintern(%s) returns input pointer\n",
+ values[i]);
+ else if (!check_pointer_eq(i1, i2))
+ test_msg("address('%s') != address('%s'), so strintern('%s') != strintern('%s')",
+ i1, i2, values[i], values[i]);
+ else
+ check_str(i1, values[i]);
+ }
+}
+
+int cmd_main(int argc UNUSED, const char **argv UNUSED)
+{
+ TEST(setup(t_replace, 0), "replace works");
+ TEST(setup(t_replace, 1), "replace (case insensitive) works");
+ TEST(setup(t_get, 0), "get works");
+ TEST(setup(t_get, 1), "get (case insensitive) works");
+ TEST(setup(t_add, 0), "add works");
+ TEST(setup(t_add, 1), "add (case insensitive) works");
+ TEST(setup(t_remove, 0), "remove works");
+ TEST(setup(t_remove, 1), "remove (case insensitive) works");
+ TEST(setup(t_iterate, 0), "iterate works");
+ TEST(setup(t_iterate, 1), "iterate (case insensitive) works");
+ TEST(setup(t_alloc, 0), "grow / shrink works");
+ TEST(setup(t_intern, 0), "string interning works");
+ return test_done();
+}
diff --git a/t/unit-tests/t-reftable-basics.c b/t/unit-tests/t-reftable-basics.c
index 4e80bdf16d..1dd60ab5f0 100644
--- a/t/unit-tests/t-reftable-basics.c
+++ b/t/unit-tests/t-reftable-basics.c
@@ -20,141 +20,125 @@ static int integer_needle_lesseq(size_t i, void *_args)
return args->needle <= args->haystack[i];
}
-static void test_binsearch(void)
+int cmd_main(int argc, const char *argv[])
{
- int haystack[] = { 2, 4, 6, 8, 10 };
- struct {
- int needle;
- size_t expected_idx;
- } testcases[] = {
- {-9000, 0},
- {-1, 0},
- {0, 0},
- {2, 0},
- {3, 1},
- {4, 1},
- {7, 3},
- {9, 4},
- {10, 4},
- {11, 5},
- {9000, 5},
- };
-
- for (size_t i = 0; i < ARRAY_SIZE(testcases); i++) {
- struct integer_needle_lesseq_args args = {
- .haystack = haystack,
- .needle = testcases[i].needle,
+ if_test ("binary search with binsearch works") {
+ int haystack[] = { 2, 4, 6, 8, 10 };
+ struct {
+ int needle;
+ size_t expected_idx;
+ } testcases[] = {
+ {-9000, 0},
+ {-1, 0},
+ {0, 0},
+ {2, 0},
+ {3, 1},
+ {4, 1},
+ {7, 3},
+ {9, 4},
+ {10, 4},
+ {11, 5},
+ {9000, 5},
};
- size_t idx;
- idx = binsearch(ARRAY_SIZE(haystack), &integer_needle_lesseq, &args);
- check_int(idx, ==, testcases[i].expected_idx);
+ for (size_t i = 0; i < ARRAY_SIZE(testcases); i++) {
+ struct integer_needle_lesseq_args args = {
+ .haystack = haystack,
+ .needle = testcases[i].needle,
+ };
+ size_t idx;
+
+ idx = binsearch(ARRAY_SIZE(haystack),
+ &integer_needle_lesseq, &args);
+ check_int(idx, ==, testcases[i].expected_idx);
+ }
}
-}
-static void test_names_length(void)
-{
- const char *a[] = { "a", "b", NULL };
- check_int(names_length(a), ==, 2);
-}
-
-static void test_names_equal(void)
-{
- const char *a[] = { "a", "b", "c", NULL };
- const char *b[] = { "a", "b", "d", NULL };
- const char *c[] = { "a", "b", NULL };
+ if_test ("names_length retuns size of a NULL-terminated string array") {
+ const char *a[] = { "a", "b", NULL };
+ check_int(names_length(a), ==, 2);
+ }
- check(names_equal(a, a));
- check(!names_equal(a, b));
- check(!names_equal(a, c));
-}
+ if_test ("names_equal compares NULL-terminated string arrays") {
+ const char *a[] = { "a", "b", "c", NULL };
+ const char *b[] = { "a", "b", "d", NULL };
+ const char *c[] = { "a", "b", NULL };
-static void test_parse_names_normal(void)
-{
- char in1[] = "line\n";
- char in2[] = "a\nb\nc";
- char **out = NULL;
- parse_names(in1, strlen(in1), &out);
- check_str(out[0], "line");
- check(!out[1]);
- free_names(out);
-
- parse_names(in2, strlen(in2), &out);
- check_str(out[0], "a");
- check_str(out[1], "b");
- check_str(out[2], "c");
- check(!out[3]);
- free_names(out);
-}
+ check(names_equal(a, a));
+ check(!names_equal(a, b));
+ check(!names_equal(a, c));
+ }
-static void test_parse_names_drop_empty(void)
-{
- char in[] = "a\n\nb\n";
- char **out = NULL;
- parse_names(in, strlen(in), &out);
- check_str(out[0], "a");
- /* simply '\n' should be dropped as empty string */
- check_str(out[1], "b");
- check(!out[2]);
- free_names(out);
-}
+ if_test ("parse_names works for basic input") {
+ char in1[] = "line\n";
+ char in2[] = "a\nb\nc";
+ char **out = NULL;
+ parse_names(in1, strlen(in1), &out);
+ check_str(out[0], "line");
+ check(!out[1]);
+ free_names(out);
+
+ parse_names(in2, strlen(in2), &out);
+ check_str(out[0], "a");
+ check_str(out[1], "b");
+ check_str(out[2], "c");
+ check(!out[3]);
+ free_names(out);
+ }
-static void test_common_prefix(void)
-{
- struct strbuf a = STRBUF_INIT;
- struct strbuf b = STRBUF_INIT;
- struct {
- const char *a, *b;
- int want;
- } cases[] = {
- {"abcdef", "abc", 3},
- { "abc", "ab", 2 },
- { "", "abc", 0 },
- { "abc", "abd", 2 },
- { "abc", "pqr", 0 },
- };
-
- for (size_t i = 0; i < ARRAY_SIZE(cases); i++) {
- strbuf_addstr(&a, cases[i].a);
- strbuf_addstr(&b, cases[i].b);
- check_int(common_prefix_size(&a, &b), ==, cases[i].want);
- strbuf_reset(&a);
- strbuf_reset(&b);
+ if_test ("parse_names drops empty string") {
+ char in[] = "a\n\nb\n";
+ char **out = NULL;
+ parse_names(in, strlen(in), &out);
+ check_str(out[0], "a");
+ /* simply '\n' should be dropped as empty string */
+ check_str(out[1], "b");
+ check(!out[2]);
+ free_names(out);
}
- strbuf_release(&a);
- strbuf_release(&b);
-}
-static void test_u24_roundtrip(void)
-{
- uint32_t in = 0x112233;
- uint8_t dest[3];
- uint32_t out;
- put_be24(dest, in);
- out = get_be24(dest);
- check_int(in, ==, out);
-}
+ if_test ("common_prefix_size works") {
+ struct strbuf a = STRBUF_INIT;
+ struct strbuf b = STRBUF_INIT;
+ struct {
+ const char *a, *b;
+ int want;
+ } cases[] = {
+ {"abcdef", "abc", 3},
+ { "abc", "ab", 2 },
+ { "", "abc", 0 },
+ { "abc", "abd", 2 },
+ { "abc", "pqr", 0 },
+ };
-static void test_u16_roundtrip(void)
-{
- uint32_t in = 0xfef1;
- uint8_t dest[3];
- uint32_t out;
- put_be16(dest, in);
- out = get_be16(dest);
- check_int(in, ==, out);
-}
+ for (size_t i = 0; i < ARRAY_SIZE(cases); i++) {
+ strbuf_addstr(&a, cases[i].a);
+ strbuf_addstr(&b, cases[i].b);
+ check_int(common_prefix_size(&a, &b), ==, cases[i].want);
+ strbuf_reset(&a);
+ strbuf_reset(&b);
+ }
+ strbuf_release(&a);
+ strbuf_release(&b);
+ }
-int cmd_main(int argc, const char *argv[])
-{
- TEST(test_common_prefix(), "common_prefix_size works");
- TEST(test_parse_names_normal(), "parse_names works for basic input");
- TEST(test_parse_names_drop_empty(), "parse_names drops empty string");
- TEST(test_binsearch(), "binary search with binsearch works");
- TEST(test_names_length(), "names_length retuns size of a NULL-terminated string array");
- TEST(test_names_equal(), "names_equal compares NULL-terminated string arrays");
- TEST(test_u24_roundtrip(), "put_be24 and get_be24 work");
- TEST(test_u16_roundtrip(), "put_be16 and get_be16 work");
+ if_test ("put_be24 and get_be24 work") {
+ uint32_t in = 0x112233;
+ uint8_t dest[3];
+ uint32_t out;
+ put_be24(dest, in);
+ out = get_be24(dest);
+ check_int(in, ==, out);
+ }
+
+ if_test ("put_be16 and get_be16 work") {
+ uint32_t in = 0xfef1;
+ uint8_t dest[3];
+ uint32_t out;
+ put_be16(dest, in);
+ out = get_be16(dest);
+ check_int(in, ==, out);
+ }
return test_done();
}
diff --git a/reftable/readwrite_test.c b/t/unit-tests/t-reftable-readwrite.c
index f411abfe9c..2ce56a0523 100644
--- a/reftable/readwrite_test.c
+++ b/t/unit-tests/t-reftable-readwrite.c
@@ -6,37 +6,49 @@ license that can be found in the LICENSE file or at
https://developers.google.com/open-source/licenses/bsd
*/
-#include "system.h"
-
-#include "basics.h"
-#include "block.h"
-#include "blocksource.h"
-#include "reader.h"
-#include "record.h"
-#include "test_framework.h"
-#include "reftable-tests.h"
-#include "reftable-writer.h"
+#include "test-lib.h"
+#include "reftable/basics.h"
+#include "reftable/blocksource.h"
+#include "reftable/reader.h"
+#include "reftable/reftable-error.h"
+#include "reftable/reftable-writer.h"
static const int update_index = 5;
-static void test_buffer(void)
+static void set_test_hash(uint8_t *p, int i)
+{
+ memset(p, (uint8_t)i, hash_size(GIT_SHA1_FORMAT_ID));
+}
+
+static ssize_t strbuf_add_void(void *b, const void *data, size_t sz)
+{
+ strbuf_add(b, data, sz);
+ return sz;
+}
+
+static int noop_flush(void *arg)
+{
+ return 0;
+}
+
+static void t_buffer(void)
{
struct strbuf buf = STRBUF_INIT;
- struct reftable_block_source source = { NULL };
- struct reftable_block out = { NULL };
+ struct reftable_block_source source = { 0 };
+ struct reftable_block out = { 0 };
int n;
uint8_t in[] = "hello";
strbuf_add(&buf, in, sizeof(in));
block_source_from_strbuf(&source, &buf);
- EXPECT(block_source_size(&source) == 6);
+ check_int(block_source_size(&source), ==, 6);
n = block_source_read_block(&source, &out, 0, sizeof(in));
- EXPECT(n == sizeof(in));
- EXPECT(!memcmp(in, out.data, n));
+ check_int(n, ==, sizeof(in));
+ check(!memcmp(in, out.data, n));
reftable_block_done(&out);
n = block_source_read_block(&source, &out, 1, 2);
- EXPECT(n == 2);
- EXPECT(!memcmp(out.data, "el", 2));
+ check_int(n, ==, 2);
+ check(!memcmp(out.data, "el", 2));
reftable_block_done(&out);
block_source_close(&source);
@@ -52,9 +64,9 @@ static void write_table(char ***names, struct strbuf *buf, int N,
};
struct reftable_writer *w =
reftable_new_writer(&strbuf_add_void, &noop_flush, buf, &opts);
- struct reftable_ref_record ref = { NULL };
+ struct reftable_ref_record ref = { 0 };
int i = 0, n;
- struct reftable_log_record log = { NULL };
+ struct reftable_log_record log = { 0 };
const struct reftable_stats *stats = NULL;
REFTABLE_CALLOC_ARRAY(*names, N + 1);
@@ -73,7 +85,7 @@ static void write_table(char ***names, struct strbuf *buf, int N,
(*names)[i] = xstrdup(name);
n = reftable_writer_add_ref(w, &ref);
- EXPECT(n == 0);
+ check_int(n, ==, 0);
}
for (i = 0; i < N; i++) {
@@ -89,27 +101,25 @@ static void write_table(char ***names, struct strbuf *buf, int N,
log.value.update.message = (char *) "message";
n = reftable_writer_add_log(w, &log);
- EXPECT(n == 0);
+ check_int(n, ==, 0);
}
n = reftable_writer_close(w);
- EXPECT(n == 0);
+ check_int(n, ==, 0);
stats = reftable_writer_stats(w);
for (i = 0; i < stats->ref_stats.blocks; i++) {
int off = i * opts.block_size;
- if (off == 0) {
- off = header_size(
- (hash_id == GIT_SHA256_FORMAT_ID) ? 2 : 1);
- }
- EXPECT(buf->buf[off] == 'r');
+ if (!off)
+ off = header_size((hash_id == GIT_SHA256_FORMAT_ID) ? 2 : 1);
+ check_char(buf->buf[off], ==, 'r');
}
- EXPECT(stats->log_stats.blocks > 0);
+ check_int(stats->log_stats.blocks, >, 0);
reftable_writer_free(w);
}
-static void test_log_buffer_size(void)
+static void t_log_buffer_size(void)
{
struct strbuf buf = STRBUF_INIT;
struct reftable_write_options opts = {
@@ -140,14 +150,14 @@ static void test_log_buffer_size(void)
}
reftable_writer_set_limits(w, update_index, update_index);
err = reftable_writer_add_log(w, &log);
- EXPECT_ERR(err);
+ check(!err);
err = reftable_writer_close(w);
- EXPECT_ERR(err);
+ check(!err);
reftable_writer_free(w);
strbuf_release(&buf);
}
-static void test_log_overflow(void)
+static void t_log_overflow(void)
{
struct strbuf buf = STRBUF_INIT;
char msg[256] = { 0 };
@@ -177,12 +187,12 @@ static void test_log_overflow(void)
memset(msg, 'x', sizeof(msg) - 1);
reftable_writer_set_limits(w, update_index, update_index);
err = reftable_writer_add_log(w, &log);
- EXPECT(err == REFTABLE_ENTRY_TOO_BIG_ERROR);
+ check_int(err, ==, REFTABLE_ENTRY_TOO_BIG_ERROR);
reftable_writer_free(w);
strbuf_release(&buf);
}
-static void test_log_write_read(void)
+static void t_log_write_read(void)
{
int N = 2;
char **names = reftable_calloc(N + 1, sizeof(*names));
@@ -190,13 +200,13 @@ static void test_log_write_read(void)
struct reftable_write_options opts = {
.block_size = 256,
};
- struct reftable_ref_record ref = { NULL };
+ struct reftable_ref_record ref = { 0 };
int i = 0;
- struct reftable_log_record log = { NULL };
+ struct reftable_log_record log = { 0 };
int n;
- struct reftable_iterator it = { NULL };
- struct reftable_reader rd = { NULL };
- struct reftable_block_source source = { NULL };
+ struct reftable_iterator it = { 0 };
+ struct reftable_reader rd = { 0 };
+ struct reftable_block_source source = { 0 };
struct strbuf buf = STRBUF_INIT;
struct reftable_writer *w =
reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts);
@@ -204,17 +214,17 @@ static void test_log_write_read(void)
reftable_writer_set_limits(w, 0, N);
for (i = 0; i < N; i++) {
char name[256];
- struct reftable_ref_record ref = { NULL };
+ struct reftable_ref_record ref = { 0 };
snprintf(name, sizeof(name), "b%02d%0*d", i, 130, 7);
names[i] = xstrdup(name);
ref.refname = name;
ref.update_index = i;
err = reftable_writer_add_ref(w, &ref);
- EXPECT_ERR(err);
+ check(!err);
}
for (i = 0; i < N; i++) {
- struct reftable_log_record log = { NULL };
+ struct reftable_log_record log = { 0 };
log.refname = names[i];
log.update_index = i;
@@ -223,33 +233,33 @@ static void test_log_write_read(void)
set_test_hash(log.value.update.new_hash, i + 1);
err = reftable_writer_add_log(w, &log);
- EXPECT_ERR(err);
+ check(!err);
}
n = reftable_writer_close(w);
- EXPECT(n == 0);
+ check_int(n, ==, 0);
stats = reftable_writer_stats(w);
- EXPECT(stats->log_stats.blocks > 0);
+ check_int(stats->log_stats.blocks, >, 0);
reftable_writer_free(w);
w = NULL;
block_source_from_strbuf(&source, &buf);
err = init_reader(&rd, &source, "file.log");
- EXPECT_ERR(err);
+ check(!err);
reftable_reader_init_ref_iterator(&rd, &it);
err = reftable_iterator_seek_ref(&it, names[N - 1]);
- EXPECT_ERR(err);
+ check(!err);
err = reftable_iterator_next_ref(&it, &ref);
- EXPECT_ERR(err);
+ check(!err);
/* end of iteration. */
err = reftable_iterator_next_ref(&it, &ref);
- EXPECT(0 < err);
+ check_int(err, >, 0);
reftable_iterator_destroy(&it);
reftable_ref_record_release(&ref);
@@ -257,23 +267,19 @@ static void test_log_write_read(void)
reftable_reader_init_log_iterator(&rd, &it);
err = reftable_iterator_seek_log(&it, "");
- EXPECT_ERR(err);
+ check(!err);
- i = 0;
- while (1) {
+ for (i = 0; ; i++) {
int err = reftable_iterator_next_log(&it, &log);
- if (err > 0) {
+ if (err > 0)
break;
- }
-
- EXPECT_ERR(err);
- EXPECT_STREQ(names[i], log.refname);
- EXPECT(i == log.update_index);
- i++;
+ check(!err);
+ check_str(names[i], log.refname);
+ check_int(i, ==, log.update_index);
reftable_log_record_release(&log);
}
- EXPECT(i == N);
+ check_int(i, ==, N);
reftable_iterator_destroy(&it);
/* cleanup. */
@@ -282,7 +288,7 @@ static void test_log_write_read(void)
reader_close(&rd);
}
-static void test_log_zlib_corruption(void)
+static void t_log_zlib_corruption(void)
{
struct reftable_write_options opts = {
.block_size = 256,
@@ -316,13 +322,13 @@ static void test_log_zlib_corruption(void)
reftable_writer_set_limits(w, 1, 1);
err = reftable_writer_add_log(w, &log);
- EXPECT_ERR(err);
+ check(!err);
n = reftable_writer_close(w);
- EXPECT(n == 0);
+ check_int(n, ==, 0);
stats = reftable_writer_stats(w);
- EXPECT(stats->log_stats.blocks > 0);
+ check_int(stats->log_stats.blocks, >, 0);
reftable_writer_free(w);
w = NULL;
@@ -332,11 +338,11 @@ static void test_log_zlib_corruption(void)
block_source_from_strbuf(&source, &buf);
err = init_reader(&rd, &source, "file.log");
- EXPECT_ERR(err);
+ check(!err);
reftable_reader_init_log_iterator(&rd, &it);
err = reftable_iterator_seek_log(&it, "refname");
- EXPECT(err == REFTABLE_ZLIB_ERROR);
+ check_int(err, ==, REFTABLE_ZLIB_ERROR);
reftable_iterator_destroy(&it);
@@ -345,14 +351,14 @@ static void test_log_zlib_corruption(void)
reader_close(&rd);
}
-static void test_table_read_write_sequential(void)
+static void t_table_read_write_sequential(void)
{
char **names;
struct strbuf buf = STRBUF_INIT;
int N = 50;
- struct reftable_iterator it = { NULL };
- struct reftable_block_source source = { NULL };
- struct reftable_reader rd = { NULL };
+ struct reftable_iterator it = { 0 };
+ struct reftable_block_source source = { 0 };
+ struct reftable_reader rd = { 0 };
int err = 0;
int j = 0;
@@ -361,26 +367,23 @@ static void test_table_read_write_sequential(void)
block_source_from_strbuf(&source, &buf);
err = init_reader(&rd, &source, "file.ref");
- EXPECT_ERR(err);
+ check(!err);
reftable_reader_init_ref_iterator(&rd, &it);
err = reftable_iterator_seek_ref(&it, "");
- EXPECT_ERR(err);
+ check(!err);
- while (1) {
- struct reftable_ref_record ref = { NULL };
+ for (j = 0; ; j++) {
+ struct reftable_ref_record ref = { 0 };
int r = reftable_iterator_next_ref(&it, &ref);
- EXPECT(r >= 0);
- if (r > 0) {
+ check_int(r, >=, 0);
+ if (r > 0)
break;
- }
- EXPECT(0 == strcmp(names[j], ref.refname));
- EXPECT(update_index == ref.update_index);
-
- j++;
+ check_str(names[j], ref.refname);
+ check_int(update_index, ==, ref.update_index);
reftable_ref_record_release(&ref);
}
- EXPECT(j == N);
+ check_int(j, ==, N);
reftable_iterator_destroy(&it);
strbuf_release(&buf);
free_names(names);
@@ -388,90 +391,85 @@ static void test_table_read_write_sequential(void)
reader_close(&rd);
}
-static void test_table_write_small_table(void)
+static void t_table_write_small_table(void)
{
char **names;
struct strbuf buf = STRBUF_INIT;
int N = 1;
write_table(&names, &buf, N, 4096, GIT_SHA1_FORMAT_ID);
- EXPECT(buf.len < 200);
+ check_int(buf.len, <, 200);
strbuf_release(&buf);
free_names(names);
}
-static void test_table_read_api(void)
+static void t_table_read_api(void)
{
char **names;
struct strbuf buf = STRBUF_INIT;
int N = 50;
- struct reftable_reader rd = { NULL };
- struct reftable_block_source source = { NULL };
+ struct reftable_reader rd = { 0 };
+ struct reftable_block_source source = { 0 };
int err;
- int i;
- struct reftable_log_record log = { NULL };
- struct reftable_iterator it = { NULL };
+ struct reftable_log_record log = { 0 };
+ struct reftable_iterator it = { 0 };
write_table(&names, &buf, N, 256, GIT_SHA1_FORMAT_ID);
block_source_from_strbuf(&source, &buf);
err = init_reader(&rd, &source, "file.ref");
- EXPECT_ERR(err);
+ check(!err);
reftable_reader_init_ref_iterator(&rd, &it);
err = reftable_iterator_seek_ref(&it, names[0]);
- EXPECT_ERR(err);
+ check(!err);
err = reftable_iterator_next_log(&it, &log);
- EXPECT(err == REFTABLE_API_ERROR);
+ check_int(err, ==, REFTABLE_API_ERROR);
strbuf_release(&buf);
- for (i = 0; i < N; i++) {
- reftable_free(names[i]);
- }
+ free_names(names);
reftable_iterator_destroy(&it);
- reftable_free(names);
reader_close(&rd);
strbuf_release(&buf);
}
-static void test_table_read_write_seek(int index, int hash_id)
+static void t_table_read_write_seek(int index, int hash_id)
{
char **names;
struct strbuf buf = STRBUF_INIT;
int N = 50;
- struct reftable_reader rd = { NULL };
- struct reftable_block_source source = { NULL };
+ struct reftable_reader rd = { 0 };
+ struct reftable_block_source source = { 0 };
int err;
int i = 0;
- struct reftable_iterator it = { NULL };
+ struct reftable_iterator it = { 0 };
struct strbuf pastLast = STRBUF_INIT;
- struct reftable_ref_record ref = { NULL };
+ struct reftable_ref_record ref = { 0 };
write_table(&names, &buf, N, 256, hash_id);
block_source_from_strbuf(&source, &buf);
err = init_reader(&rd, &source, "file.ref");
- EXPECT_ERR(err);
- EXPECT(hash_id == reftable_reader_hash_id(&rd));
+ check(!err);
+ check_int(hash_id, ==, reftable_reader_hash_id(&rd));
- if (!index) {
+ if (!index)
rd.ref_offsets.index_offset = 0;
- } else {
- EXPECT(rd.ref_offsets.index_offset > 0);
- }
+ else
+ check_int(rd.ref_offsets.index_offset, >, 0);
for (i = 1; i < N; i++) {
reftable_reader_init_ref_iterator(&rd, &it);
err = reftable_iterator_seek_ref(&it, names[i]);
- EXPECT_ERR(err);
+ check(!err);
err = reftable_iterator_next_ref(&it, &ref);
- EXPECT_ERR(err);
- EXPECT(0 == strcmp(names[i], ref.refname));
- EXPECT(REFTABLE_REF_VAL1 == ref.value_type);
- EXPECT(i == ref.value.val1[0]);
+ check(!err);
+ check_str(names[i], ref.refname);
+ check_int(REFTABLE_REF_VAL1, ==, ref.value_type);
+ check_int(i, ==, ref.value.val1[0]);
reftable_ref_record_release(&ref);
reftable_iterator_destroy(&it);
@@ -483,40 +481,37 @@ static void test_table_read_write_seek(int index, int hash_id)
reftable_reader_init_ref_iterator(&rd, &it);
err = reftable_iterator_seek_ref(&it, pastLast.buf);
if (err == 0) {
- struct reftable_ref_record ref = { NULL };
+ struct reftable_ref_record ref = { 0 };
int err = reftable_iterator_next_ref(&it, &ref);
- EXPECT(err > 0);
+ check_int(err, >, 0);
} else {
- EXPECT(err > 0);
+ check_int(err, >, 0);
}
strbuf_release(&pastLast);
reftable_iterator_destroy(&it);
strbuf_release(&buf);
- for (i = 0; i < N; i++) {
- reftable_free(names[i]);
- }
- reftable_free(names);
+ free_names(names);
reader_close(&rd);
}
-static void test_table_read_write_seek_linear(void)
+static void t_table_read_write_seek_linear(void)
{
- test_table_read_write_seek(0, GIT_SHA1_FORMAT_ID);
+ t_table_read_write_seek(0, GIT_SHA1_FORMAT_ID);
}
-static void test_table_read_write_seek_linear_sha256(void)
+static void t_table_read_write_seek_linear_sha256(void)
{
- test_table_read_write_seek(0, GIT_SHA256_FORMAT_ID);
+ t_table_read_write_seek(0, GIT_SHA256_FORMAT_ID);
}
-static void test_table_read_write_seek_index(void)
+static void t_table_read_write_seek_index(void)
{
- test_table_read_write_seek(1, GIT_SHA1_FORMAT_ID);
+ t_table_read_write_seek(1, GIT_SHA1_FORMAT_ID);
}
-static void test_table_refs_for(int indexed)
+static void t_table_refs_for(int indexed)
{
int N = 50;
char **want_names = reftable_calloc(N + 1, sizeof(*want_names));
@@ -526,18 +521,18 @@ static void test_table_refs_for(int indexed)
struct reftable_write_options opts = {
.block_size = 256,
};
- struct reftable_ref_record ref = { NULL };
+ struct reftable_ref_record ref = { 0 };
int i = 0;
int n;
int err;
struct reftable_reader rd;
- struct reftable_block_source source = { NULL };
+ struct reftable_block_source source = { 0 };
struct strbuf buf = STRBUF_INIT;
struct reftable_writer *w =
reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts);
- struct reftable_iterator it = { NULL };
+ struct reftable_iterator it = { 0 };
int j;
set_test_hash(want_hash, 4);
@@ -546,7 +541,7 @@ static void test_table_refs_for(int indexed)
uint8_t hash[GIT_SHA1_RAWSZ];
char fill[51] = { 0 };
char name[100];
- struct reftable_ref_record ref = { NULL };
+ struct reftable_ref_record ref = { 0 };
memset(hash, i, sizeof(hash));
memset(fill, 'x', 50);
@@ -563,16 +558,15 @@ static void test_table_refs_for(int indexed)
*/
/* blocks. */
n = reftable_writer_add_ref(w, &ref);
- EXPECT(n == 0);
+ check_int(n, ==, 0);
if (!memcmp(ref.value.val2.value, want_hash, GIT_SHA1_RAWSZ) ||
- !memcmp(ref.value.val2.target_value, want_hash, GIT_SHA1_RAWSZ)) {
+ !memcmp(ref.value.val2.target_value, want_hash, GIT_SHA1_RAWSZ))
want_names[want_names_len++] = xstrdup(name);
- }
}
n = reftable_writer_close(w);
- EXPECT(n == 0);
+ check_int(n, ==, 0);
reftable_writer_free(w);
w = NULL;
@@ -580,33 +574,28 @@ static void test_table_refs_for(int indexed)
block_source_from_strbuf(&source, &buf);
err = init_reader(&rd, &source, "file.ref");
- EXPECT_ERR(err);
- if (!indexed) {
+ check(!err);
+ if (!indexed)
rd.obj_offsets.is_present = 0;
- }
reftable_reader_init_ref_iterator(&rd, &it);
err = reftable_iterator_seek_ref(&it, "");
- EXPECT_ERR(err);
+ check(!err);
reftable_iterator_destroy(&it);
err = reftable_reader_refs_for(&rd, &it, want_hash);
- EXPECT_ERR(err);
+ check(!err);
- j = 0;
- while (1) {
+ for (j = 0; ; j++) {
int err = reftable_iterator_next_ref(&it, &ref);
- EXPECT(err >= 0);
- if (err > 0) {
+ check_int(err, >=, 0);
+ if (err > 0)
break;
- }
-
- EXPECT(j < want_names_len);
- EXPECT(0 == strcmp(ref.refname, want_names[j]));
- j++;
+ check_int(j, <, want_names_len);
+ check_str(ref.refname, want_names[j]);
reftable_ref_record_release(&ref);
}
- EXPECT(j == want_names_len);
+ check_int(j, ==, want_names_len);
strbuf_release(&buf);
free_names(want_names);
@@ -614,54 +603,54 @@ static void test_table_refs_for(int indexed)
reader_close(&rd);
}
-static void test_table_refs_for_no_index(void)
+static void t_table_refs_for_no_index(void)
{
- test_table_refs_for(0);
+ t_table_refs_for(0);
}
-static void test_table_refs_for_obj_index(void)
+static void t_table_refs_for_obj_index(void)
{
- test_table_refs_for(1);
+ t_table_refs_for(1);
}
-static void test_write_empty_table(void)
+static void t_write_empty_table(void)
{
struct reftable_write_options opts = { 0 };
struct strbuf buf = STRBUF_INIT;
struct reftable_writer *w =
reftable_new_writer(&strbuf_add_void, &noop_flush, &buf, &opts);
- struct reftable_block_source source = { NULL };
+ struct reftable_block_source source = { 0 };
struct reftable_reader *rd = NULL;
- struct reftable_ref_record rec = { NULL };
- struct reftable_iterator it = { NULL };
+ struct reftable_ref_record rec = { 0 };
+ struct reftable_iterator it = { 0 };
int err;
reftable_writer_set_limits(w, 1, 1);
err = reftable_writer_close(w);
- EXPECT(err == REFTABLE_EMPTY_TABLE_ERROR);
+ check_int(err, ==, REFTABLE_EMPTY_TABLE_ERROR);
reftable_writer_free(w);
- EXPECT(buf.len == header_size(1) + footer_size(1));
+ check_int(buf.len, ==, header_size(1) + footer_size(1));
block_source_from_strbuf(&source, &buf);
err = reftable_new_reader(&rd, &source, "filename");
- EXPECT_ERR(err);
+ check(!err);
reftable_reader_init_ref_iterator(rd, &it);
err = reftable_iterator_seek_ref(&it, "");
- EXPECT_ERR(err);
+ check(!err);
err = reftable_iterator_next_ref(&it, &rec);
- EXPECT(err > 0);
+ check_int(err, >, 0);
reftable_iterator_destroy(&it);
reftable_reader_free(rd);
strbuf_release(&buf);
}
-static void test_write_object_id_min_length(void)
+static void t_write_object_id_min_length(void)
{
struct reftable_write_options opts = {
.block_size = 75,
@@ -686,17 +675,17 @@ static void test_write_object_id_min_length(void)
snprintf(name, sizeof(name), "ref%05d", i);
ref.refname = name;
err = reftable_writer_add_ref(w, &ref);
- EXPECT_ERR(err);
+ check(!err);
}
err = reftable_writer_close(w);
- EXPECT_ERR(err);
- EXPECT(reftable_writer_stats(w)->object_id_len == 2);
+ check(!err);
+ check_int(reftable_writer_stats(w)->object_id_len, ==, 2);
reftable_writer_free(w);
strbuf_release(&buf);
}
-static void test_write_object_id_length(void)
+static void t_write_object_id_length(void)
{
struct reftable_write_options opts = {
.block_size = 75,
@@ -722,17 +711,17 @@ static void test_write_object_id_length(void)
ref.refname = name;
ref.value.val1[15] = i;
err = reftable_writer_add_ref(w, &ref);
- EXPECT_ERR(err);
+ check(!err);
}
err = reftable_writer_close(w);
- EXPECT_ERR(err);
- EXPECT(reftable_writer_stats(w)->object_id_len == 16);
+ check(!err);
+ check_int(reftable_writer_stats(w)->object_id_len, ==, 16);
reftable_writer_free(w);
strbuf_release(&buf);
}
-static void test_write_empty_key(void)
+static void t_write_empty_key(void)
{
struct reftable_write_options opts = { 0 };
struct strbuf buf = STRBUF_INIT;
@@ -747,15 +736,15 @@ static void test_write_empty_key(void)
reftable_writer_set_limits(w, 1, 1);
err = reftable_writer_add_ref(w, &ref);
- EXPECT(err == REFTABLE_API_ERROR);
+ check_int(err, ==, REFTABLE_API_ERROR);
err = reftable_writer_close(w);
- EXPECT(err == REFTABLE_EMPTY_TABLE_ERROR);
+ check_int(err, ==, REFTABLE_EMPTY_TABLE_ERROR);
reftable_writer_free(w);
strbuf_release(&buf);
}
-static void test_write_key_order(void)
+static void t_write_key_order(void)
{
struct reftable_write_options opts = { 0 };
struct strbuf buf = STRBUF_INIT;
@@ -782,15 +771,20 @@ static void test_write_key_order(void)
reftable_writer_set_limits(w, 1, 1);
err = reftable_writer_add_ref(w, &refs[0]);
- EXPECT_ERR(err);
+ check(!err);
err = reftable_writer_add_ref(w, &refs[1]);
- EXPECT(err == REFTABLE_API_ERROR);
+ check_int(err, ==, REFTABLE_API_ERROR);
+
+ refs[0].update_index = 2;
+ err = reftable_writer_add_ref(w, &refs[0]);
+ check_int(err, ==, REFTABLE_API_ERROR);
+
reftable_writer_close(w);
reftable_writer_free(w);
strbuf_release(&buf);
}
-static void test_write_multiple_indices(void)
+static void t_write_multiple_indices(void)
{
struct reftable_write_options opts = {
.block_size = 100,
@@ -817,7 +811,7 @@ static void test_write_multiple_indices(void)
ref.refname = buf.buf,
err = reftable_writer_add_ref(writer, &ref);
- EXPECT_ERR(err);
+ check(!err);
}
for (i = 0; i < 100; i++) {
@@ -835,7 +829,7 @@ static void test_write_multiple_indices(void)
log.refname = buf.buf,
err = reftable_writer_add_log(writer, &log);
- EXPECT_ERR(err);
+ check(!err);
}
reftable_writer_close(writer);
@@ -845,13 +839,13 @@ static void test_write_multiple_indices(void)
* for each of the block types.
*/
stats = reftable_writer_stats(writer);
- EXPECT(stats->ref_stats.index_offset > 0);
- EXPECT(stats->obj_stats.index_offset > 0);
- EXPECT(stats->log_stats.index_offset > 0);
+ check_int(stats->ref_stats.index_offset, >, 0);
+ check_int(stats->obj_stats.index_offset, >, 0);
+ check_int(stats->log_stats.index_offset, >, 0);
block_source_from_strbuf(&source, &writer_buf);
err = reftable_new_reader(&reader, &source, "filename");
- EXPECT_ERR(err);
+ check(!err);
/*
* Seeking the log uses the log index now. In case there is any
@@ -859,7 +853,7 @@ static void test_write_multiple_indices(void)
*/
reftable_reader_init_log_iterator(reader, &it);
err = reftable_iterator_seek_log(&it, "");
- EXPECT_ERR(err);
+ check(!err);
reftable_iterator_destroy(&it);
reftable_writer_free(writer);
@@ -868,7 +862,7 @@ static void test_write_multiple_indices(void)
strbuf_release(&buf);
}
-static void test_write_multi_level_index(void)
+static void t_write_multi_level_index(void)
{
struct reftable_write_options opts = {
.block_size = 100,
@@ -895,7 +889,7 @@ static void test_write_multi_level_index(void)
ref.refname = buf.buf,
err = reftable_writer_add_ref(writer, &ref);
- EXPECT_ERR(err);
+ check(!err);
}
reftable_writer_close(writer);
@@ -904,18 +898,18 @@ static void test_write_multi_level_index(void)
* multi-level index.
*/
stats = reftable_writer_stats(writer);
- EXPECT(stats->ref_stats.max_index_level == 2);
+ check_int(stats->ref_stats.max_index_level, ==, 2);
block_source_from_strbuf(&source, &writer_buf);
err = reftable_new_reader(&reader, &source, "filename");
- EXPECT_ERR(err);
+ check(!err);
/*
* Seeking the last ref should work as expected.
*/
reftable_reader_init_ref_iterator(reader, &it);
err = reftable_iterator_seek_ref(&it, "refs/heads/199");
- EXPECT_ERR(err);
+ check(!err);
reftable_iterator_destroy(&it);
reftable_writer_free(writer);
@@ -924,56 +918,57 @@ static void test_write_multi_level_index(void)
strbuf_release(&buf);
}
-static void test_corrupt_table_empty(void)
+static void t_corrupt_table_empty(void)
{
struct strbuf buf = STRBUF_INIT;
- struct reftable_block_source source = { NULL };
- struct reftable_reader rd = { NULL };
+ struct reftable_block_source source = { 0 };
+ struct reftable_reader rd = { 0 };
int err;
block_source_from_strbuf(&source, &buf);
err = init_reader(&rd, &source, "file.log");
- EXPECT(err == REFTABLE_FORMAT_ERROR);
+ check_int(err, ==, REFTABLE_FORMAT_ERROR);
}
-static void test_corrupt_table(void)
+static void t_corrupt_table(void)
{
uint8_t zeros[1024] = { 0 };
struct strbuf buf = STRBUF_INIT;
- struct reftable_block_source source = { NULL };
- struct reftable_reader rd = { NULL };
+ struct reftable_block_source source = { 0 };
+ struct reftable_reader rd = { 0 };
int err;
strbuf_add(&buf, zeros, sizeof(zeros));
block_source_from_strbuf(&source, &buf);
err = init_reader(&rd, &source, "file.log");
- EXPECT(err == REFTABLE_FORMAT_ERROR);
+ check_int(err, ==, REFTABLE_FORMAT_ERROR);
strbuf_release(&buf);
}
-int readwrite_test_main(int argc, const char *argv[])
+int cmd_main(int argc, const char *argv[])
{
- RUN_TEST(test_log_zlib_corruption);
- RUN_TEST(test_corrupt_table);
- RUN_TEST(test_corrupt_table_empty);
- RUN_TEST(test_log_write_read);
- RUN_TEST(test_write_key_order);
- RUN_TEST(test_table_read_write_seek_linear_sha256);
- RUN_TEST(test_log_buffer_size);
- RUN_TEST(test_table_write_small_table);
- RUN_TEST(test_buffer);
- RUN_TEST(test_table_read_api);
- RUN_TEST(test_table_read_write_sequential);
- RUN_TEST(test_table_read_write_seek_linear);
- RUN_TEST(test_table_read_write_seek_index);
- RUN_TEST(test_table_refs_for_no_index);
- RUN_TEST(test_table_refs_for_obj_index);
- RUN_TEST(test_write_empty_key);
- RUN_TEST(test_write_empty_table);
- RUN_TEST(test_log_overflow);
- RUN_TEST(test_write_object_id_length);
- RUN_TEST(test_write_object_id_min_length);
- RUN_TEST(test_write_multiple_indices);
- RUN_TEST(test_write_multi_level_index);
- return 0;
+ TEST(t_buffer(), "strbuf works as blocksource");
+ TEST(t_corrupt_table(), "read-write on corrupted table");
+ TEST(t_corrupt_table_empty(), "read-write on an empty table");
+ TEST(t_log_buffer_size(), "buffer extension for log compression");
+ TEST(t_log_overflow(), "log overflow returns expected error");
+ TEST(t_log_write_read(), "read-write on log records");
+ TEST(t_log_zlib_corruption(), "reading corrupted log record returns expected error");
+ TEST(t_table_read_api(), "read on a table");
+ TEST(t_table_read_write_seek_index(), "read-write on a table with index");
+ TEST(t_table_read_write_seek_linear(), "read-write on a table without index (SHA1)");
+ TEST(t_table_read_write_seek_linear_sha256(), "read-write on a table without index (SHA256)");
+ TEST(t_table_read_write_sequential(), "sequential read-write on a table");
+ TEST(t_table_refs_for_no_index(), "refs-only table with no index");
+ TEST(t_table_refs_for_obj_index(), "refs-only table with index");
+ TEST(t_table_write_small_table(), "write_table works");
+ TEST(t_write_empty_key(), "write on refs with empty keys");
+ TEST(t_write_empty_table(), "read-write on empty tables");
+ TEST(t_write_key_order(), "refs must be written in increasing order");
+ TEST(t_write_multi_level_index(), "table with multi-level index");
+ TEST(t_write_multiple_indices(), "table with indices for multiple block types");
+ TEST(t_write_object_id_length(), "prefix compression on writing refs");
+ TEST(t_write_object_id_min_length(), "prefix compression on writing refs");
+
+ return test_done();
}
diff --git a/t/unit-tests/t-strvec.c b/t/unit-tests/t-strvec.c
index fa1a041469..c4bac8fc91 100644
--- a/t/unit-tests/t-strvec.c
+++ b/t/unit-tests/t-strvec.c
@@ -19,237 +19,193 @@
} \
} while (0)
-static void t_static_init(void)
-{
- struct strvec vec = STRVEC_INIT;
- check_pointer_eq(vec.v, empty_strvec);
- check_uint(vec.nr, ==, 0);
- check_uint(vec.alloc, ==, 0);
-}
-
-static void t_dynamic_init(void)
-{
- struct strvec vec;
- strvec_init(&vec);
- check_pointer_eq(vec.v, empty_strvec);
- check_uint(vec.nr, ==, 0);
- check_uint(vec.alloc, ==, 0);
-}
-
-static void t_clear(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_push(&vec, "foo");
- strvec_clear(&vec);
- check_pointer_eq(vec.v, empty_strvec);
- check_uint(vec.nr, ==, 0);
- check_uint(vec.alloc, ==, 0);
-}
-
-static void t_push(void)
-{
- struct strvec vec = STRVEC_INIT;
-
- strvec_push(&vec, "foo");
- check_strvec(&vec, "foo", NULL);
-
- strvec_push(&vec, "bar");
- check_strvec(&vec, "foo", "bar", NULL);
-
- strvec_clear(&vec);
-}
-
-static void t_pushf(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushf(&vec, "foo: %d", 1);
- check_strvec(&vec, "foo: 1", NULL);
- strvec_clear(&vec);
-}
-
-static void t_pushl(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushl(&vec, "foo", "bar", "baz", NULL);
- check_strvec(&vec, "foo", "bar", "baz", NULL);
- strvec_clear(&vec);
-}
-
-static void t_pushv(void)
-{
- const char *strings[] = {
- "foo", "bar", "baz", NULL,
- };
- struct strvec vec = STRVEC_INIT;
-
- strvec_pushv(&vec, strings);
- check_strvec(&vec, "foo", "bar", "baz", NULL);
-
- strvec_clear(&vec);
-}
-
-static void t_replace_at_head(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushl(&vec, "foo", "bar", "baz", NULL);
- strvec_replace(&vec, 0, "replaced");
- check_strvec(&vec, "replaced", "bar", "baz", NULL);
- strvec_clear(&vec);
-}
-
-static void t_replace_at_tail(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushl(&vec, "foo", "bar", "baz", NULL);
- strvec_replace(&vec, 2, "replaced");
- check_strvec(&vec, "foo", "bar", "replaced", NULL);
- strvec_clear(&vec);
-}
-
-static void t_replace_in_between(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushl(&vec, "foo", "bar", "baz", NULL);
- strvec_replace(&vec, 1, "replaced");
- check_strvec(&vec, "foo", "replaced", "baz", NULL);
- strvec_clear(&vec);
-}
-
-static void t_replace_with_substring(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushl(&vec, "foo", NULL);
- strvec_replace(&vec, 0, vec.v[0] + 1);
- check_strvec(&vec, "oo", NULL);
- strvec_clear(&vec);
-}
-
-static void t_remove_at_head(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushl(&vec, "foo", "bar", "baz", NULL);
- strvec_remove(&vec, 0);
- check_strvec(&vec, "bar", "baz", NULL);
- strvec_clear(&vec);
-}
-
-static void t_remove_at_tail(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushl(&vec, "foo", "bar", "baz", NULL);
- strvec_remove(&vec, 2);
- check_strvec(&vec, "foo", "bar", NULL);
- strvec_clear(&vec);
-}
-
-static void t_remove_in_between(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushl(&vec, "foo", "bar", "baz", NULL);
- strvec_remove(&vec, 1);
- check_strvec(&vec, "foo", "baz", NULL);
- strvec_clear(&vec);
-}
-
-static void t_pop_empty_array(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pop(&vec);
- check_strvec(&vec, NULL);
- strvec_clear(&vec);
-}
-
-static void t_pop_non_empty_array(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_pushl(&vec, "foo", "bar", "baz", NULL);
- strvec_pop(&vec);
- check_strvec(&vec, "foo", "bar", NULL);
- strvec_clear(&vec);
-}
-
-static void t_split_empty_string(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_split(&vec, "");
- check_strvec(&vec, NULL);
- strvec_clear(&vec);
-}
-
-static void t_split_single_item(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_split(&vec, "foo");
- check_strvec(&vec, "foo", NULL);
- strvec_clear(&vec);
-}
-
-static void t_split_multiple_items(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_split(&vec, "foo bar baz");
- check_strvec(&vec, "foo", "bar", "baz", NULL);
- strvec_clear(&vec);
-}
-
-static void t_split_whitespace_only(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_split(&vec, " \t\n");
- check_strvec(&vec, NULL);
- strvec_clear(&vec);
-}
-
-static void t_split_multiple_consecutive_whitespaces(void)
-{
- struct strvec vec = STRVEC_INIT;
- strvec_split(&vec, "foo\n\t bar");
- check_strvec(&vec, "foo", "bar", NULL);
- strvec_clear(&vec);
-}
-
-static void t_detach(void)
-{
- struct strvec vec = STRVEC_INIT;
- const char **detached;
-
- strvec_push(&vec, "foo");
-
- detached = strvec_detach(&vec);
- check_str(detached[0], "foo");
- check_pointer_eq(detached[1], NULL);
-
- check_pointer_eq(vec.v, empty_strvec);
- check_uint(vec.nr, ==, 0);
- check_uint(vec.alloc, ==, 0);
-
- free((char *) detached[0]);
- free(detached);
-}
-
int cmd_main(int argc, const char **argv)
{
- TEST(t_static_init(), "static initialization");
- TEST(t_dynamic_init(), "dynamic initialization");
- TEST(t_clear(), "clear");
- TEST(t_push(), "push");
- TEST(t_pushf(), "pushf");
- TEST(t_pushl(), "pushl");
- TEST(t_pushv(), "pushv");
- TEST(t_replace_at_head(), "replace at head");
- TEST(t_replace_in_between(), "replace in between");
- TEST(t_replace_at_tail(), "replace at tail");
- TEST(t_replace_with_substring(), "replace with substring");
- TEST(t_remove_at_head(), "remove at head");
- TEST(t_remove_in_between(), "remove in between");
- TEST(t_remove_at_tail(), "remove at tail");
- TEST(t_pop_empty_array(), "pop with empty array");
- TEST(t_pop_non_empty_array(), "pop with non-empty array");
- TEST(t_split_empty_string(), "split empty string");
- TEST(t_split_single_item(), "split single item");
- TEST(t_split_multiple_items(), "split multiple items");
- TEST(t_split_whitespace_only(), "split whitespace only");
- TEST(t_split_multiple_consecutive_whitespaces(), "split multiple consecutive whitespaces");
- TEST(t_detach(), "detach");
+ if_test ("static initialization") {
+ struct strvec vec = STRVEC_INIT;
+ check_pointer_eq(vec.v, empty_strvec);
+ check_uint(vec.nr, ==, 0);
+ check_uint(vec.alloc, ==, 0);
+ }
+
+ if_test ("dynamic initialization") {
+ struct strvec vec;
+ strvec_init(&vec);
+ check_pointer_eq(vec.v, empty_strvec);
+ check_uint(vec.nr, ==, 0);
+ check_uint(vec.alloc, ==, 0);
+ }
+
+ if_test ("clear") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_push(&vec, "foo");
+ strvec_clear(&vec);
+ check_pointer_eq(vec.v, empty_strvec);
+ check_uint(vec.nr, ==, 0);
+ check_uint(vec.alloc, ==, 0);
+ }
+
+ if_test ("push") {
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_push(&vec, "foo");
+ check_strvec(&vec, "foo", NULL);
+
+ strvec_push(&vec, "bar");
+ check_strvec(&vec, "foo", "bar", NULL);
+
+ strvec_clear(&vec);
+ }
+
+ if_test ("pushf") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushf(&vec, "foo: %d", 1);
+ check_strvec(&vec, "foo: 1", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("pushl") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ check_strvec(&vec, "foo", "bar", "baz", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("pushv") {
+ const char *strings[] = {
+ "foo", "bar", "baz", NULL,
+ };
+ struct strvec vec = STRVEC_INIT;
+
+ strvec_pushv(&vec, strings);
+ check_strvec(&vec, "foo", "bar", "baz", NULL);
+
+ strvec_clear(&vec);
+ }
+
+ if_test ("replace at head") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_replace(&vec, 0, "replaced");
+ check_strvec(&vec, "replaced", "bar", "baz", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("replace at tail") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_replace(&vec, 2, "replaced");
+ check_strvec(&vec, "foo", "bar", "replaced", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("replace in between") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_replace(&vec, 1, "replaced");
+ check_strvec(&vec, "foo", "replaced", "baz", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("replace with substring") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", NULL);
+ strvec_replace(&vec, 0, vec.v[0] + 1);
+ check_strvec(&vec, "oo", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("remove at head") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_remove(&vec, 0);
+ check_strvec(&vec, "bar", "baz", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("remove at tail") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_remove(&vec, 2);
+ check_strvec(&vec, "foo", "bar", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("remove in between") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_remove(&vec, 1);
+ check_strvec(&vec, "foo", "baz", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("pop with empty array") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pop(&vec);
+ check_strvec(&vec, NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("pop with non-empty array") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_pushl(&vec, "foo", "bar", "baz", NULL);
+ strvec_pop(&vec);
+ check_strvec(&vec, "foo", "bar", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("split empty string") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_split(&vec, "");
+ check_strvec(&vec, NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("split single item") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_split(&vec, "foo");
+ check_strvec(&vec, "foo", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("split multiple items") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_split(&vec, "foo bar baz");
+ check_strvec(&vec, "foo", "bar", "baz", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("split whitespace only") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_split(&vec, " \t\n");
+ check_strvec(&vec, NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("split multiple consecutive whitespaces") {
+ struct strvec vec = STRVEC_INIT;
+ strvec_split(&vec, "foo\n\t bar");
+ check_strvec(&vec, "foo", "bar", NULL);
+ strvec_clear(&vec);
+ }
+
+ if_test ("detach") {
+ struct strvec vec = STRVEC_INIT;
+ const char **detached;
+
+ strvec_push(&vec, "foo");
+
+ detached = strvec_detach(&vec);
+ check_str(detached[0], "foo");
+ check_pointer_eq(detached[1], NULL);
+
+ check_pointer_eq(vec.v, empty_strvec);
+ check_uint(vec.nr, ==, 0);
+ check_uint(vec.alloc, ==, 0);
+
+ free((char *) detached[0]);
+ free(detached);
+ }
+
return test_done();
}
diff --git a/t/unit-tests/test-lib.c b/t/unit-tests/test-lib.c
index 3c513ce59a..fa1f95965c 100644
--- a/t/unit-tests/test-lib.c
+++ b/t/unit-tests/test-lib.c
@@ -16,6 +16,8 @@ static struct {
unsigned running :1;
unsigned skip_all :1;
unsigned todo :1;
+ char location[100];
+ char description[100];
} ctx = {
.lazy_plan = 1,
.result = RESULT_NONE,
@@ -125,6 +127,8 @@ void test_plan(int count)
int test_done(void)
{
+ if (ctx.running && ctx.location[0] && ctx.description[0])
+ test__run_end(1, ctx.location, "%s", ctx.description);
assert(!ctx.running);
if (ctx.lazy_plan)
@@ -167,13 +171,38 @@ void test_skip_all(const char *format, ...)
va_end(ap);
}
+void test__run_describe(const char *location, const char *format, ...)
+{
+ va_list ap;
+ int len;
+
+ assert(ctx.running);
+ assert(!ctx.location[0]);
+ assert(!ctx.description[0]);
+
+ xsnprintf(ctx.location, sizeof(ctx.location), "%s",
+ make_relative(location));
+
+ va_start(ap, format);
+ len = vsnprintf(ctx.description, sizeof(ctx.description), format, ap);
+ va_end(ap);
+ if (len < 0)
+ die("unable to format message: %s", format);
+ if (len >= sizeof(ctx.description))
+ BUG("ctx.description too small to format %s", format);
+}
+
int test__run_begin(void)
{
+ if (ctx.running && ctx.location[0] && ctx.description[0])
+ test__run_end(1, ctx.location, "%s", ctx.description);
assert(!ctx.running);
ctx.count++;
ctx.result = RESULT_NONE;
ctx.running = 1;
+ ctx.location[0] = '\0';
+ ctx.description[0] = '\0';
return ctx.skip_all;
}
@@ -264,7 +293,12 @@ static void test_todo(void)
int test_assert(const char *location, const char *check, int ok)
{
- assert(ctx.running);
+ if (!ctx.running) {
+ test_msg("BUG: check outside of test at %s",
+ make_relative(location));
+ ctx.failed = 1;
+ return 0;
+ }
if (ctx.result == RESULT_SKIP) {
test_msg("skipping check '%s' at %s", check,
diff --git a/t/unit-tests/test-lib.h b/t/unit-tests/test-lib.h
index c59f646fd9..e4b234697f 100644
--- a/t/unit-tests/test-lib.h
+++ b/t/unit-tests/test-lib.h
@@ -15,6 +15,23 @@
TEST_LOCATION(), __VA_ARGS__)
/*
+ * Run a test unless test_skip_all() has been called. Acts like a
+ * conditional; the test body is expected as a statement or block after
+ * the closing parenthesis. The description for each test should be
+ * unique. E.g.:
+ *
+ * if_test ("something else %d %d", arg1, arg2) {
+ * prepare();
+ * test_something_else(arg1, arg2);
+ * cleanup();
+ * }
+ */
+#define if_test(...) \
+ if (test__run_begin() ? \
+ (test__run_end(0, TEST_LOCATION(), __VA_ARGS__), 0) : \
+ (test__run_describe(TEST_LOCATION(), __VA_ARGS__), 1))
+
+/*
* Print a test plan, should be called before any tests. If the number
* of tests is not known in advance test_done() will automatically
* print a plan at the end of the test program.
@@ -154,6 +171,9 @@ union test__tmp {
extern union test__tmp test__tmp[2];
+__attribute__((format (printf, 2, 3)))
+void test__run_describe(const char *, const char *, ...);
+
int test__run_begin(void);
__attribute__((format (printf, 3, 4)))
int test__run_end(int, const char *, const char *, ...);
diff --git a/trailer.c b/trailer.c
index 72e5136c73..682d74505b 100644
--- a/trailer.c
+++ b/trailer.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "environment.h"
diff --git a/transport.c b/transport.c
index 7c4af9f56f..bab28965f9 100644
--- a/transport.c
+++ b/transport.c
@@ -1273,7 +1273,7 @@ static int run_pre_push_hook(struct transport *transport,
struct ref *r;
struct child_process proc = CHILD_PROCESS_INIT;
struct strbuf buf;
- const char *hook_path = find_hook("pre-push");
+ const char *hook_path = find_hook(the_repository, "pre-push");
if (!hook_path)
return 0;
diff --git a/unpack-trees.c b/unpack-trees.c
index 7dc884fafd..9a55cb6204 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -210,6 +210,7 @@ void clear_unpack_trees_porcelain(struct unpack_trees_options *opts)
{
strvec_clear(&opts->internal.msgs_to_free);
memset(opts->internal.msgs, 0, sizeof(opts->internal.msgs));
+ discard_index(&opts->internal.result);
}
static int do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
@@ -2082,6 +2083,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
o->internal.result.updated_workdir = 1;
discard_index(o->dst_index);
*o->dst_index = o->internal.result;
+ memset(&o->internal.result, 0, sizeof(o->internal.result));
} else {
discard_index(&o->internal.result);
}
diff --git a/upload-pack.c b/upload-pack.c
index 0052c6a4dc..f03ba3e98b 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -857,7 +857,7 @@ static void send_unshallow(struct upload_pack_data *data)
}
}
-static int check_ref(const char *refname_full, const struct object_id *oid,
+static int check_ref(const char *refname_full, const char *referent UNUSED, const struct object_id *oid,
int flag, void *cb_data);
static void deepen(struct upload_pack_data *data, int depth)
{
@@ -1208,7 +1208,7 @@ static int mark_our_ref(const char *refname, const char *refname_full,
return 0;
}
-static int check_ref(const char *refname_full, const struct object_id *oid,
+static int check_ref(const char *refname_full, const char *referent UNUSED,const struct object_id *oid,
int flag UNUSED, void *cb_data)
{
const char *refname = strip_namespace(refname_full);
@@ -1276,14 +1276,14 @@ static void write_v0_ref(struct upload_pack_data *data,
return;
}
-static int send_ref(const char *refname, const struct object_id *oid,
+static int send_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
int flag UNUSED, void *cb_data)
{
write_v0_ref(cb_data, refname, strip_namespace(refname), oid);
return 0;
}
-static int find_symref(const char *refname,
+static int find_symref(const char *refname, const char *referent UNUSED,
const struct object_id *oid UNUSED,
int flag, void *cb_data)
{
diff --git a/userdiff.c b/userdiff.c
index c4ebb9ff73..989629149f 100644
--- a/userdiff.c
+++ b/userdiff.c
@@ -399,8 +399,11 @@ static struct userdiff_driver *userdiff_find_by_namelen(const char *name, size_t
static int parse_funcname(struct userdiff_funcname *f, const char *k,
const char *v, int cflags)
{
- if (git_config_string((char **) &f->pattern, k, v) < 0)
+ f->pattern = NULL;
+ FREE_AND_NULL(f->pattern_owned);
+ if (git_config_string(&f->pattern_owned, k, v) < 0)
return -1;
+ f->pattern = f->pattern_owned;
f->cflags = cflags;
return 0;
}
@@ -444,20 +447,37 @@ int userdiff_config(const char *k, const char *v)
return parse_funcname(&drv->funcname, k, v, REG_EXTENDED);
if (!strcmp(type, "binary"))
return parse_tristate(&drv->binary, k, v);
- if (!strcmp(type, "command"))
- return git_config_string((char **) &drv->external.cmd, k, v);
+ if (!strcmp(type, "command")) {
+ FREE_AND_NULL(drv->external.cmd);
+ return git_config_string(&drv->external.cmd, k, v);
+ }
if (!strcmp(type, "trustexitcode")) {
drv->external.trust_exit_code = git_config_bool(k, v);
return 0;
}
- if (!strcmp(type, "textconv"))
- return git_config_string((char **) &drv->textconv, k, v);
+ if (!strcmp(type, "textconv")) {
+ int ret;
+ FREE_AND_NULL(drv->textconv_owned);
+ ret = git_config_string(&drv->textconv_owned, k, v);
+ drv->textconv = drv->textconv_owned;
+ return ret;
+ }
if (!strcmp(type, "cachetextconv"))
return parse_bool(&drv->textconv_want_cache, k, v);
- if (!strcmp(type, "wordregex"))
- return git_config_string((char **) &drv->word_regex, k, v);
- if (!strcmp(type, "algorithm"))
- return git_config_string((char **) &drv->algorithm, k, v);
+ if (!strcmp(type, "wordregex")) {
+ int ret;
+ FREE_AND_NULL(drv->word_regex_owned);
+ ret = git_config_string(&drv->word_regex_owned, k, v);
+ drv->word_regex = drv->word_regex_owned;
+ return ret;
+ }
+ if (!strcmp(type, "algorithm")) {
+ int ret;
+ FREE_AND_NULL(drv->algorithm_owned);
+ ret = git_config_string(&drv->algorithm_owned, k, v);
+ drv->algorithm = drv->algorithm_owned;
+ return ret;
+ }
return 0;
}
diff --git a/userdiff.h b/userdiff.h
index 7565930337..827361b0bc 100644
--- a/userdiff.h
+++ b/userdiff.h
@@ -8,6 +8,7 @@ struct repository;
struct userdiff_funcname {
const char *pattern;
+ char *pattern_owned;
int cflags;
};
@@ -20,11 +21,14 @@ struct userdiff_driver {
const char *name;
struct external_diff external;
const char *algorithm;
+ char *algorithm_owned;
int binary;
struct userdiff_funcname funcname;
const char *word_regex;
+ char *word_regex_owned;
const char *word_regex_multi_byte;
const char *textconv;
+ char *textconv_owned;
struct notes_cache *textconv_cache;
int textconv_want_cache;
};
diff --git a/versioncmp.c b/versioncmp.c
index 45e676cbca..e3b2a6e330 100644
--- a/versioncmp.c
+++ b/versioncmp.c
@@ -1,3 +1,5 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "config.h"
#include "strbuf.h"
diff --git a/walker.c b/walker.c
index 0fafdc97cf..807a7a3881 100644
--- a/walker.c
+++ b/walker.c
@@ -221,6 +221,7 @@ static int interpret_target(struct walker *walker, char *target, struct object_i
}
static int mark_complete(const char *path UNUSED,
+ const char *referent UNUSED,
const struct object_id *oid,
int flag UNUSED,
void *cb_data UNUSED)
diff --git a/worktree.c b/worktree.c
index f3c4c8ec54..30a947426e 100644
--- a/worktree.c
+++ b/worktree.c
@@ -252,7 +252,7 @@ const char *worktree_lock_reason(struct worktree *wt)
if (!wt->lock_reason_valid) {
struct strbuf path = STRBUF_INIT;
- strbuf_addstr(&path, worktree_git_path(wt, "locked"));
+ strbuf_addstr(&path, worktree_git_path(the_repository, wt, "locked"));
if (file_exists(path.buf)) {
struct strbuf lock_reason = STRBUF_INIT;
if (strbuf_read_file(&lock_reason, path.buf, 0) < 0)
@@ -546,7 +546,7 @@ int other_head_refs(each_ref_fn fn, void *cb_data)
refname.buf,
RESOLVE_REF_READING,
&oid, &flag))
- ret = fn(refname.buf, &oid, flag, cb_data);
+ ret = fn(refname.buf, NULL, &oid, flag, cb_data);
if (ret)
break;
}
diff --git a/wt-status.c b/wt-status.c
index b778eef989..b477239039 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1618,7 +1618,7 @@ static char *get_branch(const struct worktree *wt, const char *path)
struct object_id oid;
const char *branch_name;
- if (strbuf_read_file(&sb, worktree_git_path(wt, "%s", path), 0) <= 0)
+ if (strbuf_read_file(&sb, worktree_git_path(the_repository, wt, "%s", path), 0) <= 0)
goto got_nothing;
while (sb.len && sb.buf[sb.len - 1] == '\n')
@@ -1716,18 +1716,18 @@ int wt_status_check_rebase(const struct worktree *wt,
{
struct stat st;
- if (!stat(worktree_git_path(wt, "rebase-apply"), &st)) {
- if (!stat(worktree_git_path(wt, "rebase-apply/applying"), &st)) {
+ if (!stat(worktree_git_path(the_repository, wt, "rebase-apply"), &st)) {
+ if (!stat(worktree_git_path(the_repository, wt, "rebase-apply/applying"), &st)) {
state->am_in_progress = 1;
- if (!stat(worktree_git_path(wt, "rebase-apply/patch"), &st) && !st.st_size)
+ if (!stat(worktree_git_path(the_repository, wt, "rebase-apply/patch"), &st) && !st.st_size)
state->am_empty_patch = 1;
} else {
state->rebase_in_progress = 1;
state->branch = get_branch(wt, "rebase-apply/head-name");
state->onto = get_branch(wt, "rebase-apply/onto");
}
- } else if (!stat(worktree_git_path(wt, "rebase-merge"), &st)) {
- if (!stat(worktree_git_path(wt, "rebase-merge/interactive"), &st))
+ } else if (!stat(worktree_git_path(the_repository, wt, "rebase-merge"), &st)) {
+ if (!stat(worktree_git_path(the_repository, wt, "rebase-merge/interactive"), &st))
state->rebase_interactive_in_progress = 1;
else
state->rebase_in_progress = 1;
@@ -1743,7 +1743,7 @@ int wt_status_check_bisect(const struct worktree *wt,
{
struct stat st;
- if (!stat(worktree_git_path(wt, "BISECT_LOG"), &st)) {
+ if (!stat(worktree_git_path(the_repository, wt, "BISECT_LOG"), &st)) {
state->bisect_in_progress = 1;
state->bisecting_from = get_branch(wt, "BISECT_START");
return 1;